diff --git a/alac/codec/ag_dec.c b/alac/codec/ag_dec.c new file mode 100644 index 00000000..2214c941 --- /dev/null +++ b/alac/codec/ag_dec.c @@ -0,0 +1,362 @@ +/* + * 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: ag_dec.c + + Contains: Adaptive Golomb decode routines. + + Copyright: (c) 2001-2011 Apple, Inc. +*/ + +#include "aglib.h" +#include "ALACBitUtilities.h" +#include "ALACAudioTypes.h" + +#include +#include +#include +#include +#if __GNUC__ && TARGET_OS_MAC + #if __POWERPC__ + #include + #else + #include + #endif +#endif + +#define CODE_TO_LONG_MAXBITS 32 +#define N_MAX_MEAN_CLAMP 0xffff +#define N_MEAN_CLAMP_VAL 0xffff +#define REPORT_VAL 40 + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__((always_inline)) +#else +#define ALWAYS_INLINE +#endif + +/* And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this + to help the compiler out. In many cases this required manual inlining or a macro. Sorry + if it is ugly but the performance gains are well worth it. + - WSK 5/19/04 +*/ + +void set_standard_ag_params(AGParamRecPtr params, uint32_t fullwidth, uint32_t sectorwidth) +{ + /* Use + fullwidth = sectorwidth = numOfSamples, for analog 1-dimensional type-short data, + but use + fullwidth = full image width, sectorwidth = sector (patch) width + for such as image (2-dim.) data. + */ + set_ag_params( params, MB0, PB0, KB0, fullwidth, sectorwidth, MAX_RUN_DEFAULT ); +} + +void set_ag_params(AGParamRecPtr params, uint32_t m, uint32_t p, uint32_t k, uint32_t f, uint32_t s, uint32_t maxrun) +{ + params->mb = params->mb0 = m; + params->pb = p; + params->kb = k; + params->wb = (1u<kb)-1; + params->qb = QB-params->pb; + params->fw = f; + params->sw = s; + params->maxrun = maxrun; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + + +// note: implementing this with some kind of "count leading zeros" assembly is a big performance win +static inline int32_t lead( int32_t m ) +{ + long j; + unsigned long c = (1ul << 31); + + for(j=0; j < 32; j++) + { + if((c & m) != 0) + break; + c >>= 1; + } + return (j); +} + +#define arithmin(a, b) ((a) < (b) ? (a) : (b)) + +static inline int32_t ALWAYS_INLINE lg3a( int32_t x) +{ + int32_t result; + + x += 3; + result = lead(x); + + return 31 - result; +} + +static inline uint32_t ALWAYS_INLINE read32bit( uint8_t * buffer ) +{ + // embedded CPUs typically can't read unaligned 32-bit words so just read the bytes + uint32_t value; + + value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) | + ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3]; + return value; + +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +#define get_next_fromlong(inlong, suff) ((inlong) >> (32 - (suff))) + + +static inline uint32_t ALWAYS_INLINE +getstreambits( uint8_t *in, int32_t bitoffset, int32_t numbits ) +{ + uint32_t load1, load2; + uint32_t byteoffset = bitoffset / 8; + uint32_t result; + + //Assert( numbits <= 32 ); + + load1 = read32bit( in + byteoffset ); + + if ( (numbits + (bitoffset & 0x7)) > 32) + { + int32_t load2shift; + + result = load1 << (bitoffset & 0x7); + load2 = (uint32_t) in[byteoffset+4]; + load2shift = (8-(numbits + (bitoffset & 0x7)-32)); + load2 >>= load2shift; + result >>= (32-numbits); + result |= load2; + } + else + { + result = load1 >> (32-numbits-(bitoffset & 7)); + } + + // a shift of >= "the number of bits in the type of the value being shifted" results in undefined + // behavior so don't try to shift by 32 + if ( numbits != (sizeof(result) * 8) ) + result &= ~(0xfffffffful << numbits); + + return result; +} + + +static inline int32_t dyn_get(unsigned char *in, uint32_t *bitPos, uint32_t m, uint32_t k) +{ + uint32_t tempbits = *bitPos; + uint32_t result; + uint32_t pre = 0, v; + uint32_t streamlong; + + streamlong = read32bit( in + (tempbits >> 3) ); + streamlong <<= (tempbits & 7); + + /* find the number of bits in the prefix */ + { + uint32_t notI = ~streamlong; + pre = lead( notI); + } + + if(pre >= MAX_PREFIX_16) + { + pre = MAX_PREFIX_16; + tempbits += pre; + streamlong <<= pre; + result = get_next_fromlong(streamlong,MAX_DATATYPE_BITS_16); + tempbits += MAX_DATATYPE_BITS_16; + + } + else + { + // all of the bits must fit within the long we have loaded + //Assert(pre+1+k <= 32); + + tempbits += pre; + tempbits += 1; + streamlong <<= pre+1; + v = get_next_fromlong(streamlong, k); + tempbits += k; + + result = pre*m + v-1; + + if(v<2) { + result -= (v-1); + tempbits -= 1; + } + } + + *bitPos = tempbits; + return result; +} + + +static inline int32_t dyn_get_32bit( uint8_t * in, uint32_t * bitPos, int32_t m, int32_t k, int32_t maxbits ) +{ + uint32_t tempbits = *bitPos; + uint32_t v; + uint32_t streamlong; + uint32_t result; + + streamlong = read32bit( in + (tempbits >> 3) ); + streamlong <<= (tempbits & 7); + + /* find the number of bits in the prefix */ + { + uint32_t notI = ~streamlong; + result = lead( notI); + } + + if(result >= MAX_PREFIX_32) + { + result = getstreambits(in, tempbits+MAX_PREFIX_32, maxbits); + tempbits += MAX_PREFIX_32 + maxbits; + } + else + { + /* all of the bits must fit within the long we have loaded*/ + //Assert(k<=14); + //Assert(result=2) + { + result += (v-1); + tempbits += 1; + } + } + } + + *bitPos = tempbits; + + return result; +} + +int32_t dyn_decomp( AGParamRecPtr params, BitBuffer * bitstream, int32_t * pc, int32_t numSamples, int32_t maxSize, uint32_t * outNumBits ) +{ + uint8_t *in; + int32_t *outPtr = pc; + uint32_t bitPos, startPos, maxPos; + uint32_t j, m, k, n, c, mz; + int32_t del, zmode; + uint32_t mb; + uint32_t pb_local = params->pb; + uint32_t kb_local = params->kb; + uint32_t wb_local = params->wb; + int32_t status; + + RequireAction( (bitstream != nil) && (pc != nil) && (outNumBits != nil), return kALAC_ParamError; ); + *outNumBits = 0; + + in = bitstream->cur; + startPos = bitstream->bitIndex; + maxPos = bitstream->byteSize * 8; + bitPos = startPos; + + mb = params->mb0; + zmode = 0; + + c = 0; + status = ALAC_noErr; + + while (c < numSamples) + { + // bail if we've run off the end of the buffer + RequireAction( bitPos < maxPos, status = kALAC_ParamError; goto Exit; ); + + m = (mb)>>QBSHIFT; + k = lg3a(m); + + k = arithmin(k, kb_local); + m = (1<> 1) * (multiplier); + } + + *outPtr++ = del; + + c++; + + mb = pb_local*(n+zmode) + mb - ((pb_local*mb)>>QBSHIFT); + + // update mean tracking + if (n > N_MAX_MEAN_CLAMP) + mb = N_MEAN_CLAMP_VAL; + + zmode = 0; + + if (((mb << MMULSHIFT) < QB) && (c < numSamples)) + { + zmode = 1; + k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT); + mz = ((1<= 65535) + zmode = 0; + + mb = 0; + } + } + +Exit: + *outNumBits = (bitPos - startPos); + BitBufferAdvance( bitstream, *outNumBits ); + RequireAction( bitstream->cur <= bitstream->end, status = kALAC_ParamError; ); + + return status; +} diff --git a/alac/codec/ag_enc.c b/alac/codec/ag_enc.c new file mode 100644 index 00000000..2dfe9996 --- /dev/null +++ b/alac/codec/ag_enc.c @@ -0,0 +1,370 @@ +/* + * 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: ag_enc.c + + Contains: Adaptive Golomb encode routines. + + Copyright: (c) 2001-2011 Apple, Inc. +*/ + +#include "aglib.h" +#include "ALACBitUtilities.h" +#include "EndianPortable.h" +#include "ALACAudioTypes.h" + +#include +#include +#include +#include +#if __GNUC__ && TARGET_OS_MAC + #if __POWERPC__ + #include + #else + #include + #endif +#endif + +#define CODE_TO_LONG_MAXBITS 32 +#define N_MAX_MEAN_CLAMP 0xffff +#define N_MEAN_CLAMP_VAL 0xffff +#define REPORT_VAL 40 + +#if __GNUC__ +#define ALWAYS_INLINE __attribute__((always_inline)) +#else +#define ALWAYS_INLINE +#endif + + +/* And on the subject of the CodeWarrior x86 compiler and inlining, I reworked a lot of this + to help the compiler out. In many cases this required manual inlining or a macro. Sorry + if it is ugly but the performance gains are well worth it. + - WSK 5/19/04 +*/ + +// note: implementing this with some kind of "count leading zeros" assembly is a big performance win +static inline int32_t lead( int32_t m ) +{ + long j; + unsigned long c = (1ul << 31); + + for(j=0; j < 32; j++) + { + if((c & m) != 0) + break; + c >>= 1; + } + return (j); +} + +#define arithmin(a, b) ((a) < (b) ? (a) : (b)) + +static inline int32_t ALWAYS_INLINE lg3a( int32_t x) +{ + int32_t result; + + x += 3; + result = lead(x); + + return 31 - result; +} + +static inline int32_t ALWAYS_INLINE abs_func( int32_t a ) +{ + // note: the CW PPC intrinsic __abs() turns into these instructions so no need to try and use it + int32_t isneg = a >> 31; + int32_t xorval = a ^ isneg; + int32_t result = xorval-isneg; + + return result; +} + +static inline uint32_t ALWAYS_INLINE read32bit( uint8_t * buffer ) +{ + // embedded CPUs typically can't read unaligned 32-bit words so just read the bytes + uint32_t value; + + value = ((uint32_t)buffer[0] << 24) | ((uint32_t)buffer[1] << 16) | + ((uint32_t)buffer[2] << 8) | (uint32_t)buffer[3]; + return value; +} + +#if PRAGMA_MARK +#pragma mark - +#endif + +static inline int32_t dyn_code(int32_t m, int32_t k, int32_t n, uint32_t *outNumBits) +{ + uint32_t div, mod, de; + uint32_t numBits; + uint32_t value; + + //Assert( n >= 0 ); + + div = n/m; + + if(div >= MAX_PREFIX_16) + { + numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16; + value = (((1< MAX_PREFIX_16 + MAX_DATATYPE_BITS_16) + { + numBits = MAX_PREFIX_16 + MAX_DATATYPE_BITS_16; + value = (((1< 25) + goto codeasescape; + } + else + { +codeasescape: + numBits = MAX_PREFIX_32; + value = (((1<> 3)); + uint32_t mask; + uint32_t curr; + uint32_t shift; + + //Assert( numBits <= 32 ); + + curr = *i; + curr = Swap32NtoB( curr ); + + shift = 32 - (bitPos & 7) - numBits; + + mask = ~0u >> (32 - numBits); // mask must be created in two steps to avoid compiler sequencing ambiguity + mask <<= shift; + + value = (value << shift) & mask; + value |= curr & ~mask; + + *i = Swap32BtoN( value ); +} + + +static inline void ALWAYS_INLINE dyn_jam_noDeref_large(unsigned char *out, uint32_t bitPos, uint32_t numBits, uint32_t value) +{ + uint32_t * i = (uint32_t *)(out + (bitPos>>3)); + uint32_t w; + uint32_t curr; + uint32_t mask; + int32_t shiftvalue = (32 - (bitPos&7) - numBits); + + //Assert(numBits <= 32); + + curr = *i; + curr = Swap32NtoB( curr ); + + if (shiftvalue < 0) + { + uint8_t tailbyte; + uint8_t *tailptr; + + w = value >> -shiftvalue; + mask = ~0u >> -shiftvalue; + w |= (curr & ~mask); + + tailptr = ((uint8_t *)i) + 4; + tailbyte = (value << ((8+shiftvalue))) & 0xff; + *tailptr = (uint8_t)tailbyte; + } + else + { + mask = ~0u >> (32 - numBits); + mask <<= shiftvalue; // mask must be created in two steps to avoid compiler sequencing ambiguity + + w = (value << shiftvalue) & mask; + w |= curr & ~mask; + } + + *i = Swap32BtoN( w ); +} + + +int32_t dyn_comp( AGParamRecPtr params, int32_t * pc, BitBuffer * bitstream, int32_t numSamples, int32_t bitSize, uint32_t * outNumBits ) +{ + unsigned char * out; + uint32_t bitPos, startPos; + uint32_t m, k, n, c, mz, nz; + uint32_t numBits; + uint32_t value; + int32_t del, zmode; + uint32_t overflow, overflowbits; + int32_t status; + + // shadow the variables in params so there's not the dereferencing overhead + uint32_t mb, pb, kb, wb; + int32_t rowPos = 0; + int32_t rowSize = params->sw; + int32_t rowJump = (params->fw) - rowSize; + int32_t * inPtr = pc; + + *outNumBits = 0; + RequireAction( (bitSize >= 1) && (bitSize <= 32), return kALAC_ParamError; ); + + out = bitstream->cur; + startPos = bitstream->bitIndex; + bitPos = startPos; + + mb = params->mb = params->mb0; + pb = params->pb; + kb = params->kb; + wb = params->wb; + zmode = 0; + + c=0; + status = ALAC_noErr; + + while (c < numSamples) + { + m = mb >> QBSHIFT; + k = lg3a(m); + if ( k > kb) + { + k = kb; + } + m = (1<> 31) & 1) - zmode; + //Assert( 32-lead(n) <= bitSize ); + + if ( dyn_code_32bit(bitSize, m, k, n, &numBits, &value, &overflow, &overflowbits) ) + { + dyn_jam_noDeref(out, bitPos, numBits, value); + bitPos += numBits; + dyn_jam_noDeref_large(out, bitPos, overflowbits, overflow); + bitPos += overflowbits; + } + else + { + dyn_jam_noDeref(out, bitPos, numBits, value); + bitPos += numBits; + } + + c++; + if ( rowPos >= rowSize) + { + rowPos = 0; + inPtr += rowJump; + } + + mb = pb * (n + zmode) + mb - ((pb *mb)>>QBSHIFT); + + // update mean tracking if it's overflowed + if (n > N_MAX_MEAN_CLAMP) + mb = N_MEAN_CLAMP_VAL; + + zmode = 0; + + RequireAction(c <= numSamples, status = kALAC_ParamError; goto Exit; ); + + if (((mb << MMULSHIFT) < QB) && (c < numSamples)) + { + zmode = 1; + nz = 0; + + while(c= rowSize) + { + rowPos = 0; + inPtr += rowJump; + } + + if(nz >= 65535) + { + zmode = 0; + break; + } + } + + k = lead(mb) - BITOFF+((mb+MOFF)>>MDENSHIFT); + mz = ((1< + +#ifdef __cplusplus +extern "C" { +#endif + +#define QBSHIFT 9 +#define QB (1<