diff --git a/alac/codec/ALACEncoder.cpp b/alac/codec/ALACEncoder.cpp new file mode 100644 index 00000000..1b71c295 --- /dev/null +++ b/alac/codec/ALACEncoder.cpp @@ -0,0 +1,1425 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ALACEncoder.cpp +*/ + +// build stuff +#define VERBOSE_DEBUG 0 + +// headers +#include +#include +#include + +#include "ALACEncoder.h" + +#include "aglib.h" +#include "dplib.h" +#include "matrixlib.h" + +#include "ALACBitUtilities.h" +#include "ALACAudioTypes.h" +#include "EndianPortable.h" + +// Note: in C you can't typecast to a 2-dimensional array pointer but that's what we need when +// picking which coefs to use so we declare this typedef b/c we *can* typecast to this type +typedef int16_t (*SearchCoefs)[kALACMaxCoefs]; + +// defines/constants +const uint32_t kALACEncoderMagic = 'dpge'; +const uint32_t kMaxSampleSize = 32; // max allowed bit width is 32 +const uint32_t kDefaultMixBits = 2; +const uint32_t kDefaultMixRes = 0; +const uint32_t kMaxRes = 4; +const uint32_t kDefaultNumUV = 8; +const uint32_t kMinUV = 4; +const uint32_t kMaxUV = 8; + +// static functions +#if VERBOSE_DEBUG +static void AddFiller( BitBuffer * bits, int32_t numBytes ); +#endif + + +/* + Map Format: 3-bit field per channel which is the same as the "element tag" that should be placed + at the beginning of the frame for that channel. Indicates whether SCE, CPE, or LFE. + Each particular field is accessed via the current channel index. Note that the channel + index increments by two for channel pairs. + + For example: + + C L R 3-channel input = (ID_CPE << 3) | (ID_SCE) + index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3) + index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3) + + C L R Ls Rs LFE 5.1-channel input = (ID_LFE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE) + index 0 value = (map & (0x7ul << (0 * 3))) >> (0 * 3) + index 1 value = (map & (0x7ul << (1 * 3))) >> (1 * 3) + index 3 value = (map & (0x7ul << (3 * 3))) >> (3 * 3) + index 5 value = (map & (0x7ul << (5 * 3))) >> (5 * 3) + index 7 value = (map & (0x7ul << (7 * 3))) >> (7 * 3) +*/ +static const uint32_t sChannelMaps[kALACMaxChannels] = +{ + ID_SCE, + ID_CPE, + (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 18) | (ID_SCE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE), + (ID_SCE << 21) | (ID_CPE << 15) | (ID_CPE << 9) | (ID_CPE << 3) | (ID_SCE) +}; + +static const uint32_t sSupportediPodSampleRates[] = +{ + 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000 +}; + +/* + Constructor +*/ +ALACEncoder::ALACEncoder() : + mBitDepth( 0 ), + mFastMode( 0 ), + mMixBufferU( nil ), + mMixBufferV( nil ), + mPredictorU( nil ), + mPredictorV( nil ), + mShiftBufferUV( nil ), + mWorkBuffer( nil ), + + + mTotalBytesGenerated( 0 ), + mAvgBitRate( 0 ), + mMaxFrameBytes( 0 ) +{ + // overrides + mFrameSize = kALACDefaultFrameSize; +} + +/* + Destructor +*/ +ALACEncoder::~ALACEncoder() +{ + // delete the matrix mixing buffers + if ( mMixBufferU ) + { + free(mMixBufferU); + mMixBufferU = NULL; + } + if ( mMixBufferV ) + { + free(mMixBufferV); + mMixBufferV = NULL; + } + + // delete the dynamic predictor's "corrector" buffers + if ( mPredictorU ) + { + free(mPredictorU); + mPredictorU = NULL; + } + if ( mPredictorV ) + { + free(mPredictorV); + mPredictorV = NULL; + } + + // delete the unused byte shift buffer + if ( mShiftBufferUV ) + { + free(mShiftBufferUV); + mShiftBufferUV = NULL; + } + + // delete the work buffer + if ( mWorkBuffer ) + { + free(mWorkBuffer); + mWorkBuffer = NULL; + } +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + HEADER SPECIFICATION + + For every segment we adopt the following header: + + 1 byte reserved (always 0) + 1 byte flags (see below) + [4 byte frame length] (optional, see below) + ---Next, the per-segment ALAC parameters--- + 1 byte mixBits (middle-side parameter) + 1 byte mixRes (middle-side parameter, interpreted as signed char) + + 1 byte shiftU (4 bits modeU, 4 bits denShiftU) + 1 byte filterU (3 bits pbFactorU, 5 bits numU) + (numU) shorts (signed DP coefficients for V channel) + ---Next, 2nd-channel ALAC parameters in case of stereo mode--- + 1 byte shiftV (4 bits modeV, 4 bits denShiftV) + 1 byte filterV (3 bits pbFactorV, 5 bits numV) + (numV) shorts (signed DP coefficients for V channel) + ---After this come the shift-off bytes for (>= 24)-bit data (n-byte shift) if indicated--- + ---Then comes the AG-compressor bitstream--- + + + FLAGS + ----- + + The presence of certain flag bits changes the header format such that the parameters might + not even be sent. The currently defined flags format is: + + 0000psse + + where 0 = reserved, must be 0 + p = 1-bit field "partial frame" flag indicating 32-bit frame length follows this byte + ss = 2-bit field indicating "number of shift-off bytes ignored by compression" + e = 1-bit field indicating "escape" + + The "partial frame" flag means that the following segment is not equal to the frame length specified + in the out-of-band decoder configuration. This allows the decoder to deal with end-of-file partial + segments without incurring the 32-bit overhead for each segment. + + The "shift-off" field indicates the number of bytes at the bottom of the word that were passed through + uncompressed. The reason for this is that the entropy inherent in the LS bytes of >= 24-bit words + quite often means that the frame would have to be "escaped" b/c the compressed size would be >= the + uncompressed size. However, by shifting the input values down and running the remaining bits through + the normal compression algorithm, a net win can be achieved. If this field is non-zero, it means that + the shifted-off bytes follow after the parameter section of the header and before the compressed + bitstream. Note that doing this also allows us to use matrixing on 32-bit inputs after one or more + bytes are shifted off the bottom which helps the eventual compression ratio. For stereo channels, + the shifted off bytes are interleaved. + + The "escape" flag means that this segment was not compressed b/c the compressed size would be + >= uncompressed size. In that case, the audio data was passed through uncompressed after the header. + The other header parameter bytes will not be sent. + + + PARAMETERS + ---------- + + If the segment is not a partial or escape segment, the total header size (in bytes) is given exactly by: + + 4 + (2 + 2 * numU) (mono mode) + 4 + (2 + 2 * numV) + (2 + 2 * numV) (stereo mode) + + where the ALAC filter-lengths numU, numV are bounded by a + constant (in the current source, numU, numV <= NUMCOEPAIRS), and + this forces an absolute upper bound on header size. + + Each segment-decode process loads up these bytes from the front of the + local stream, in the above order, then follows with the entropy-encoded + bits for the given segment. + + To generalize middle-side, there are various mixing modes including middle-side, each lossless, + as embodied in the mix() and unmix() functions. These functions exploit a generalized middle-side + transformation: + + u := [(rL + (m-r)R)/m]; + v := L - R; + + where [ ] denotes integer floor. The (lossless) inverse is + + L = u + v - [rV/m]; + R = L - v; + + In the segment header, m and r are encoded in mixBits and mixRes. + Classical "middle-side" is obtained with m = 2, r = 1, but now + we have more generalized mixes. + + NOTES + ----- + The relevance of the ALAC coefficients is explained in detail + in patent documents. +*/ + +/* + EncodeStereo() + - encode a channel pair +*/ +int32_t ALACEncoder::EncodeStereo( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples ) +{ + BitBuffer workBits; + BitBuffer startBits = *bitstream; // squirrel away copy of current state in case we need to go back and do an escape packet + AGParamRec agParams; + uint32_t bits1, bits2; + uint32_t dilate; + int32_t mixBits, mixRes, maxRes; + uint32_t minBits, minBits1, minBits2; + uint32_t numU, numV; + uint32_t mode; + uint32_t pbFactor; + uint32_t chanBits; + uint32_t denShift; + uint8_t bytesShifted; + SearchCoefs coefsU; + SearchCoefs coefsV; + uint32_t index; + uint8_t partialFrame; + uint32_t escapeBits; + bool doEscape; + int32_t status = ALAC_noErr; + + // make sure we handle this bit-depth before we get going + RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; ); + + // reload coefs pointers for this channel pair + // - note that, while you might think they should be re-initialized per block, retaining state across blocks + // actually results in better overall compression + // - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using + // different coefs for the different passes of "mixRes" results in even better compression + coefsU = (SearchCoefs) mCoefsU[channelIndex]; + coefsV = (SearchCoefs) mCoefsV[channelIndex]; + + // matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many + // so enable 16-bit "shift off" and encode in 17-bit mode + // - in addition, 24-bit mode really improves with one byte shifted off + if ( mBitDepth == 32 ) + bytesShifted = 2; + else if ( mBitDepth >= 24 ) + bytesShifted = 1; + else + bytesShifted = 0; + + chanBits = mBitDepth - (bytesShifted * 8) + 1; + + // flag whether or not this is a partial frame + partialFrame = (numSamples == mFrameSize) ? 0 : 1; + + // brute-force encode optimization loop + // - run over variations of the encoding params to find the best choice + mixBits = kDefaultMixBits; + maxRes = kMaxRes; + numU = numV = kDefaultNumUV; + denShift = DENSHIFT_DEFAULT; + mode = 0; + pbFactor = 4; + dilate = 8; + + minBits = minBits1 = minBits2 = 1ul << 31; + + int32_t bestRes = mLastMixRes[channelIndex]; + + for ( mixRes = 0; mixRes <= maxRes; mixRes++ ) + { + // mix the stereo inputs + switch ( mBitDepth ) + { + case 16: + mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes ); + break; + case 20: + mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, mixBits, mixRes ); + break; + case 24: + // includes extraction of shifted-off bytes + mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, + mixBits, mixRes, mShiftBufferUV, bytesShifted ); + break; + case 32: + // includes extraction of shifted-off bytes + mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples/dilate, + mixBits, mixRes, mShiftBufferUV, bytesShifted ); + break; + } + + BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes ); + + // run the dynamic predictors + pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT ); + pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT ); + + // run the lossless compressor on each channel + set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 ); + RequireNoErr( status, goto Exit; ); + + set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 ); + RequireNoErr( status, goto Exit; ); + + // look for best match + if ( (bits1 + bits2) < minBits1 ) + { + minBits1 = bits1 + bits2; + bestRes = mixRes; + } + } + + mLastMixRes[channelIndex] = (int16_t)bestRes; + + // mix the stereo inputs with the current best mixRes + mixRes = mLastMixRes[channelIndex]; + switch ( mBitDepth ) + { + case 16: + mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes ); + break; + case 20: + mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes ); + break; + case 24: + // also extracts the shifted off bytes into the shift buffers + mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, + mixBits, mixRes, mShiftBufferUV, bytesShifted ); + break; + case 32: + // also extracts the shifted off bytes into the shift buffers + mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, + mixBits, mixRes, mShiftBufferUV, bytesShifted ); + break; + } + + // now it's time for the predictor coefficient search loop + numU = numV = kMinUV; + minBits1 = minBits2 = 1ul << 31; + + for ( uint32_t numUV = kMinUV; numUV <= kMaxUV; numUV += 4 ) + { + BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes ); + + dilate = 32; + + // run the predictor over the same data multiple times to help it converge + for ( uint32_t converge = 0; converge < 8; converge++ ) + { + pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT ); + pc_block( mMixBufferV, mPredictorV, numSamples/dilate, coefsV[numUV-1], numUV, chanBits, DENSHIFT_DEFAULT ); + } + + dilate = 8; + + set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 ); + + if ( (bits1 * dilate + 16 * numUV) < minBits1 ) + { + minBits1 = bits1 * dilate + 16 * numUV; + numU = numUV; + } + + set_ag_params( &agParams, MB0, (pbFactor * PB0)/4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorV, &workBits, numSamples/dilate, chanBits, &bits2 ); + + if ( (bits2 * dilate + 16 * numUV) < minBits2 ) + { + minBits2 = bits2 * dilate + 16 * numUV; + numV = numUV; + } + } + + // test for escape hatch if best calculated compressed size turns out to be more than the input size + minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0); + if ( bytesShifted != 0 ) + minBits += (numSamples * (bytesShifted * 8) * 2); + + escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8); /* 2 common header bytes */ + + doEscape = (minBits >= escapeBits) ? true : false; + + if ( doEscape == false ) + { + // write bitstream header and coefs + BitBufferWrite( bitstream, 0, 12 ); + BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 ); + if ( partialFrame ) + BitBufferWrite( bitstream, numSamples, 32 ); + BitBufferWrite( bitstream, mixBits, 8 ); + BitBufferWrite( bitstream, mixRes, 8 ); + + //Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) ); + //Assert( (pbFactor < 8) && (numU < 32) ); + //Assert( (pbFactor < 8) && (numV < 32) ); + + BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 ); + BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 ); + for ( index = 0; index < numU; index++ ) + BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 ); + + BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 ); + BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 ); + for ( index = 0; index < numV; index++ ) + BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 ); + + // if shift active, write the interleaved shift buffers + if ( bytesShifted != 0 ) + { + uint32_t bitShift = bytesShifted * 8; + + //Assert( bitShift <= 16 ); + + for ( index = 0; index < (numSamples * 2); index += 2 ) + { + uint32_t shiftedVal; + + shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1]; + BitBufferWrite( bitstream, shiftedVal, bitShift * 2 ); + } + } + + // run the dynamic predictor and lossless compression for the "left" channel + // - note: to avoid allocating more buffers, we're mixing and matching between the available buffers instead + // of only using "U" buffers for the U-channel and "V" buffers for the V-channel + if ( mode == 0 ) + { + pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT ); + } + else + { + pc_block( mMixBufferU, mPredictorV, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT ); + pc_block( mPredictorV, mPredictorU, numSamples, nil, 31, chanBits, 0 ); + } + + set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 ); + RequireNoErr( status, goto Exit; ); + + // run the dynamic predictor and lossless compression for the "right" channel + if ( mode == 0 ) + { + pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT ); + } + else + { + pc_block( mMixBufferV, mPredictorU, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT ); + pc_block( mPredictorU, mPredictorV, numSamples, nil, 31, chanBits, 0 ); + } + + set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 ); + RequireNoErr( status, goto Exit; ); + + /* if we happened to create a compressed packet that was actually bigger than an escape packet would be, + chuck it and do an escape packet + */ + minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits ); + if ( minBits >= escapeBits ) + { + *bitstream = startBits; // reset bitstream state + doEscape = true; + printf( "compressed frame too big: %u vs. %u \n", minBits, escapeBits ); + } + } + + if ( doEscape == true ) + { + /* escape */ + status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples ); + +#if VERBOSE_DEBUG + DebugMsg( "escape!: %lu vs %lu", minBits, escapeBits ); +#endif + } + +Exit: + return status; +} + +/* + EncodeStereoFast() + - encode a channel pair without the search loop for maximum possible speed +*/ +int32_t ALACEncoder::EncodeStereoFast( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples ) +{ + BitBuffer startBits = *bitstream; // squirrel away current bit position in case we decide to use escape hatch + AGParamRec agParams; + uint32_t bits1, bits2; + int32_t mixBits, mixRes; + uint32_t minBits, minBits1, minBits2; + uint32_t numU, numV; + uint32_t mode; + uint32_t pbFactor; + uint32_t chanBits; + uint32_t denShift; + uint8_t bytesShifted; + SearchCoefs coefsU; + SearchCoefs coefsV; + uint32_t index; + uint8_t partialFrame; + uint32_t escapeBits; + bool doEscape; + int32_t status; + + // make sure we handle this bit-depth before we get going + RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; ); + + // reload coefs pointers for this channel pair + // - note that, while you might think they should be re-initialized per block, retaining state across blocks + // actually results in better overall compression + // - strangely, re-using the same coefs for the different passes of the "mixRes" search loop instead of using + // different coefs for the different passes of "mixRes" results in even better compression + coefsU = (SearchCoefs) mCoefsU[channelIndex]; + coefsV = (SearchCoefs) mCoefsV[channelIndex]; + + // matrix encoding adds an extra bit but 32-bit inputs cannot be matrixed b/c 33 is too many + // so enable 16-bit "shift off" and encode in 17-bit mode + // - in addition, 24-bit mode really improves with one byte shifted off + if ( mBitDepth == 32 ) + bytesShifted = 2; + else if ( mBitDepth >= 24 ) + bytesShifted = 1; + else + bytesShifted = 0; + + chanBits = mBitDepth - (bytesShifted * 8) + 1; + + // flag whether or not this is a partial frame + partialFrame = (numSamples == mFrameSize) ? 0 : 1; + + // set up default encoding parameters for "fast" mode + mixBits = kDefaultMixBits; + mixRes = kDefaultMixRes; + numU = numV = kDefaultNumUV; + denShift = DENSHIFT_DEFAULT; + mode = 0; + pbFactor = 4; + + minBits = minBits1 = minBits2 = 1ul << 31; + + // mix the stereo inputs with default mixBits/mixRes + switch ( mBitDepth ) + { + case 16: + mix16( (int16_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes ); + break; + case 20: + mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, mixBits, mixRes ); + break; + case 24: + // also extracts the shifted off bytes into the shift buffers + mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, + mixBits, mixRes, mShiftBufferUV, bytesShifted ); + break; + case 32: + // also extracts the shifted off bytes into the shift buffers + mix32( (int32_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, + mixBits, mixRes, mShiftBufferUV, bytesShifted ); + break; + } + + /* speculatively write the bitstream assuming the compressed version will be smaller */ + + // write bitstream header and coefs + BitBufferWrite( bitstream, 0, 12 ); + BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 ); + if ( partialFrame ) + BitBufferWrite( bitstream, numSamples, 32 ); + BitBufferWrite( bitstream, mixBits, 8 ); + BitBufferWrite( bitstream, mixRes, 8 ); + + //Assert( (mode < 16) && (DENSHIFT_DEFAULT < 16) ); + //Assert( (pbFactor < 8) && (numU < 32) ); + //Assert( (pbFactor < 8) && (numV < 32) ); + + BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 ); + BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 ); + for ( index = 0; index < numU; index++ ) + BitBufferWrite( bitstream, coefsU[numU - 1][index], 16 ); + + BitBufferWrite( bitstream, (mode << 4) | DENSHIFT_DEFAULT, 8 ); + BitBufferWrite( bitstream, (pbFactor << 5) | numV, 8 ); + for ( index = 0; index < numV; index++ ) + BitBufferWrite( bitstream, coefsV[numV - 1][index], 16 ); + + // if shift active, write the interleaved shift buffers + if ( bytesShifted != 0 ) + { + uint32_t bitShift = bytesShifted * 8; + + //Assert( bitShift <= 16 ); + + for ( index = 0; index < (numSamples * 2); index += 2 ) + { + uint32_t shiftedVal; + + shiftedVal = ((uint32_t)mShiftBufferUV[index + 0] << bitShift) | (uint32_t)mShiftBufferUV[index + 1]; + BitBufferWrite( bitstream, shiftedVal, bitShift * 2 ); + } + } + + // run the dynamic predictor and lossless compression for the "left" channel + // - note: we always use mode 0 in the "fast" path so we don't need the code for mode != 0 + pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU - 1], numU, chanBits, DENSHIFT_DEFAULT ); + + set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 ); + RequireNoErr( status, goto Exit; ); + + // run the dynamic predictor and lossless compression for the "right" channel + pc_block( mMixBufferV, mPredictorV, numSamples, coefsV[numV - 1], numV, chanBits, DENSHIFT_DEFAULT ); + + set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples, numSamples, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorV, bitstream, numSamples, chanBits, &bits2 ); + RequireNoErr( status, goto Exit; ); + + // do bit requirement calculations + minBits1 = bits1 + (numU * sizeof(int16_t) * 8); + minBits2 = bits2 + (numV * sizeof(int16_t) * 8); + + // test for escape hatch if best calculated compressed size turns out to be more than the input size + minBits = minBits1 + minBits2 + (8 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0); + if ( bytesShifted != 0 ) + minBits += (numSamples * (bytesShifted * 8) * 2); + + escapeBits = (numSamples * mBitDepth * 2) + ((partialFrame == true) ? 32 : 0) + (2 * 8); /* 2 common header bytes */ + + doEscape = (minBits >= escapeBits) ? true : false; + + if ( doEscape == false ) + { + /* if we happened to create a compressed packet that was actually bigger than an escape packet would be, + chuck it and do an escape packet + */ + minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits ); + if ( minBits >= escapeBits ) + { + doEscape = true; + printf( "compressed frame too big: %u vs. %u\n", minBits, escapeBits ); + } + + } + + if ( doEscape == true ) + { + /* escape */ + + // reset bitstream position since we speculatively wrote the compressed version + *bitstream = startBits; + + // write escape frame + status = this->EncodeStereoEscape( bitstream, inputBuffer, stride, numSamples ); + +#if VERBOSE_DEBUG + DebugMsg( "escape!: %u vs %u", minBits, (numSamples * mBitDepth * 2) ); +#endif + } + +Exit: + return status; +} + +/* + EncodeStereoEscape() + - encode stereo escape frame +*/ +int32_t ALACEncoder::EncodeStereoEscape( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t numSamples ) +{ + int16_t * input16; + int32_t * input32; + uint8_t partialFrame; + uint32_t index; + + // flag whether or not this is a partial frame + partialFrame = (numSamples == mFrameSize) ? 0 : 1; + + // write bitstream header + BitBufferWrite( bitstream, 0, 12 ); + BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 ); // LSB = 1 means "frame not compressed" + if ( partialFrame ) + BitBufferWrite( bitstream, numSamples, 32 ); + + // just copy the input data to the output buffer + switch ( mBitDepth ) + { + case 16: + input16 = (int16_t *) inputBuffer; + + for ( index = 0; index < (numSamples * stride); index += stride ) + { + BitBufferWrite( bitstream, input16[index + 0], 16 ); + BitBufferWrite( bitstream, input16[index + 1], 16 ); + } + break; + case 20: + // mix20() with mixres param = 0 means de-interleave so use it to simplify things + mix20( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0 ); + for ( index = 0; index < numSamples; index++ ) + { + BitBufferWrite( bitstream, mMixBufferU[index], 20 ); + BitBufferWrite( bitstream, mMixBufferV[index], 20 ); + } + break; + case 24: + // mix24() with mixres param = 0 means de-interleave so use it to simplify things + mix24( (uint8_t *) inputBuffer, stride, mMixBufferU, mMixBufferV, numSamples, 0, 0, mShiftBufferUV, 0 ); + for ( index = 0; index < numSamples; index++ ) + { + BitBufferWrite( bitstream, mMixBufferU[index], 24 ); + BitBufferWrite( bitstream, mMixBufferV[index], 24 ); + } + break; + case 32: + input32 = (int32_t *) inputBuffer; + + for ( index = 0; index < (numSamples * stride); index += stride ) + { + BitBufferWrite( bitstream, input32[index + 0], 32 ); + BitBufferWrite( bitstream, input32[index + 1], 32 ); + } + break; + } + + return ALAC_noErr; +} + +/* + EncodeMono() + - encode a mono input buffer +*/ +int32_t ALACEncoder::EncodeMono( BitBuffer * bitstream, void * inputBuffer, uint32_t stride, uint32_t channelIndex, uint32_t numSamples ) +{ + BitBuffer startBits = *bitstream; // squirrel away copy of current state in case we need to go back and do an escape packet + AGParamRec agParams; + uint32_t bits1; + uint32_t numU; + SearchCoefs coefsU; + uint32_t dilate; + uint32_t minBits, bestU; + uint32_t minU, maxU; + uint32_t index, index2; + uint8_t bytesShifted; + uint32_t shift; + uint32_t mask; + uint32_t chanBits; + uint8_t pbFactor; + uint8_t partialFrame; + int16_t * input16; + int32_t * input32; + uint32_t escapeBits; + bool doEscape; + int32_t status; + + // make sure we handle this bit-depth before we get going + RequireAction( (mBitDepth == 16) || (mBitDepth == 20) || (mBitDepth == 24) || (mBitDepth == 32), return kALAC_ParamError; ); + + status = ALAC_noErr; + + // reload coefs array from previous frame + coefsU = (SearchCoefs) mCoefsU[channelIndex]; + + // pick bit depth for actual encoding + // - we lop off the lower byte(s) for 24-/32-bit encodings + if ( mBitDepth == 32 ) + bytesShifted = 2; + else if ( mBitDepth >= 24 ) + bytesShifted = 1; + else + bytesShifted = 0; + + shift = bytesShifted * 8; + mask = (1ul << shift) - 1; + chanBits = mBitDepth - (bytesShifted * 8); + + // flag whether or not this is a partial frame + partialFrame = (numSamples == mFrameSize) ? 0 : 1; + + // convert N-bit data to 32-bit for predictor + switch ( mBitDepth ) + { + case 16: + { + // convert 16-bit data to 32-bit for predictor + input16 = (int16_t *) inputBuffer; + for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride ) + mMixBufferU[index] = (int32_t) input16[index2]; + break; + } + case 20: + // convert 20-bit data to 32-bit for predictor + copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples ); + break; + case 24: + // convert 24-bit data to 32-bit for the predictor and extract the shifted off byte(s) + copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples ); + for ( index = 0; index < numSamples; index++ ) + { + mShiftBufferUV[index] = (uint16_t)(mMixBufferU[index] & mask); + mMixBufferU[index] >>= shift; + } + break; + case 32: + { + // just copy the 32-bit input data for the predictor and extract the shifted off byte(s) + input32 = (int32_t *) inputBuffer; + + for ( index = 0, index2 = 0; index < numSamples; index++, index2 += stride ) + { + int32_t val = input32[index2]; + + mShiftBufferUV[index] = (uint16_t)(val & mask); + mMixBufferU[index] = val >> shift; + } + break; + } + } + + // brute-force encode optimization loop (implied "encode depth" of 0 if comparing to cmd line tool) + // - run over variations of the encoding params to find the best choice + minU = 4; + maxU = 8; + minBits = 1ul << 31; + pbFactor = 4; + + minBits = 1ul << 31; + bestU = minU; + + for ( numU = minU; numU <= maxU; numU += 4 ) + { + BitBuffer workBits; + uint32_t numBits; + + BitBufferInit( &workBits, mWorkBuffer, mMaxOutputBytes ); + + dilate = 32; + for ( uint32_t converge = 0; converge < 7; converge++ ) + pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT ); + + dilate = 8; + pc_block( mMixBufferU, mPredictorU, numSamples/dilate, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT ); + + set_ag_params( &agParams, MB0, (pbFactor * PB0) / 4, KB0, numSamples/dilate, numSamples/dilate, MAX_RUN_DEFAULT ); + status = dyn_comp( &agParams, mPredictorU, &workBits, numSamples/dilate, chanBits, &bits1 ); + RequireNoErr( status, goto Exit; ); + + numBits = (dilate * bits1) + (16 * numU); + if ( numBits < minBits ) + { + bestU = numU; + minBits = numBits; + } + } + + // test for escape hatch if best calculated compressed size turns out to be more than the input size + // - first, add bits for the header bytes mixRes/maxRes/shiftU/filterU + minBits += (4 /* mixRes/maxRes/etc. */ * 8) + ((partialFrame == true) ? 32 : 0); + if ( bytesShifted != 0 ) + minBits += (numSamples * (bytesShifted * 8)); + + escapeBits = (numSamples * mBitDepth) + ((partialFrame == true) ? 32 : 0) + (2 * 8); /* 2 common header bytes */ + + doEscape = (minBits >= escapeBits) ? true : false; + + if ( doEscape == false ) + { + // write bitstream header + BitBufferWrite( bitstream, 0, 12 ); + BitBufferWrite( bitstream, (partialFrame << 3) | (bytesShifted << 1), 4 ); + if ( partialFrame ) + BitBufferWrite( bitstream, numSamples, 32 ); + BitBufferWrite( bitstream, 0, 16 ); // mixBits = mixRes = 0 + + // write the params and predictor coefs + numU = bestU; + BitBufferWrite( bitstream, (0 << 4) | DENSHIFT_DEFAULT, 8 ); // modeU = 0 + BitBufferWrite( bitstream, (pbFactor << 5) | numU, 8 ); + for ( index = 0; index < numU; index++ ) + BitBufferWrite( bitstream, coefsU[numU-1][index], 16 ); + + // if shift active, write the interleaved shift buffers + if ( bytesShifted != 0 ) + { + for ( index = 0; index < numSamples; index++ ) + BitBufferWrite( bitstream, mShiftBufferUV[index], shift ); + } + + // run the dynamic predictor with the best result + pc_block( mMixBufferU, mPredictorU, numSamples, coefsU[numU-1], numU, chanBits, DENSHIFT_DEFAULT ); + + // do lossless compression + set_standard_ag_params( &agParams, numSamples, numSamples ); + status = dyn_comp( &agParams, mPredictorU, bitstream, numSamples, chanBits, &bits1 ); + //AssertNoErr( status ); + + + /* if we happened to create a compressed packet that was actually bigger than an escape packet would be, + chuck it and do an escape packet + */ + minBits = BitBufferGetPosition( bitstream ) - BitBufferGetPosition( &startBits ); + if ( minBits >= escapeBits ) + { + *bitstream = startBits; // reset bitstream state + doEscape = true; + printf( "compressed frame too big: %u vs. %u\n", minBits, escapeBits ); + } + } + + if ( doEscape == true ) + { + // write bitstream header and coefs + BitBufferWrite( bitstream, 0, 12 ); + BitBufferWrite( bitstream, (partialFrame << 3) | 1, 4 ); // LSB = 1 means "frame not compressed" + if ( partialFrame ) + BitBufferWrite( bitstream, numSamples, 32 ); + + // just copy the input data to the output buffer + switch ( mBitDepth ) + { + case 16: + input16 = (int16_t *) inputBuffer; + for ( index = 0; index < (numSamples * stride); index += stride ) + BitBufferWrite( bitstream, input16[index], 16 ); + break; + case 20: + // convert 20-bit data to 32-bit for simplicity + copy20ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples ); + for ( index = 0; index < numSamples; index++ ) + BitBufferWrite( bitstream, mMixBufferU[index], 20 ); + break; + case 24: + // convert 24-bit data to 32-bit for simplicity + copy24ToPredictor( (uint8_t *) inputBuffer, stride, mMixBufferU, numSamples ); + for ( index = 0; index < numSamples; index++ ) + BitBufferWrite( bitstream, mMixBufferU[index], 24 ); + break; + case 32: + input32 = (int32_t *) inputBuffer; + for ( index = 0; index < (numSamples * stride); index += stride ) + BitBufferWrite( bitstream, input32[index], 32 ); + break; + } +#if VERBOSE_DEBUG + DebugMsg( "escape!: %lu vs %lu", minBits, (numSamples * mBitDepth) ); +#endif + } + +Exit: + return status; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + Encode() + - encode the next block of samples +*/ +int32_t ALACEncoder::Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat, + unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes) +{ + uint32_t numFrames; + uint32_t outputSize; + BitBuffer bitstream; + int32_t status; + + numFrames = *ioNumBytes/theInputFormat.mBytesPerPacket; + + // create a bit buffer structure pointing to our output buffer + BitBufferInit( &bitstream, theWriteBuffer, mMaxOutputBytes ); + + if ( theInputFormat.mChannelsPerFrame == 2 ) + { + // add 3-bit frame start tag ID_CPE = channel pair & 4-bit element instance tag = 0 + BitBufferWrite( &bitstream, ID_CPE, 3 ); + BitBufferWrite( &bitstream, 0, 4 ); + + // encode stereo input buffer + if ( mFastMode == false ) + status = this->EncodeStereo( &bitstream, theReadBuffer, 2, 0, numFrames ); + else + status = this->EncodeStereoFast( &bitstream, theReadBuffer, 2, 0, numFrames ); + RequireNoErr( status, goto Exit; ); + } + else if ( theInputFormat.mChannelsPerFrame == 1 ) + { + // add 3-bit frame start tag ID_SCE = mono channel & 4-bit element instance tag = 0 + BitBufferWrite( &bitstream, ID_SCE, 3 ); + BitBufferWrite( &bitstream, 0, 4 ); + + // encode mono input buffer + status = this->EncodeMono( &bitstream, theReadBuffer, 1, 0, numFrames ); + RequireNoErr( status, goto Exit; ); + } + else + { + char * inputBuffer; + uint32_t tag; + uint32_t channelIndex; + uint32_t inputIncrement; + uint8_t stereoElementTag; + uint8_t monoElementTag; + uint8_t lfeElementTag; + + inputBuffer = (char *) theReadBuffer; + inputIncrement = ((mBitDepth + 7) / 8); + + stereoElementTag = 0; + monoElementTag = 0; + lfeElementTag = 0; + + for ( channelIndex = 0; channelIndex < theInputFormat.mChannelsPerFrame; ) + { + tag = (sChannelMaps[theInputFormat.mChannelsPerFrame - 1] & (0x7ul << (channelIndex * 3))) >> (channelIndex * 3); + + BitBufferWrite( &bitstream, tag, 3 ); + switch ( tag ) + { + case ID_SCE: + // mono + BitBufferWrite( &bitstream, monoElementTag, 4 ); + + status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames ); + + inputBuffer += inputIncrement; + channelIndex++; + monoElementTag++; + break; + + case ID_CPE: + // stereo + BitBufferWrite( &bitstream, stereoElementTag, 4 ); + + status = this->EncodeStereo( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames ); + + inputBuffer += (inputIncrement * 2); + channelIndex += 2; + stereoElementTag++; + break; + + case ID_LFE: + // LFE channel (subwoofer) + BitBufferWrite( &bitstream, lfeElementTag, 4 ); + + status = this->EncodeMono( &bitstream, inputBuffer, theInputFormat.mChannelsPerFrame, channelIndex, numFrames ); + + inputBuffer += inputIncrement; + channelIndex++; + lfeElementTag++; + break; + + default: + printf( "That ain't right! (%u)\n", tag ); + status = kALAC_ParamError; + goto Exit; + } + + RequireNoErr( status, goto Exit; ); + } + } + +#if VERBOSE_DEBUG +{ + // if there is room left in the output buffer, add some random fill data to test decoder + int32_t bitsLeft; + int32_t bytesLeft; + + bitsLeft = BitBufferGetPosition( &bitstream ) - 3; // - 3 for ID_END tag + bytesLeft = bitstream.byteSize - ((bitsLeft + 7) / 8); + + if ( (bytesLeft > 20) && ((bytesLeft & 0x4u) != 0) ) + AddFiller( &bitstream, bytesLeft ); +} +#endif + + // add 3-bit frame end tag: ID_END + BitBufferWrite( &bitstream, ID_END, 3 ); + + // byte-align the output data + BitBufferByteAlign( &bitstream, true ); + + outputSize = BitBufferGetPosition( &bitstream ) / 8; + //Assert( outputSize <= mMaxOutputBytes ); + + + // all good, let iTunes know what happened and remember the total number of input sample frames + *ioNumBytes = outputSize; + //mEncodedFrames += encodeMsg->numInputSamples; + + // gather encoding stats + mTotalBytesGenerated += outputSize; + mMaxFrameBytes = MAX( mMaxFrameBytes, outputSize ); + + status = ALAC_noErr; + +Exit: + return status; +} + +/* + Finish() + - drain out any leftover samples +*/ + +int32_t ALACEncoder::Finish() +{ +/* // finalize bit rate statistics + if ( mSampleSize.numEntries != 0 ) + mAvgBitRate = (uint32_t)( (((float)mTotalBytesGenerated * 8.0f) / (float)mSampleSize.numEntries) * ((float)mSampleRate / (float)mFrameSize) ); + else + mAvgBitRate = 0; +*/ + return ALAC_noErr; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + GetConfig() +*/ +void ALACEncoder::GetConfig( ALACSpecificConfig & config ) +{ + config.frameLength = Swap32NtoB(mFrameSize); + config.compatibleVersion = (uint8_t) kALACCompatibleVersion; + config.bitDepth = (uint8_t) mBitDepth; + config.pb = (uint8_t) PB0; + config.kb = (uint8_t) KB0; + config.mb = (uint8_t) MB0; + config.numChannels = (uint8_t) mNumChannels; + config.maxRun = Swap16NtoB((uint16_t) MAX_RUN_DEFAULT); + config.maxFrameBytes = Swap32NtoB(mMaxFrameBytes); + config.avgBitRate = Swap32NtoB(mAvgBitRate); + config.sampleRate = Swap32NtoB(mOutputSampleRate); +} + +uint32_t ALACEncoder::GetMagicCookieSize(uint32_t inNumChannels) +{ + if (inNumChannels > 2) + { + return sizeof(ALACSpecificConfig) + kChannelAtomSize + sizeof(ALACAudioChannelLayout); + } + else + { + return sizeof(ALACSpecificConfig); + } +} + +void ALACEncoder::GetMagicCookie(void * outCookie, uint32_t * ioSize) +{ + ALACSpecificConfig theConfig = {0}; + ALACAudioChannelLayout theChannelLayout = {0}; + uint8_t theChannelAtom[kChannelAtomSize] = {0, 0, 0, 0, 'c', 'h', 'a', 'n', 0, 0, 0, 0}; + uint32_t theCookieSize = sizeof(ALACSpecificConfig); + uint8_t * theCookiePointer = (uint8_t *)outCookie; + + GetConfig(theConfig); + if (theConfig.numChannels > 2) + { + theChannelLayout.mChannelLayoutTag = ALACChannelLayoutTags[theConfig.numChannels - 1]; + theCookieSize += (sizeof(ALACAudioChannelLayout) + kChannelAtomSize); + } + if (*ioSize >= theCookieSize) + { + memcpy(theCookiePointer, &theConfig, sizeof(ALACSpecificConfig)); + theChannelAtom[3] = (sizeof(ALACAudioChannelLayout) + kChannelAtomSize); + if (theConfig.numChannels > 2) + { + theCookiePointer += sizeof(ALACSpecificConfig); + memcpy(theCookiePointer, theChannelAtom, kChannelAtomSize); + theCookiePointer += kChannelAtomSize; + memcpy(theCookiePointer, &theChannelLayout, sizeof(ALACAudioChannelLayout)); + } + *ioSize = theCookieSize; + } + else + { + *ioSize = 0; // no incomplete cookies + } +} + +/* + InitializeEncoder() + - initialize the encoder component with the current config +*/ +int32_t ALACEncoder::InitializeEncoder(AudioFormatDescription theOutputFormat) +{ + int32_t status; + + mOutputSampleRate = theOutputFormat.mSampleRate; + mNumChannels = theOutputFormat.mChannelsPerFrame; + switch(theOutputFormat.mFormatFlags) + { + case 1: + mBitDepth = 16; + break; + case 2: + mBitDepth = 20; + break; + case 3: + mBitDepth = 24; + break; + case 4: + mBitDepth = 32; + break; + default: + break; + } + + // set up default encoding parameters and state + // - note: mFrameSize is set in the constructor or via SetFrameSize() which must be called before this routine + for ( uint32_t index = 0; index < kALACMaxChannels; index++ ) + mLastMixRes[index] = kDefaultMixRes; + + // the maximum output frame size can be no bigger than (samplesPerBlock * numChannels * ((10 + sampleSize)/8) + 1) + // but note that this can be bigger than the input size! + // - since we don't yet know what our input format will be, use our max allowed sample size in the calculation + mMaxOutputBytes = mFrameSize * mNumChannels * ((10 + kMaxSampleSize) / 8) + 1; + + // allocate mix buffers + mMixBufferU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 ); + mMixBufferV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 ); + + // allocate dynamic predictor buffers + mPredictorU = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 ); + mPredictorV = (int32_t *) calloc( mFrameSize * sizeof(int32_t), 1 ); + + // allocate combined shift buffer + mShiftBufferUV = (uint16_t *) calloc( mFrameSize * 2 * sizeof(uint16_t),1 ); + + // allocate work buffer for search loop + mWorkBuffer = (uint8_t *) calloc( mMaxOutputBytes, 1 ); + + RequireAction( (mMixBufferU != nil) && (mMixBufferV != nil) && + (mPredictorU != nil) && (mPredictorV != nil) && + (mShiftBufferUV != nil) && (mWorkBuffer != nil ), + status = kALAC_MemFullError; goto Exit; ); + + status = ALAC_noErr; + + + // initialize coefs arrays once b/c retaining state across blocks actually improves the encode ratio + for ( int32_t channel = 0; channel < (int32_t)mNumChannels; channel++ ) + { + for ( int32_t search = 0; search < kALACMaxSearches; search++ ) + { + init_coefs( mCoefsU[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs ); + init_coefs( mCoefsV[channel][search], DENSHIFT_DEFAULT, kALACMaxCoefs ); + } + } + +Exit: + return status; +} + +/* + GetSourceFormat() + - given the input format, return one of our supported formats +*/ +void ALACEncoder::GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output ) +{ + // default is 16-bit native endian + // - note: for float input we assume that's coming from one of our decoders (mp3, aac) so it only makes sense + // to encode to 16-bit since the source was lossy in the first place + // - note: if not a supported bit depth, find the closest supported bit depth to the input one + if ( (source->mFormatID != kALACFormatLinearPCM) || ((source->mFormatFlags & kALACFormatFlagIsFloat) != 0) || + ( source->mBitsPerChannel <= 16 ) ) + mBitDepth = 16; + else if ( source->mBitsPerChannel <= 20 ) + mBitDepth = 20; + else if ( source->mBitsPerChannel <= 24 ) + mBitDepth = 24; + else + mBitDepth = 32; + + // we support 16/20/24/32-bit integer data at any sample rate and our target number of channels + // and sample rate were specified when we were configured + /* + MakeUncompressedAudioFormat( mNumChannels, (float) mOutputSampleRate, mBitDepth, kAudioFormatFlagsNativeIntegerPacked, output ); + */ +} + + + +#if VERBOSE_DEBUG + +#if PRAGMA_MARK +#pragma mark - +#endif + +/* + AddFiller() + - add fill and data stream elements to the bitstream to test the decoder +*/ +static void AddFiller( BitBuffer * bits, int32_t numBytes ) +{ + uint8_t tag; + uint32_t index; + + // out of lameness, subtract 6 bytes to deal with header + alignment as required for fill/data elements + numBytes -= 6; + if ( numBytes <= 0 ) + return; + + // randomly pick Fill or Data Stream Element based on numBytes requested + tag = (numBytes & 0x8) ? ID_FIL : ID_DSE; + + BitBufferWrite( bits, tag, 3 ); + if ( tag == ID_FIL ) + { + // can't write more than 269 bytes in a fill element + numBytes = (numBytes > 269) ? 269 : numBytes; + + // fill element = 4-bit size unless >= 15 then 4-bit size + 8-bit extension size + if ( numBytes >= 15 ) + { + uint16_t extensionSize; + + BitBufferWrite( bits, 15, 4 ); + + // 8-bit extension count field is "extra + 1" which is weird but I didn't define the syntax + // - otherwise, there's no way to represent 15 + // - for example, to really mean 15 bytes you must encode extensionSize = 1 + // - why it's not like data stream elements I have no idea + extensionSize = (numBytes - 15) + 1; + Assert( extensionSize <= 255 ); + BitBufferWrite( bits, extensionSize, 8 ); + } + else + BitBufferWrite( bits, numBytes, 4 ); + + BitBufferWrite( bits, 0x10, 8 ); // extension_type = FILL_DATA = b0001 or'ed with fill_nibble = b0000 + for ( index = 0; index < (numBytes - 1); index++ ) + BitBufferWrite( bits, 0xa5, 8 ); // fill_byte = b10100101 = 0xa5 + } + else + { + // can't write more than 510 bytes in a data stream element + numBytes = (numBytes > 510) ? 510 : numBytes; + + BitBufferWrite( bits, 0, 4 ); // element instance tag + BitBufferWrite( bits, 1, 1 ); // byte-align flag = true + + // data stream element = 8-bit size unless >= 255 then 8-bit size + 8-bit size + if ( numBytes >= 255 ) + { + BitBufferWrite( bits, 255, 8 ); + BitBufferWrite( bits, numBytes - 255, 8 ); + } + else + BitBufferWrite( bits, numBytes, 8 ); + + BitBufferByteAlign( bits, true ); // byte-align with zeros + + for ( index = 0; index < numBytes; index++ ) + BitBufferWrite( bits, 0x5a, 8 ); + } +} + +#endif /* VERBOSE_DEBUG */ diff --git a/alac/codec/ALACEncoder.h b/alac/codec/ALACEncoder.h new file mode 100644 index 00000000..0e6c6890 --- /dev/null +++ b/alac/codec/ALACEncoder.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: ALACEncoder.h +*/ + +#pragma once + +#include + +#include "ALACAudioTypes.h" + + +struct BitBuffer; + +class ALACEncoder +{ + public: + ALACEncoder(); + virtual ~ALACEncoder(); + + virtual int32_t Encode(AudioFormatDescription theInputFormat, AudioFormatDescription theOutputFormat, + unsigned char * theReadBuffer, unsigned char * theWriteBuffer, int32_t * ioNumBytes); + virtual int32_t Finish( ); + + void SetFastMode( bool fast ) { mFastMode = fast; }; + + // this must be called *before* InitializeEncoder() + void SetFrameSize( uint32_t frameSize ) { mFrameSize = frameSize; }; + + void GetConfig( ALACSpecificConfig & config ); + uint32_t GetMagicCookieSize(uint32_t inNumChannels); + void GetMagicCookie( void * config, uint32_t * ioSize ); + + virtual int32_t InitializeEncoder(AudioFormatDescription theOutputFormat); + + protected: + virtual void GetSourceFormat( const AudioFormatDescription * source, AudioFormatDescription * output ); + + int32_t EncodeStereo( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples ); + int32_t EncodeStereoFast( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples ); + int32_t EncodeStereoEscape( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t numSamples ); + int32_t EncodeMono( struct BitBuffer * bitstream, void * input, uint32_t stride, uint32_t channelIndex, uint32_t numSamples ); + + + // ALAC encoder parameters + int16_t mBitDepth; + bool mFastMode; + + // encoding state + int16_t mLastMixRes[kALACMaxChannels]; + + // encoding buffers + int32_t * mMixBufferU; + int32_t * mMixBufferV; + int32_t * mPredictorU; + int32_t * mPredictorV; + uint16_t * mShiftBufferUV; + + uint8_t * mWorkBuffer; + + // per-channel coefficients buffers + int16_t mCoefsU[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs]; + int16_t mCoefsV[kALACMaxChannels][kALACMaxSearches][kALACMaxCoefs]; + + // encoding statistics + uint32_t mTotalBytesGenerated; + uint32_t mAvgBitRate; + uint32_t mMaxFrameBytes; + uint32_t mFrameSize; + uint32_t mMaxOutputBytes; + uint32_t mNumChannels; + uint32_t mOutputSampleRate; +}; diff --git a/alac/codec/APPLE_LICENSE.txt b/alac/codec/APPLE_LICENSE.txt new file mode 100644 index 00000000..71fe6fd7 --- /dev/null +++ b/alac/codec/APPLE_LICENSE.txt @@ -0,0 +1,335 @@ +APPLE PUBLIC SOURCE LICENSE +Version 2.0 - August 6, 2003 + +Please read this License carefully before downloading this software. By +downloading or using this software, you are agreeing to be bound by the terms +of this License. If you do not or cannot agree to the terms of this License, +please do not download or use the software. + +Apple Note: In January 2007, Apple changed its corporate name from "Apple +Computer, Inc." to "Apple Inc." This change has been reflected below and +copyright years updated, but no other changes have been made to the APSL 2.0. + +1. General; Definitions. This License applies to any program or other +work which Apple Inc. ("Apple") makes publicly available and which contains a +notice placed by Apple identifying such program or work as "Original Code" and +stating that it is subject to the terms of this Apple Public Source License +version 2.0 ("License"). As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is the +grantor of rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to Apple and (ii) that cover subject matter contained in +the Original Code, but only to the extent necessary to use, reproduce and/or +distribute the Original Code without infringement; and (b) in the case where +You are the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to You and (ii) that cover subject matter in +Your Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or contributes to +the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the combination +of Original Code and any Modifications, and/or any respective portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or otherwise +make Covered Code available, directly or indirectly, to anyone other than You; +and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way +to provide a service, including but not limited to delivery of content, through +electronic communication with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions +thereof with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change to, +the substance and/or structure of the Original Code, any previous +Modifications, the combination of Original Code and any previous Modifications, +and/or any respective portions thereof. When code is released as a series of +files, a Modification is: (a) any addition to or deletion from the contents of +a file containing Covered Code; and/or (b) any new file or other representation +of computer program statements that contains any part of Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Apple under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Apple under this License, and that has been expressly identified by Apple as +such in the header file(s) of such work; and (b) the object code compiled from +such Source Code and originally made available by Apple under this License + +1.8 "Source Code" means the human readable form of a program or other work +that is suitable for making modifications to it, including all modules it +contains, plus any associated interface definition files, scripts used to +control compilation and installation of an executable (object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership +of fifty percent (50%) or more of the outstanding shares or beneficial +ownership of such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Apple hereby grants You, effective on the date You +accept this License and download the Original Code, a world-wide, royalty-free, +non-exclusive license, to the extent of Apple's Applicable Patent Rights and +copyrights covering the Original Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, internally +distribute within Your organization, and Externally Deploy verbatim, unmodified +copies of the Original Code, for commercial or non-commercial purposes, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the +copyright and other proprietary notices and disclaimers of Apple as they appear +in the Original Code, and keep intact all notices in the Original Code that +refer to this License; and + +(b) You must include a copy of this License with every copy of Source Code +of Covered Code and documentation You distribute or Externally Deploy, and You +may not offer or impose any terms on such Source Code that alter or restrict +this License or the recipients' rights hereunder, except as permitted under +Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, +display, perform, internally distribute within Your organization, and +Externally Deploy Your Modifications and Covered Code, for commercial or +non-commercial purposes, provided that in each instance You also meet all of +these conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to the +Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the notice +in Exhibit A in each file of the Source Code of all Your Modifications, and +cause the modified files to carry prominent notices stating that You changed +the files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make Source Code +of all Your Externally Deployed Modifications either available to those to whom +You have Externally Deployed Your Modifications, or publicly available. Source +Code of Your Externally Deployed Modifications must be released under the terms +set forth in this License, including the license grants set forth in Section 3 +below, for as long as you Externally Deploy the Covered Code or twelve (12) +months from the date of initial External Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Externally Deployed +Modifications electronically (e.g. download from a web site). + +2.3 Distribution of Executable Versions. In addition, if You Externally +Deploy Covered Code (Original Code and/or Modifications) in object code, +executable form only, You must include a prominent notice, in the code itself +as well as in related documentation, stating that Source Code of the Covered +Code is available under the terms of this License with information on how and +where to obtain such Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that although +Apple and each Contributor grants the licenses to their respective portions of +the Covered Code set forth herein, no assurances are provided by Apple or any +Contributor that the Covered Code does not infringe the patent or other +intellectual property rights of any other entity. Apple and each Contributor +disclaim any liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a condition to +exercising the rights and licenses granted hereunder, You hereby assume sole +responsibility to secure any other intellectual property rights needed, if any. +For example, if a third party patent license is required to allow You to +distribute the Covered Code, it is Your responsibility to acquire that license +before distributing the Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the licenses +granted to You under this License, You hereby grant to any person or entity +receiving or distributing Covered Code under this License a non-exclusive, +royalty-free, perpetual, irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights (other than patent) owned or +controlled by You, to use, reproduce, display, perform, modify, sublicense, +distribute and Externally Deploy Your Modifications of the same scope and +extent as Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered Code +with other code not governed by the terms of this License and distribute the +Larger Work as a single product. In each such instance, You must make sure the +requirements of this License are fulfilled for the Covered Code or any portion +thereof. + +5. Limitations on Patent License. Except as expressly stated in Section +2, no other patent rights, express or implied, are granted by Apple herein. +Modifications and/or Larger Works may require additional patent licenses from +Apple which Apple may grant in its sole discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, +warranty, support, indemnity or liability obligations and/or other rights +consistent with the scope of the license granted herein ("Additional Terms") to +one or more recipients of Covered Code. However, You may do so only on Your own +behalf and as Your sole responsibility, and not on behalf of Apple or any +Contributor. You must obtain the recipient's agreement that any such Additional +Terms are offered by You alone, and You hereby agree to indemnify, defend and +hold Apple and every Contributor harmless for any liability incurred by or +claims asserted against Apple or such Contributor by reason of any such +Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new versions +of this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular +version of this License, You may continue to use it under the terms of that +version. You may also choose to use such Original Code under the terms of any +subsequent version of this License published by Apple. No one other than Apple +has the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in +part pre-release, untested, or not fully tested works. The Covered Code may +contain errors that could cause failures or loss of data, and may be incomplete +or contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" +FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM +ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF +QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED +REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You acknowledge +that the Covered Code is not intended for use in the operation of nuclear +facilities, aircraft navigation, communication systems, or air traffic control +machines in which case the failure of the Covered Code could lead to death, +personal injury, or severe physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS +LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL +PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF +LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT +APPLY TO YOU. In no event shall Apple's total liability to You for all damages +(other than as may be required by applicable law) under this License exceed the +amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the +trademarks or trade names "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime +Streaming Server" or any other trademarks, service marks, logos or trade names +belonging to Apple (collectively "Apple Marks") or to any trademark, service +mark, logo or trade name belonging to any Contributor. You agree not to use +any Apple Marks in or as part of the name of products derived from the Original +Code or to endorse or promote products derived from the Original Code other +than as expressly permitted by and in strict compliance at all times with +Apple's third party trademark usage guidelines which are posted at +http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Apple retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Apple +("Apple Modifications"), and such Apple Modifications will not be automatically +subject to this License. Apple may, at its sole discretion, choose to license +such Apple Modifications under this License, or on different terms from those +contained in this License or may choose not to license them at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; +(b) immediately in the event of the circumstances described in Section +13.5(b); or +(c) automatically without notice from Apple if You, at any time during the +term of this License, commence an action for patent infringement against Apple; +provided that Apple did not first commence an action for patent infringement +against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately stop +any further use, reproduction, modification, sublicensing and distribution of +the Covered Code. All sublicenses to the Covered Code which have been properly +granted prior to termination shall survive any termination of this License. +Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to +Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other +for compensation, indemnity or damages of any sort solely as a result of +terminating this License in accordance with its terms, and termination of this +License will be without prejudice to any other right or remedy of any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as +defined in FAR 2.101. Government software and technical data rights in the +Covered Code include only those rights customarily provided to the public as +defined in this License. This customary commercial license in technical data +and software is provided in accordance with FAR 12.211 (Technical Data) and +12.212 (Computer Software) and, for Department of Defense purchases, DFAR +252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in +Commercial Computer Software or Computer Software Documentation). Accordingly, +all U.S. Government End Users acquire Covered Code with only those rights set +forth herein. + +13.2 Relationship of Parties. This License will not be construed as +creating an agency, partnership, joint venture or any other form of legal +association between or among You, Apple or any Contributor, and You will not +represent to the contrary, whether expressly, by implication, appearance or +otherwise. + +13.3 Independent Development. Nothing in this License will impair Apple's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions +as, or otherwise compete with, Modifications, Larger Works, technology or +products that You may develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to enforce +any provision of this License will not be deemed a waiver of future enforcement +of that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +13.5 Severability. (a) If for any reason a court of competent jurisdiction +finds any provision of this License, or portion thereof, to be unenforceable, +that provision of the License will be enforced to the maximum extent +permissible so as to effect the economic benefits and intent of the parties, +and the remainder of this License will continue in full force and effect. (b) +Notwithstanding the foregoing, if applicable law prohibits or restricts You +from fully and/or specifically complying with Sections 2 and/or 3 or prevents +the enforceability of either of those Sections, this License will immediately +terminate and You must immediately discontinue any use of the Covered Code and +destroy all copies of it that are in your possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution between +You and Apple relating to this License shall take place in the Northern +District of California, and You and Apple hereby consent to the personal +jurisdiction of, and venue in, the state and federal courts within that +District with respect to this License. The application of the United Nations +Convention on Contracts for the International Sale of Goods is expressly +excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +California, except that body of California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé que le +présent contrat et tous les documents connexes soient rédigés en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. + +This file contains Original Code and/or Modifications of Original Code as +defined in and that are subject to the Apple Public Source License Version 2.0 +(the 'License'). You may not use this file except in compliance with the +License. Please obtain a copy of the License at +http://www.opensource.apple.com/apsl/ and read it before using this file. + +The Original Code and all software distributed under the License are +distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS +OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the +specific language governing rights and limitations under the License." + diff --git a/alac/codec/dp_enc.c b/alac/codec/dp_enc.c new file mode 100644 index 00000000..869104c7 --- /dev/null +++ b/alac/codec/dp_enc.c @@ -0,0 +1,386 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: dp_enc.c + + Contains: Dynamic Predictor encode routines + + Copyright: (c) 2001-2011 Apple, Inc. +*/ + +#include "dplib.h" +#include + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__((always_inline)) +#else +#define ALWAYS_INLINE +#endif + +#if TARGET_CPU_PPC && (__MWERKS__ >= 0x3200) +// align loops to a 16 byte boundary to make the G5 happy +#pragma function_align 16 +#define LOOP_ALIGN asm { align 16 } +#else +#define LOOP_ALIGN +#endif + +void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs ) +{ + int32_t k; + int32_t den = 1 << denshift; + + coefs[0] = (AINIT * den) >> 4; + coefs[1] = (BINIT * den) >> 4; + coefs[2] = (CINIT * den) >> 4; + for ( k = 3; k < numPairs; k++ ) + coefs[k] = 0; +} + +void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs ) +{ + int32_t k; + + for ( k = 0; k < numPairs; k++ ) + dstCoefs[k] = srcCoefs[k]; +} + +static inline int32_t ALWAYS_INLINE sign_of_int( int32_t i ) +{ + int32_t negishift; + + negishift = ((uint32_t)-i) >> 31; + return negishift | (i >> 31); +} + +void pc_block( int32_t * in, int32_t * pc1, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift ) +{ + register int16_t a0, a1, a2, a3; + register int32_t b0, b1, b2, b3; + int32_t j, k, lim; + int32_t * pin; + int32_t sum1, dd; + int32_t sg, sgn; + int32_t top; + int32_t del, del0; + uint32_t chanshift = 32 - chanbits; + int32_t denhalf = 1 << (denshift - 1); + + pc1[0] = in[0]; + if ( numactive == 0 ) + { + // just copy if numactive == 0 (but don't bother if in/out pointers the same) + if ( (num > 1) && (in != pc1) ) + memcpy( &pc1[1], &in[1], (num - 1) * sizeof(int32_t) ); + return; + } + if ( numactive == 31 ) + { + // short-circuit if numactive == 31 + for( j = 1; j < num; j++ ) + { + del = in[j] - in[j-1]; + pc1[j] = (del << chanshift) >> chanshift; + } + return; + } + + for ( j = 1; j <= numactive; j++ ) + { + del = in[j] - in[j-1]; + pc1[j] = (del << chanshift) >> chanshift; + } + + lim = numactive + 1; + + if ( numactive == 4 ) + { + // optimization for numactive == 4 + a0 = coefs[0]; + a1 = coefs[1]; + a2 = coefs[2]; + a3 = coefs[3]; + + for ( j = lim; j < num; j++ ) + { + LOOP_ALIGN + + top = in[j - lim]; + pin = in + j - 1; + + b0 = top - pin[0]; + b1 = top - pin[-1]; + b2 = top - pin[-2]; + b3 = top - pin[-3]; + + sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3) >> denshift; + + del = in[j] - top - sum1; + del = (del << chanshift) >> chanshift; + pc1[j] = del; + del0 = del; + + sg = sign_of_int(del); + if ( sg > 0 ) + { + sgn = sign_of_int( b3 ); + a3 -= sgn; + del0 -= (4 - 3) * ((sgn * b3) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b2 ); + a2 -= sgn; + del0 -= (4 - 2) * ((sgn * b2) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b1 ); + a1 -= sgn; + del0 -= (4 - 1) * ((sgn * b1) >> denshift); + if ( del0 <= 0 ) + continue; + + a0 -= sign_of_int( b0 ); + } + else if ( sg < 0 ) + { + // note: to avoid unnecessary negations, we flip the value of "sgn" + sgn = -sign_of_int( b3 ); + a3 -= sgn; + del0 -= (4 - 3) * ((sgn * b3) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b2 ); + a2 -= sgn; + del0 -= (4 - 2) * ((sgn * b2) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b1 ); + a1 -= sgn; + del0 -= (4 - 1) * ((sgn * b1) >> denshift); + if ( del0 >= 0 ) + continue; + + a0 += sign_of_int( b0 ); + } + } + + coefs[0] = a0; + coefs[1] = a1; + coefs[2] = a2; + coefs[3] = a3; + } + else if ( numactive == 8 ) + { + // optimization for numactive == 8 + register int16_t a4, a5, a6, a7; + register int32_t b4, b5, b6, b7; + + a0 = coefs[0]; + a1 = coefs[1]; + a2 = coefs[2]; + a3 = coefs[3]; + a4 = coefs[4]; + a5 = coefs[5]; + a6 = coefs[6]; + a7 = coefs[7]; + + for ( j = lim; j < num; j++ ) + { + LOOP_ALIGN + + top = in[j - lim]; + pin = in + j - 1; + + b0 = top - (*pin--); + b1 = top - (*pin--); + b2 = top - (*pin--); + b3 = top - (*pin--); + b4 = top - (*pin--); + b5 = top - (*pin--); + b6 = top - (*pin--); + b7 = top - (*pin); + pin += 8; + + sum1 = (denhalf - a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3 + - a4 * b4 - a5 * b5 - a6 * b6 - a7 * b7) >> denshift; + + del = in[j] - top - sum1; + del = (del << chanshift) >> chanshift; + pc1[j] = del; + del0 = del; + + sg = sign_of_int(del); + if ( sg > 0 ) + { + sgn = sign_of_int( b7 ); + a7 -= sgn; + del0 -= 1 * ((sgn * b7) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b6 ); + a6 -= sgn; + del0 -= 2 * ((sgn * b6) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b5 ); + a5 -= sgn; + del0 -= 3 * ((sgn * b5) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b4 ); + a4 -= sgn; + del0 -= 4 * ((sgn * b4) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b3 ); + a3 -= sgn; + del0 -= 5 * ((sgn * b3) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b2 ); + a2 -= sgn; + del0 -= 6 * ((sgn * b2) >> denshift); + if ( del0 <= 0 ) + continue; + + sgn = sign_of_int( b1 ); + a1 -= sgn; + del0 -= 7 * ((sgn * b1) >> denshift); + if ( del0 <= 0 ) + continue; + + a0 -= sign_of_int( b0 ); + } + else if ( sg < 0 ) + { + // note: to avoid unnecessary negations, we flip the value of "sgn" + sgn = -sign_of_int( b7 ); + a7 -= sgn; + del0 -= 1 * ((sgn * b7) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b6 ); + a6 -= sgn; + del0 -= 2 * ((sgn * b6) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b5 ); + a5 -= sgn; + del0 -= 3 * ((sgn * b5) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b4 ); + a4 -= sgn; + del0 -= 4 * ((sgn * b4) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b3 ); + a3 -= sgn; + del0 -= 5 * ((sgn * b3) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b2 ); + a2 -= sgn; + del0 -= 6 * ((sgn * b2) >> denshift); + if ( del0 >= 0 ) + continue; + + sgn = -sign_of_int( b1 ); + a1 -= sgn; + del0 -= 7 * ((sgn * b1) >> denshift); + if ( del0 >= 0 ) + continue; + + a0 += sign_of_int( b0 ); + } + } + + coefs[0] = a0; + coefs[1] = a1; + coefs[2] = a2; + coefs[3] = a3; + coefs[4] = a4; + coefs[5] = a5; + coefs[6] = a6; + coefs[7] = a7; + } + else + { +//pc_block_general: + // general case + for ( j = lim; j < num; j++ ) + { + LOOP_ALIGN + + top = in[j - lim]; + pin = in + j - 1; + + sum1 = 0; + for ( k = 0; k < numactive; k++ ) + sum1 -= coefs[k] * (top - pin[-k]); + + del = in[j] - top - ((sum1 + denhalf) >> denshift); + del = (del << chanshift) >> chanshift; + pc1[j] = del; + del0 = del; + + sg = sign_of_int( del ); + if ( sg > 0 ) + { + for ( k = (numactive - 1); k >= 0; k-- ) + { + dd = top - pin[-k]; + sgn = sign_of_int( dd ); + coefs[k] -= sgn; + del0 -= (numactive - k) * ((sgn * dd) >> denshift); + if ( del0 <= 0 ) + break; + } + } + else if ( sg < 0 ) + { + for ( k = (numactive - 1); k >= 0; k-- ) + { + dd = top - pin[-k]; + sgn = sign_of_int( dd ); + coefs[k] += sgn; + del0 -= (numactive - k) * ((-sgn * dd) >> denshift); + if ( del0 >= 0 ) + break; + } + } + } + } +} diff --git a/alac/codec/dplib.h b/alac/codec/dplib.h new file mode 100644 index 00000000..9a1ea5b2 --- /dev/null +++ b/alac/codec/dplib.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2011 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +/* + File: dplib.h + + Contains: Dynamic Predictor routines + + Copyright: Copyright (C) 2001-2011 Apple, Inc. +*/ + +#ifndef __DPLIB_H__ +#define __DPLIB_H__ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +// defines + +#define DENSHIFT_MAX 15 +#define DENSHIFT_DEFAULT 9 +#define AINIT 38 +#define BINIT (-29) +#define CINIT (-2) +#define NUMCOEPAIRS 16 + +// prototypes + +void init_coefs( int16_t * coefs, uint32_t denshift, int32_t numPairs ); +void copy_coefs( int16_t * srcCoefs, int16_t * dstCoefs, int32_t numPairs ); + +// NOTE: these routines read at least "numactive" samples so the i/o buffers must be at least that big + +void pc_block( int32_t * in, int32_t * pc, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift ); +void unpc_block( int32_t * pc, int32_t * out, int32_t num, int16_t * coefs, int32_t numactive, uint32_t chanbits, uint32_t denshift ); + +#ifdef __cplusplus +} +#endif + +#endif /* __DPLIB_H__ */