alac_decoder/0000755000076500007650000000000011251345442013366 5ustar crazneycrazneyalac_decoder/alac.c0000644000076500007650000010336611251345442014443 0ustar crazneycrazney/* * ALAC (Apple Lossless Audio Codec) decoder * Copyright (c) 2005 David Hammerton * All rights reserved. * * This is the actual decoder. * * http://crazney.net/programs/itunes/alac.html * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #ifdef _WIN32 #include "stdint_win.h" #else #include #endif #include "decomp.h" #define _Swap32(v) do { \ v = (((v) & 0x000000FF) << 0x18) | \ (((v) & 0x0000FF00) << 0x08) | \ (((v) & 0x00FF0000) >> 0x08) | \ (((v) & 0xFF000000) >> 0x18); } while(0) #define _Swap16(v) do { \ v = (((v) & 0x00FF) << 0x08) | \ (((v) & 0xFF00) >> 0x08); } while (0) struct {signed int x:24;} se_struct_24; #define SignExtend24(val) (se_struct_24.x = val) extern int host_bigendian; struct alac_file { unsigned char *input_buffer; int input_buffer_bitaccumulator; /* used so we can do arbitary bit reads */ int samplesize; int numchannels; int bytespersample; /* buffers */ int32_t *predicterror_buffer_a; int32_t *predicterror_buffer_b; int32_t *outputsamples_buffer_a; int32_t *outputsamples_buffer_b; int32_t *uncompressed_bytes_buffer_a; int32_t *uncompressed_bytes_buffer_b; /* stuff from setinfo */ uint32_t setinfo_max_samples_per_frame; /* 0x1000 = 4096 */ /* max samples per frame? */ uint8_t setinfo_7a; /* 0x00 */ uint8_t setinfo_sample_size; /* 0x10 */ uint8_t setinfo_rice_historymult; /* 0x28 */ uint8_t setinfo_rice_initialhistory; /* 0x0a */ uint8_t setinfo_rice_kmodifier; /* 0x0e */ uint8_t setinfo_7f; /* 0x02 */ uint16_t setinfo_80; /* 0x00ff */ uint32_t setinfo_82; /* 0x000020e7 */ /* max sample size?? */ uint32_t setinfo_86; /* 0x00069fe4 */ /* bit rate (avarge)?? */ uint32_t setinfo_8a_rate; /* 0x0000ac44 */ /* end setinfo stuff */ }; static void allocate_buffers(alac_file *alac) { alac->predicterror_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4); alac->predicterror_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4); alac->outputsamples_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4); alac->outputsamples_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4); alac->uncompressed_bytes_buffer_a = malloc(alac->setinfo_max_samples_per_frame * 4); alac->uncompressed_bytes_buffer_b = malloc(alac->setinfo_max_samples_per_frame * 4); } void alac_set_info(alac_file *alac, char *inputbuffer) { char *ptr = inputbuffer; ptr += 4; /* size */ ptr += 4; /* frma */ ptr += 4; /* alac */ ptr += 4; /* size */ ptr += 4; /* alac */ ptr += 4; /* 0 ? */ alac->setinfo_max_samples_per_frame = *(uint32_t*)ptr; /* buffer size / 2 ? */ if (!host_bigendian) _Swap32(alac->setinfo_max_samples_per_frame); ptr += 4; alac->setinfo_7a = *(uint8_t*)ptr; ptr += 1; alac->setinfo_sample_size = *(uint8_t*)ptr; ptr += 1; alac->setinfo_rice_historymult = *(uint8_t*)ptr; ptr += 1; alac->setinfo_rice_initialhistory = *(uint8_t*)ptr; ptr += 1; alac->setinfo_rice_kmodifier = *(uint8_t*)ptr; ptr += 1; alac->setinfo_7f = *(uint8_t*)ptr; ptr += 1; alac->setinfo_80 = *(uint16_t*)ptr; if (!host_bigendian) _Swap16(alac->setinfo_80); ptr += 2; alac->setinfo_82 = *(uint32_t*)ptr; if (!host_bigendian) _Swap32(alac->setinfo_82); ptr += 4; alac->setinfo_86 = *(uint32_t*)ptr; if (!host_bigendian) _Swap32(alac->setinfo_86); ptr += 4; alac->setinfo_8a_rate = *(uint32_t*)ptr; if (!host_bigendian) _Swap32(alac->setinfo_8a_rate); ptr += 4; allocate_buffers(alac); } /* stream reading */ /* supports reading 1 to 16 bits, in big endian format */ static uint32_t readbits_16(alac_file *alac, int bits) { uint32_t result; int new_accumulator; result = (alac->input_buffer[0] << 16) | (alac->input_buffer[1] << 8) | (alac->input_buffer[2]); /* shift left by the number of bits we've already read, * so that the top 'n' bits of the 24 bits we read will * be the return bits */ result = result << alac->input_buffer_bitaccumulator; result = result & 0x00ffffff; /* and then only want the top 'n' bits from that, where * n is 'bits' */ result = result >> (24 - bits); new_accumulator = (alac->input_buffer_bitaccumulator + bits); /* increase the buffer pointer if we've read over n bytes. */ alac->input_buffer += (new_accumulator >> 3); /* and the remainder goes back into the bit accumulator */ alac->input_buffer_bitaccumulator = (new_accumulator & 7); return result; } /* supports reading 1 to 32 bits, in big endian format */ static uint32_t readbits(alac_file *alac, int bits) { int32_t result = 0; if (bits > 16) { bits -= 16; result = readbits_16(alac, 16) << bits; } result |= readbits_16(alac, bits); return result; } /* reads a single bit */ static int readbit(alac_file *alac) { int result; int new_accumulator; result = alac->input_buffer[0]; result = result << alac->input_buffer_bitaccumulator; result = result >> 7 & 1; new_accumulator = (alac->input_buffer_bitaccumulator + 1); alac->input_buffer += (new_accumulator / 8); alac->input_buffer_bitaccumulator = (new_accumulator % 8); return result; } static void unreadbits(alac_file *alac, int bits) { int new_accumulator = (alac->input_buffer_bitaccumulator - bits); alac->input_buffer += (new_accumulator >> 3); alac->input_buffer_bitaccumulator = (new_accumulator & 7); if (alac->input_buffer_bitaccumulator < 0) alac->input_buffer_bitaccumulator *= -1; } /* various implementations of count_leading_zero: * the first one is the original one, the simplest and most * obvious for what it's doing. never use this. * then there are the asm ones. fill in as necessary * and finally an unrolled and optimised c version * to fall back to */ #if 0 /* hideously inefficient. could use a bitmask search, * alternatively bsr on x86, */ static int count_leading_zeros(int32_t input) { int i = 0; while (!(0x80000000 & input) && i < 32) { i++; input = input << 1; } return i; } #elif defined(__GNUC__) && (defined(_X86) || defined(__i386) || defined(i386)) /* for some reason the unrolled version (below) is * actually faster than this. yay intel! */ static int count_leading_zeros(int input) { int output = 0; if (!input) return 32; __asm("bsr %1, %0\n" : "=r" (output) : "r" (input)); return (0x1f - output); } #elif defined(_MSC_VER) && defined(_M_IX86) static int count_leading_zeros(int input) { int output = 0; if (!input) return 32; __asm { mov eax, input; mov edx, 0x1f; bsr ecx, eax; sub edx, ecx; mov output, edx; } return output; } #else #warning using generic count leading zeroes. You may wish to write one for your CPU / compiler static int count_leading_zeros(int input) { int output = 0; int curbyte = 0; curbyte = input >> 24; if (curbyte) goto found; output += 8; curbyte = input >> 16; if (curbyte & 0xff) goto found; output += 8; curbyte = input >> 8; if (curbyte & 0xff) goto found; output += 8; curbyte = input; if (curbyte & 0xff) goto found; output += 8; return output; found: if (!(curbyte & 0xf0)) { output += 4; } else curbyte >>= 4; if (curbyte & 0x8) return output; if (curbyte & 0x4) return output + 1; if (curbyte & 0x2) return output + 2; if (curbyte & 0x1) return output + 3; /* shouldn't get here: */ return output + 4; } #endif #define RICE_THRESHOLD 8 // maximum number of bits for a rice prefix. int32_t entropy_decode_value(alac_file* alac, int readSampleSize, int k, int rice_kmodifier_mask) { int32_t x = 0; // decoded value // read x, number of 1s before 0 represent the rice value. while (x <= RICE_THRESHOLD && readbit(alac)) { x++; } if (x > RICE_THRESHOLD) { // read the number from the bit stream (raw value) int32_t value; value = readbits(alac, readSampleSize); // mask value value &= (((uint32_t)0xffffffff) >> (32 - readSampleSize)); x = value; } else { if (k != 1) { int extraBits = readbits(alac, k); // x = x * (2^k - 1) x *= (((1 << k) - 1) & rice_kmodifier_mask); if (extraBits > 1) x += extraBits - 1; else unreadbits(alac, 1); } } return x; } void entropy_rice_decode(alac_file* alac, int32_t* outputBuffer, int outputSize, int readSampleSize, int rice_initialhistory, int rice_kmodifier, int rice_historymult, int rice_kmodifier_mask) { int outputCount; int history = rice_initialhistory; int signModifier = 0; for (outputCount = 0; outputCount < outputSize; outputCount++) { int32_t decodedValue; int32_t finalValue; int32_t k; k = 31 - rice_kmodifier - count_leading_zeros((history >> 9) + 3); if (k < 0) k += rice_kmodifier; else k = rice_kmodifier; // note: don't use rice_kmodifier_mask here (set mask to 0xFFFFFFFF) decodedValue = entropy_decode_value(alac, readSampleSize, k, 0xFFFFFFFF); decodedValue += signModifier; finalValue = (decodedValue + 1) / 2; // inc by 1 and shift out sign bit if (decodedValue & 1) // the sign is stored in the low bit finalValue *= -1; outputBuffer[outputCount] = finalValue; signModifier = 0; // update history history += (decodedValue * rice_historymult) - ((history * rice_historymult) >> 9); if (decodedValue > 0xFFFF) history = 0xFFFF; // special case, for compressed blocks of 0 if ((history < 128) && (outputCount + 1 < outputSize)) { int32_t blockSize; signModifier = 1; k = count_leading_zeros(history) + ((history + 16) / 64) - 24; // note: blockSize is always 16bit blockSize = entropy_decode_value(alac, 16, k, rice_kmodifier_mask); // got blockSize 0s if (blockSize > 0) { memset(&outputBuffer[outputCount + 1], 0, blockSize * sizeof(*outputBuffer)); outputCount += blockSize; } if (blockSize > 0xFFFF) signModifier = 0; history = 0; } } } #define SIGN_EXTENDED32(val, bits) ((val << (32 - bits)) >> (32 - bits)) #define SIGN_ONLY(v) \ ((v < 0) ? (-1) : \ ((v > 0) ? (1) : \ (0))) static void predictor_decompress_fir_adapt(int32_t *error_buffer, int32_t *buffer_out, int output_size, int readsamplesize, int16_t *predictor_coef_table, int predictor_coef_num, int predictor_quantitization) { int i; /* first sample always copies */ *buffer_out = *error_buffer; if (!predictor_coef_num) { if (output_size <= 1) return; memcpy(buffer_out+1, error_buffer+1, (output_size-1) * 4); return; } if (predictor_coef_num == 0x1f) /* 11111 - max value of predictor_coef_num */ { /* second-best case scenario for fir decompression, * error describes a small difference from the previous sample only */ if (output_size <= 1) return; for (i = 0; i < output_size - 1; i++) { int32_t prev_value; int32_t error_value; prev_value = buffer_out[i]; error_value = error_buffer[i+1]; buffer_out[i+1] = SIGN_EXTENDED32((prev_value + error_value), readsamplesize); } return; } /* read warm-up samples */ if (predictor_coef_num > 0) { int i; for (i = 0; i < predictor_coef_num; i++) { int32_t val; val = buffer_out[i] + error_buffer[i+1]; val = SIGN_EXTENDED32(val, readsamplesize); buffer_out[i+1] = val; } } #if 0 /* 4 and 8 are very common cases (the only ones i've seen). these * should be unrolled and optimised */ if (predictor_coef_num == 4) { /* FIXME: optimised general case */ return; } if (predictor_coef_table == 8) { /* FIXME: optimised general case */ return; } #endif /* general case */ if (predictor_coef_num > 0) { for (i = predictor_coef_num + 1; i < output_size; i++) { int j; int sum = 0; int outval; int error_val = error_buffer[i]; for (j = 0; j < predictor_coef_num; j++) { sum += (buffer_out[predictor_coef_num-j] - buffer_out[0]) * predictor_coef_table[j]; } outval = (1 << (predictor_quantitization-1)) + sum; outval = outval >> predictor_quantitization; outval = outval + buffer_out[0] + error_val; outval = SIGN_EXTENDED32(outval, readsamplesize); buffer_out[predictor_coef_num+1] = outval; if (error_val > 0) { int predictor_num = predictor_coef_num - 1; while (predictor_num >= 0 && error_val > 0) { int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num]; int sign = SIGN_ONLY(val); predictor_coef_table[predictor_num] -= sign; val *= sign; /* absolute value */ error_val -= ((val >> predictor_quantitization) * (predictor_coef_num - predictor_num)); predictor_num--; } } else if (error_val < 0) { int predictor_num = predictor_coef_num - 1; while (predictor_num >= 0 && error_val < 0) { int val = buffer_out[0] - buffer_out[predictor_coef_num - predictor_num]; int sign = - SIGN_ONLY(val); predictor_coef_table[predictor_num] -= sign; val *= sign; /* neg value */ error_val -= ((val >> predictor_quantitization) * (predictor_coef_num - predictor_num)); predictor_num--; } } buffer_out++; } } } void deinterlace_16(int32_t *buffer_a, int32_t *buffer_b, int16_t *buffer_out, int numchannels, int numsamples, uint8_t interlacing_shift, uint8_t interlacing_leftweight) { int i; if (numsamples <= 0) return; /* weighted interlacing */ if (interlacing_leftweight) { for (i = 0; i < numsamples; i++) { int32_t difference, midright; int16_t left; int16_t right; midright = buffer_a[i]; difference = buffer_b[i]; right = midright - ((difference * interlacing_leftweight) >> interlacing_shift); left = right + difference; /* output is always little endian */ if (host_bigendian) { _Swap16(left); _Swap16(right); } buffer_out[i*numchannels] = left; buffer_out[i*numchannels + 1] = right; } return; } /* otherwise basic interlacing took place */ for (i = 0; i < numsamples; i++) { int16_t left, right; left = buffer_a[i]; right = buffer_b[i]; /* output is always little endian */ if (host_bigendian) { _Swap16(left); _Swap16(right); } buffer_out[i*numchannels] = left; buffer_out[i*numchannels + 1] = right; } } void deinterlace_24(int32_t *buffer_a, int32_t *buffer_b, int uncompressed_bytes, int32_t *uncompressed_bytes_buffer_a, int32_t *uncompressed_bytes_buffer_b, void *buffer_out, int numchannels, int numsamples, uint8_t interlacing_shift, uint8_t interlacing_leftweight) { int i; if (numsamples <= 0) return; /* weighted interlacing */ if (interlacing_leftweight) { for (i = 0; i < numsamples; i++) { int32_t difference, midright; int32_t left; int32_t right; midright = buffer_a[i]; difference = buffer_b[i]; right = midright - ((difference * interlacing_leftweight) >> interlacing_shift); left = right + difference; if (uncompressed_bytes) { uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8)); left <<= (uncompressed_bytes * 8); right <<= (uncompressed_bytes * 8); left |= uncompressed_bytes_buffer_a[i] & mask; right |= uncompressed_bytes_buffer_b[i] & mask; } ((uint8_t*)buffer_out)[i * numchannels * 3] = (left) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 3] = (right) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF; } return; } /* otherwise basic interlacing took place */ for (i = 0; i < numsamples; i++) { int32_t left, right; left = buffer_a[i]; right = buffer_b[i]; if (uncompressed_bytes) { uint32_t mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8)); left <<= (uncompressed_bytes * 8); right <<= (uncompressed_bytes * 8); left |= uncompressed_bytes_buffer_a[i] & mask; right |= uncompressed_bytes_buffer_b[i] & mask; } ((uint8_t*)buffer_out)[i * numchannels * 3] = (left) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 1] = (left >> 8) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 2] = (left >> 16) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 3] = (right) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 4] = (right >> 8) & 0xFF; ((uint8_t*)buffer_out)[i * numchannels * 3 + 5] = (right >> 16) & 0xFF; } } void decode_frame(alac_file *alac, unsigned char *inbuffer, void *outbuffer, int *outputsize) { int channels; int32_t outputsamples = alac->setinfo_max_samples_per_frame; /* setup the stream */ alac->input_buffer = inbuffer; alac->input_buffer_bitaccumulator = 0; channels = readbits(alac, 3); *outputsize = outputsamples * alac->bytespersample; switch(channels) { case 0: /* 1 channel */ { int hassize; int isnotcompressed; int readsamplesize; int uncompressed_bytes; int ricemodifier; /* 2^result = something to do with output waiting. * perhaps matters if we read > 1 frame in a pass? */ readbits(alac, 4); readbits(alac, 12); /* unknown, skip 12 bits */ hassize = readbits(alac, 1); /* the output sample size is stored soon */ uncompressed_bytes = readbits(alac, 2); /* number of bytes in the (compressed) stream that are not compressed */ isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */ if (hassize) { /* now read the number of samples, * as a 32bit integer */ outputsamples = readbits(alac, 32); *outputsize = outputsamples * alac->bytespersample; } readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8); if (!isnotcompressed) { /* so it is compressed */ int16_t predictor_coef_table[32]; int predictor_coef_num; int prediction_type; int prediction_quantitization; int i; /* skip 16 bits, not sure what they are. seem to be used in * two channel case */ readbits(alac, 8); readbits(alac, 8); prediction_type = readbits(alac, 4); prediction_quantitization = readbits(alac, 4); ricemodifier = readbits(alac, 3); predictor_coef_num = readbits(alac, 5); /* read the predictor table */ for (i = 0; i < predictor_coef_num; i++) { predictor_coef_table[i] = (int16_t)readbits(alac, 16); } if (uncompressed_bytes) { int i; for (i = 0; i < outputsamples; i++) { alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8); } } entropy_rice_decode(alac, alac->predicterror_buffer_a, outputsamples, readsamplesize, alac->setinfo_rice_initialhistory, alac->setinfo_rice_kmodifier, ricemodifier * alac->setinfo_rice_historymult / 4, (1 << alac->setinfo_rice_kmodifier) - 1); if (prediction_type == 0) { /* adaptive fir */ predictor_decompress_fir_adapt(alac->predicterror_buffer_a, alac->outputsamples_buffer_a, outputsamples, readsamplesize, predictor_coef_table, predictor_coef_num, prediction_quantitization); } else { fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type); /* i think the only other prediction type (or perhaps this is just a * boolean?) runs adaptive fir twice.. like: * predictor_decompress_fir_adapt(predictor_error, tempout, ...) * predictor_decompress_fir_adapt(predictor_error, outputsamples ...) * little strange.. */ } } else { /* not compressed, easy case */ if (alac->setinfo_sample_size <= 16) { int i; for (i = 0; i < outputsamples; i++) { int32_t audiobits = readbits(alac, alac->setinfo_sample_size); audiobits = SIGN_EXTENDED32(audiobits, alac->setinfo_sample_size); alac->outputsamples_buffer_a[i] = audiobits; } } else { int i; for (i = 0; i < outputsamples; i++) { int32_t audiobits; audiobits = readbits(alac, 16); /* special case of sign extension.. * as we'll be ORing the low 16bits into this */ audiobits = audiobits << (alac->setinfo_sample_size - 16); audiobits |= readbits(alac, alac->setinfo_sample_size - 16); audiobits = SignExtend24(audiobits); alac->outputsamples_buffer_a[i] = audiobits; } } uncompressed_bytes = 0; // always 0 for uncompressed } switch(alac->setinfo_sample_size) { case 16: { int i; for (i = 0; i < outputsamples; i++) { int16_t sample = alac->outputsamples_buffer_a[i]; if (host_bigendian) _Swap16(sample); ((int16_t*)outbuffer)[i * alac->numchannels] = sample; } break; } case 24: { int i; for (i = 0; i < outputsamples; i++) { int32_t sample = alac->outputsamples_buffer_a[i]; if (uncompressed_bytes) { uint32_t mask; sample = sample << (uncompressed_bytes * 8); mask = ~(0xFFFFFFFF << (uncompressed_bytes * 8)); sample |= alac->uncompressed_bytes_buffer_a[i] & mask; } ((uint8_t*)outbuffer)[i * alac->numchannels * 3] = (sample) & 0xFF; ((uint8_t*)outbuffer)[i * alac->numchannels * 3 + 1] = (sample >> 8) & 0xFF; ((uint8_t*)outbuffer)[i * alac->numchannels * 3 + 2] = (sample >> 16) & 0xFF; } break; } case 20: case 32: fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); break; default: break; } break; } case 1: /* 2 channels */ { int hassize; int isnotcompressed; int readsamplesize; int uncompressed_bytes; uint8_t interlacing_shift; uint8_t interlacing_leftweight; /* 2^result = something to do with output waiting. * perhaps matters if we read > 1 frame in a pass? */ readbits(alac, 4); readbits(alac, 12); /* unknown, skip 12 bits */ hassize = readbits(alac, 1); /* the output sample size is stored soon */ uncompressed_bytes = readbits(alac, 2); /* the number of bytes in the (compressed) stream that are not compressed */ isnotcompressed = readbits(alac, 1); /* whether the frame is compressed */ if (hassize) { /* now read the number of samples, * as a 32bit integer */ outputsamples = readbits(alac, 32); *outputsize = outputsamples * alac->bytespersample; } readsamplesize = alac->setinfo_sample_size - (uncompressed_bytes * 8) + 1; if (!isnotcompressed) { /* compressed */ int16_t predictor_coef_table_a[32]; int predictor_coef_num_a; int prediction_type_a; int prediction_quantitization_a; int ricemodifier_a; int16_t predictor_coef_table_b[32]; int predictor_coef_num_b; int prediction_type_b; int prediction_quantitization_b; int ricemodifier_b; int i; interlacing_shift = readbits(alac, 8); interlacing_leftweight = readbits(alac, 8); /******** channel 1 ***********/ prediction_type_a = readbits(alac, 4); prediction_quantitization_a = readbits(alac, 4); ricemodifier_a = readbits(alac, 3); predictor_coef_num_a = readbits(alac, 5); /* read the predictor table */ for (i = 0; i < predictor_coef_num_a; i++) { predictor_coef_table_a[i] = (int16_t)readbits(alac, 16); } /******** channel 2 *********/ prediction_type_b = readbits(alac, 4); prediction_quantitization_b = readbits(alac, 4); ricemodifier_b = readbits(alac, 3); predictor_coef_num_b = readbits(alac, 5); /* read the predictor table */ for (i = 0; i < predictor_coef_num_b; i++) { predictor_coef_table_b[i] = (int16_t)readbits(alac, 16); } /*********************/ if (uncompressed_bytes) { /* see mono case */ int i; for (i = 0; i < outputsamples; i++) { alac->uncompressed_bytes_buffer_a[i] = readbits(alac, uncompressed_bytes * 8); alac->uncompressed_bytes_buffer_b[i] = readbits(alac, uncompressed_bytes * 8); } } /* channel 1 */ entropy_rice_decode(alac, alac->predicterror_buffer_a, outputsamples, readsamplesize, alac->setinfo_rice_initialhistory, alac->setinfo_rice_kmodifier, ricemodifier_a * alac->setinfo_rice_historymult / 4, (1 << alac->setinfo_rice_kmodifier) - 1); if (prediction_type_a == 0) { /* adaptive fir */ predictor_decompress_fir_adapt(alac->predicterror_buffer_a, alac->outputsamples_buffer_a, outputsamples, readsamplesize, predictor_coef_table_a, predictor_coef_num_a, prediction_quantitization_a); } else { /* see mono case */ fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_a); } /* channel 2 */ entropy_rice_decode(alac, alac->predicterror_buffer_b, outputsamples, readsamplesize, alac->setinfo_rice_initialhistory, alac->setinfo_rice_kmodifier, ricemodifier_b * alac->setinfo_rice_historymult / 4, (1 << alac->setinfo_rice_kmodifier) - 1); if (prediction_type_b == 0) { /* adaptive fir */ predictor_decompress_fir_adapt(alac->predicterror_buffer_b, alac->outputsamples_buffer_b, outputsamples, readsamplesize, predictor_coef_table_b, predictor_coef_num_b, prediction_quantitization_b); } else { fprintf(stderr, "FIXME: unhandled predicition type: %i\n", prediction_type_b); } } else { /* not compressed, easy case */ if (alac->setinfo_sample_size <= 16) { int i; for (i = 0; i < outputsamples; i++) { int32_t audiobits_a, audiobits_b; audiobits_a = readbits(alac, alac->setinfo_sample_size); audiobits_b = readbits(alac, alac->setinfo_sample_size); audiobits_a = SIGN_EXTENDED32(audiobits_a, alac->setinfo_sample_size); audiobits_b = SIGN_EXTENDED32(audiobits_b, alac->setinfo_sample_size); alac->outputsamples_buffer_a[i] = audiobits_a; alac->outputsamples_buffer_b[i] = audiobits_b; } } else { int i; for (i = 0; i < outputsamples; i++) { int32_t audiobits_a, audiobits_b; audiobits_a = readbits(alac, 16); audiobits_a = audiobits_a << (alac->setinfo_sample_size - 16); audiobits_a |= readbits(alac, alac->setinfo_sample_size - 16); audiobits_a = SignExtend24(audiobits_a); audiobits_b = readbits(alac, 16); audiobits_b = audiobits_b << (alac->setinfo_sample_size - 16); audiobits_b |= readbits(alac, alac->setinfo_sample_size - 16); audiobits_b = SignExtend24(audiobits_b); alac->outputsamples_buffer_a[i] = audiobits_a; alac->outputsamples_buffer_b[i] = audiobits_b; } } uncompressed_bytes = 0; // always 0 for uncompressed interlacing_shift = 0; interlacing_leftweight = 0; } switch(alac->setinfo_sample_size) { case 16: { deinterlace_16(alac->outputsamples_buffer_a, alac->outputsamples_buffer_b, (int16_t*)outbuffer, alac->numchannels, outputsamples, interlacing_shift, interlacing_leftweight); break; } case 24: { deinterlace_24(alac->outputsamples_buffer_a, alac->outputsamples_buffer_b, uncompressed_bytes, alac->uncompressed_bytes_buffer_a, alac->uncompressed_bytes_buffer_b, (int16_t*)outbuffer, alac->numchannels, outputsamples, interlacing_shift, interlacing_leftweight); break; } case 20: case 32: fprintf(stderr, "FIXME: unimplemented sample size %i\n", alac->setinfo_sample_size); break; default: break; } break; } } } alac_file *create_alac(int samplesize, int numchannels) { alac_file *newfile = malloc(sizeof(alac_file)); newfile->samplesize = samplesize; newfile->numchannels = numchannels; newfile->bytespersample = (samplesize / 8) * numchannels; return newfile; } alac_decoder/alac.xcodeproj/0000755000076500007650000000000011251345442016262 5ustar crazneycrazneyalac_decoder/alac.xcodeproj/project.pbxproj0000644000076500007650000002011411251345442021334 0ustar crazneycrazney// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 45; objects = { /* Begin PBXBuildFile section */ 7230FB301007508400AD35CD /* stream.c in Sources */ = {isa = PBXBuildFile; fileRef = 7230FB291007508400AD35CD /* stream.c */; }; 7230FB311007508400AD35CD /* wavwriter.c in Sources */ = {isa = PBXBuildFile; fileRef = 7230FB2B1007508400AD35CD /* wavwriter.c */; }; 7230FB321007508400AD35CD /* demux.c in Sources */ = {isa = PBXBuildFile; fileRef = 7230FB2D1007508400AD35CD /* demux.c */; }; 7230FB331007508400AD35CD /* alac.c in Sources */ = {isa = PBXBuildFile; fileRef = 7230FB2E1007508400AD35CD /* alac.c */; }; 8DD76FAC0486AB0100D96B5E /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* main.c */; settings = {ATTRIBUTES = (); }; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ 8DD76FAF0486AB0100D96B5E /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 8; dstPath = /usr/share/man/man1/; dstSubfolderSpec = 0; files = ( ); runOnlyForDeploymentPostprocessing = 1; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ 08FB7796FE84155DC02AAC07 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 7230FB281007508400AD35CD /* wavwriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = wavwriter.h; sourceTree = ""; }; 7230FB291007508400AD35CD /* stream.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = stream.c; sourceTree = ""; }; 7230FB2A1007508400AD35CD /* stream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = stream.h; sourceTree = ""; }; 7230FB2B1007508400AD35CD /* wavwriter.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = wavwriter.c; sourceTree = ""; }; 7230FB2C1007508400AD35CD /* demux.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = demux.h; sourceTree = ""; }; 7230FB2D1007508400AD35CD /* demux.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = demux.c; sourceTree = ""; }; 7230FB2E1007508400AD35CD /* alac.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = alac.c; sourceTree = ""; }; 7230FB2F1007508400AD35CD /* decomp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = decomp.h; sourceTree = ""; }; 7230FB501007527B00AD35CD /* alac */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = alac; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 8DD76FAD0486AB0100D96B5E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 08FB7794FE84155DC02AAC07 /* alac */ = { isa = PBXGroup; children = ( 08FB7795FE84155DC02AAC07 /* Source */, C6A0FF2B0290797F04C91782 /* Documentation */, 1AB674ADFE9D54B511CA2CBB /* Products */, ); name = alac; sourceTree = ""; }; 08FB7795FE84155DC02AAC07 /* Source */ = { isa = PBXGroup; children = ( 7230FB281007508400AD35CD /* wavwriter.h */, 7230FB291007508400AD35CD /* stream.c */, 7230FB2A1007508400AD35CD /* stream.h */, 7230FB2B1007508400AD35CD /* wavwriter.c */, 7230FB2C1007508400AD35CD /* demux.h */, 7230FB2D1007508400AD35CD /* demux.c */, 7230FB2E1007508400AD35CD /* alac.c */, 7230FB2F1007508400AD35CD /* decomp.h */, 08FB7796FE84155DC02AAC07 /* main.c */, ); name = Source; sourceTree = ""; }; 1AB674ADFE9D54B511CA2CBB /* Products */ = { isa = PBXGroup; children = ( 7230FB501007527B00AD35CD /* alac */, ); name = Products; sourceTree = ""; }; C6A0FF2B0290797F04C91782 /* Documentation */ = { isa = PBXGroup; children = ( ); name = Documentation; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 8DD76FA90486AB0100D96B5E /* alac */ = { isa = PBXNativeTarget; buildConfigurationList = 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "alac" */; buildPhases = ( 8DD76FAB0486AB0100D96B5E /* Sources */, 8DD76FAD0486AB0100D96B5E /* Frameworks */, 8DD76FAF0486AB0100D96B5E /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = alac; productInstallPath = "$(HOME)/bin"; productName = alac; productReference = 7230FB501007527B00AD35CD /* alac */; productType = "com.apple.product-type.tool"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 08FB7793FE84155DC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "alac" */; compatibilityVersion = "Xcode 3.1"; hasScannedForEncodings = 1; mainGroup = 08FB7794FE84155DC02AAC07 /* alac */; projectDirPath = ""; projectRoot = ""; targets = ( 8DD76FA90486AB0100D96B5E /* alac */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ 8DD76FAB0486AB0100D96B5E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 8DD76FAC0486AB0100D96B5E /* main.c in Sources */, 7230FB301007508400AD35CD /* stream.c in Sources */, 7230FB311007508400AD35CD /* wavwriter.c in Sources */, 7230FB321007508400AD35CD /* demux.c in Sources */, 7230FB331007508400AD35CD /* alac.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ 1DEB928608733DD80010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = alac; }; name = Debug; }; 1DEB928708733DD80010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_MODEL_TUNING = G5; INSTALL_PATH = /usr/local/bin; PRODUCT_NAME = alac; }; name = Release; }; 1DEB928A08733DD80010E9CD /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_OPTIMIZATION_LEVEL = 0; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PREBINDING = NO; SDKROOT = macosx10.5; }; name = Debug; }; 1DEB928B08733DD80010E9CD /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_BIT)"; GCC_C_LANGUAGE_STANDARD = c99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; SDKROOT = macosx10.5; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 1DEB928508733DD80010E9CD /* Build configuration list for PBXNativeTarget "alac" */ = { isa = XCConfigurationList; buildConfigurations = ( 1DEB928608733DD80010E9CD /* Debug */, 1DEB928708733DD80010E9CD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 1DEB928908733DD80010E9CD /* Build configuration list for PBXProject "alac" */ = { isa = XCConfigurationList; buildConfigurations = ( 1DEB928A08733DD80010E9CD /* Debug */, 1DEB928B08733DD80010E9CD /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; } alac_decoder/alac_decoder.sln0000644000076500007650000000157111251345442016475 0ustar crazneycrazney Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "alac_decoder", "alac_decoder.vcproj", "{CC45D55D-11C8-401A-BAF0-00ABF23597C8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {CC45D55D-11C8-401A-BAF0-00ABF23597C8}.Debug|Win32.ActiveCfg = Debug|Win32 {CC45D55D-11C8-401A-BAF0-00ABF23597C8}.Debug|Win32.Build.0 = Debug|Win32 {CC45D55D-11C8-401A-BAF0-00ABF23597C8}.Release|Win32.ActiveCfg = Release|Win32 {CC45D55D-11C8-401A-BAF0-00ABF23597C8}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal alac_decoder/alac_decoder.vcproj0000644000076500007650000001061611251345442017204 0ustar crazneycrazney alac_decoder/decomp.h0000644000076500007650000000055411251345442015012 0ustar crazneycrazney#ifndef __ALAC__DECOMP_H #define __ALAC__DECOMP_H typedef struct alac_file alac_file; alac_file *create_alac(int samplesize, int numchannels); void decode_frame(alac_file *alac, unsigned char *inbuffer, void *outbuffer, int *outputsize); void alac_set_info(alac_file *alac, char *inputbuffer); #endif /* __ALAC__DECOMP_H */ alac_decoder/demux.c0000644000076500007650000005076411251345442014670 0ustar crazneycrazney/* * ALAC (Apple Lossless Audio Codec) decoder * Copyright (c) 2005 David Hammerton * All rights reserved. * * This is the quicktime container demuxer. * * http://crazney.net/programs/itunes/alac.html * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #ifdef _WIN32 #include "stdint_win.h" #else #include #endif #include "stream.h" #include "demux.h" typedef struct { stream_t *stream; demux_res_t *res; long saved_mdat_pos; } qtmovie_t; /* chunk handlers */ static void read_chunk_ftyp(qtmovie_t *qtmovie, size_t chunk_len) { fourcc_t type; uint32_t minor_ver; size_t size_remaining = chunk_len - 8; /* FIXME: can't hardcode 8, size may be 64bit */ type = stream_read_uint32(qtmovie->stream); size_remaining-=4; if (type != MAKEFOURCC('M','4','A',' ')) { fprintf(stderr, "not M4A file\n"); return; } minor_ver = stream_read_uint32(qtmovie->stream); size_remaining-=4; /* compatible brands */ while (size_remaining) { /* unused */ /*fourcc_t cbrand =*/ stream_read_uint32(qtmovie->stream); size_remaining-=4; } } static void read_chunk_tkhd(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ stream_skip(qtmovie->stream, size_remaining); } static void read_chunk_mdhd(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ stream_skip(qtmovie->stream, size_remaining); } static void read_chunk_edts(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ stream_skip(qtmovie->stream, size_remaining); } static void read_chunk_elst(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ stream_skip(qtmovie->stream, size_remaining); } /* media handler inside mdia */ static void read_chunk_hdlr(qtmovie_t *qtmovie, size_t chunk_len) { fourcc_t comptype, compsubtype; size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ int strlen; char str[256] = {0}; /* version */ stream_read_uint8(qtmovie->stream); size_remaining -= 1; /* flags */ stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); size_remaining -= 3; /* component type */ comptype = stream_read_uint32(qtmovie->stream); compsubtype = stream_read_uint32(qtmovie->stream); size_remaining -= 8; /* component manufacturer */ stream_read_uint32(qtmovie->stream); size_remaining -= 4; /* flags */ stream_read_uint32(qtmovie->stream); stream_read_uint32(qtmovie->stream); size_remaining -= 8; /* name */ strlen = stream_read_uint8(qtmovie->stream); stream_read(qtmovie->stream, strlen, str); size_remaining -= 1 + strlen; if (size_remaining) { stream_skip(qtmovie->stream, size_remaining); } } static int read_chunk_stsd(qtmovie_t *qtmovie, size_t chunk_len) { unsigned int i; uint32_t numentries; size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ /* version */ stream_read_uint8(qtmovie->stream); size_remaining -= 1; /* flags */ stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); size_remaining -= 3; numentries = stream_read_uint32(qtmovie->stream); size_remaining -= 4; if (numentries != 1) { fprintf(stderr, "only expecting one entry in sample description atom!\n"); return 0; } for (i = 0; i < numentries; i++) { uint32_t entry_size; uint16_t version; uint32_t entry_remaining; entry_size = stream_read_uint32(qtmovie->stream); qtmovie->res->format = stream_read_uint32(qtmovie->stream); entry_remaining = entry_size; entry_remaining -= 8; /* sound info: */ stream_skip(qtmovie->stream, 6); /* reserved */ entry_remaining -= 6; version = stream_read_uint16(qtmovie->stream); if (version != 1) fprintf(stderr, "unknown version??\n"); entry_remaining -= 2; /* revision level */ stream_read_uint16(qtmovie->stream); /* vendor */ stream_read_uint32(qtmovie->stream); entry_remaining -= 6; /* EH?? spec doesn't say theres an extra 16 bits here.. but there is! */ stream_read_uint16(qtmovie->stream); entry_remaining -= 2; qtmovie->res->num_channels = stream_read_uint16(qtmovie->stream); qtmovie->res->sample_size = stream_read_uint16(qtmovie->stream); entry_remaining -= 4; /* compression id */ stream_read_uint16(qtmovie->stream); /* packet size */ stream_read_uint16(qtmovie->stream); entry_remaining -= 4; /* sample rate - 32bit fixed point = 16bit?? */ qtmovie->res->sample_rate = stream_read_uint16(qtmovie->stream); entry_remaining -= 2; /* skip 2 */ stream_skip(qtmovie->stream, 2); entry_remaining -= 2; /* remaining is codec data */ #if 0 qtmovie->res->codecdata_len = stream_read_uint32(qtmovie->stream); if (qtmovie->res->codecdata_len != entry_remaining) fprintf(stderr, "perhaps not? %i vs %i\n", qtmovie->res->codecdata_len, entry_remaining); entry_remaining -= 4; stream_read_uint32(qtmovie->stream); /* 'alac' */ entry_remaining -= 4; qtmovie->res->codecdata = malloc(qtmovie->res->codecdata_len - 8); stream_read(qtmovie->stream, entry_remaining, qtmovie->res->codecdata); entry_remaining = 0; #else /* 12 = audio format atom, 8 = padding */ qtmovie->res->codecdata_len = entry_remaining + 12 + 8; qtmovie->res->codecdata = malloc(qtmovie->res->codecdata_len); memset(qtmovie->res->codecdata, 0, qtmovie->res->codecdata_len); /* audio format atom */ ((unsigned int*)qtmovie->res->codecdata)[0] = 0x0c000000; ((unsigned int*)qtmovie->res->codecdata)[1] = MAKEFOURCC('a','m','r','f'); ((unsigned int*)qtmovie->res->codecdata)[2] = MAKEFOURCC('c','a','l','a'); stream_read(qtmovie->stream, entry_remaining, ((char*)qtmovie->res->codecdata) + 12); entry_remaining -= entry_remaining; #endif if (entry_remaining) stream_skip(qtmovie->stream, entry_remaining); qtmovie->res->format_read = 1; if (qtmovie->res->format != MAKEFOURCC('a','l','a','c')) { /*fprintf(stderr, "expecting 'alac' data format, got %c%c%c%c\n", SPLITFOURCC(qtmovie->res->format));*/ return 0; } } return 1; } static void read_chunk_stts(qtmovie_t *qtmovie, size_t chunk_len) { unsigned int i; uint32_t numentries; size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ /* version */ stream_read_uint8(qtmovie->stream); size_remaining -= 1; /* flags */ stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); size_remaining -= 3; numentries = stream_read_uint32(qtmovie->stream); size_remaining -= 4; qtmovie->res->num_time_to_samples = numentries; qtmovie->res->time_to_sample = malloc(numentries * sizeof(*qtmovie->res->time_to_sample)); for (i = 0; i < numentries; i++) { qtmovie->res->time_to_sample[i].sample_count = stream_read_uint32(qtmovie->stream); qtmovie->res->time_to_sample[i].sample_duration = stream_read_uint32(qtmovie->stream); size_remaining -= 8; } if (size_remaining) { fprintf(stderr, "ehm, size remianing?\n"); stream_skip(qtmovie->stream, size_remaining); } } static void read_chunk_stsz(qtmovie_t *qtmovie, size_t chunk_len) { unsigned int i; uint32_t numentries; size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ /* version */ stream_read_uint8(qtmovie->stream); size_remaining -= 1; /* flags */ stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); stream_read_uint8(qtmovie->stream); size_remaining -= 3; /* default sample size */ if (stream_read_uint32(qtmovie->stream) != 0) { fprintf(stderr, "i was expecting variable samples sizes\n"); stream_read_uint32(qtmovie->stream); size_remaining -= 4; return; } size_remaining -= 4; numentries = stream_read_uint32(qtmovie->stream); size_remaining -= 4; qtmovie->res->num_sample_byte_sizes = numentries; qtmovie->res->sample_byte_size = malloc(numentries * sizeof(*qtmovie->res->sample_byte_size)); for (i = 0; i < numentries; i++) { qtmovie->res->sample_byte_size[i] = stream_read_uint32(qtmovie->stream); size_remaining -= 4; } if (size_remaining) { fprintf(stderr, "ehm, size remianing?\n"); stream_skip(qtmovie->stream, size_remaining); } } static int read_chunk_stbl(qtmovie_t *qtmovie, size_t chunk_len) { size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ while (size_remaining) { size_t sub_chunk_len; fourcc_t sub_chunk_id; sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { fprintf(stderr, "strange size for chunk inside stbl (%lu) (remaining: %lu)\n", sub_chunk_len, size_remaining); return 0; } sub_chunk_id = stream_read_uint32(qtmovie->stream); switch (sub_chunk_id) { case MAKEFOURCC('s','t','s','d'): if (read_chunk_stsd(qtmovie, sub_chunk_len) == 0) return 0; break; case MAKEFOURCC('s','t','t','s'): read_chunk_stts(qtmovie, sub_chunk_len); break; case MAKEFOURCC('s','t','s','z'): read_chunk_stsz(qtmovie, sub_chunk_len); break; case MAKEFOURCC('s','t','s','c'): case MAKEFOURCC('s','t','c','o'): /* skip these, no indexing for us! */ stream_skip(qtmovie->stream, sub_chunk_len - 8); break; default: fprintf(stderr, "(stbl) unknown chunk id: %c%c%c%c\n", SPLITFOURCC(sub_chunk_id)); return 0; } size_remaining -= sub_chunk_len; } return 1; } static int read_chunk_minf(qtmovie_t *qtmovie, size_t chunk_len) { size_t dinf_size, stbl_size; size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ /**** SOUND HEADER CHUNK ****/ if (stream_read_uint32(qtmovie->stream) != 16) { fprintf(stderr, "unexpected size in media info\n"); return 0; } if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('s','m','h','d')) { fprintf(stderr, "not a sound header! can't handle this.\n"); return 0; } /* now skip the rest */ stream_skip(qtmovie->stream, 16 - 8); size_remaining -= 16; /****/ /**** DINF CHUNK ****/ dinf_size = stream_read_uint32(qtmovie->stream); if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('d','i','n','f')) { fprintf(stderr, "expected dinf, didn't get it.\n"); return 0; } /* skip it */ stream_skip(qtmovie->stream, dinf_size - 8); size_remaining -= dinf_size; /****/ /**** SAMPLE TABLE ****/ stbl_size = stream_read_uint32(qtmovie->stream); if (stream_read_uint32(qtmovie->stream) != MAKEFOURCC('s','t','b','l')) { fprintf(stderr, "expected stbl, didn't get it.\n"); return 0; } if (read_chunk_stbl(qtmovie, stbl_size) == 0) return 0; size_remaining -= stbl_size; if (size_remaining) { fprintf(stderr, "oops\n"); stream_skip(qtmovie->stream, size_remaining); } return 1; } static int read_chunk_mdia(qtmovie_t *qtmovie, size_t chunk_len) { size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ while (size_remaining) { size_t sub_chunk_len; fourcc_t sub_chunk_id; sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { fprintf(stderr, "strange size for chunk inside mdia\n"); return 0; } sub_chunk_id = stream_read_uint32(qtmovie->stream); switch (sub_chunk_id) { case MAKEFOURCC('m','d','h','d'): read_chunk_mdhd(qtmovie, sub_chunk_len); break; case MAKEFOURCC('h','d','l','r'): read_chunk_hdlr(qtmovie, sub_chunk_len); break; case MAKEFOURCC('m','i','n','f'): if (read_chunk_minf(qtmovie, sub_chunk_len) == 0) return 0; break; default: fprintf(stderr, "(mdia) unknown chunk id: %c%c%c%c\n", SPLITFOURCC(sub_chunk_id)); return 0; } size_remaining -= sub_chunk_len; } return 1; } /* 'trak' - a movie track - contains other atoms */ static int read_chunk_trak(qtmovie_t *qtmovie, size_t chunk_len) { size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ while (size_remaining) { size_t sub_chunk_len; fourcc_t sub_chunk_id; sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { fprintf(stderr, "strange size for chunk inside trak\n"); return 0; } sub_chunk_id = stream_read_uint32(qtmovie->stream); switch (sub_chunk_id) { case MAKEFOURCC('t','k','h','d'): read_chunk_tkhd(qtmovie, sub_chunk_len); break; case MAKEFOURCC('m','d','i','a'): if (read_chunk_mdia(qtmovie, sub_chunk_len) == 0) return 0; break; case MAKEFOURCC('e','d','t','s'): read_chunk_edts(qtmovie, sub_chunk_len); break; default: fprintf(stderr, "(trak) unknown chunk id: %c%c%c%c\n", SPLITFOURCC(sub_chunk_id)); return 0; } size_remaining -= sub_chunk_len; } return 1; } /* 'mvhd' movie header atom */ static void read_chunk_mvhd(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ stream_skip(qtmovie->stream, size_remaining); } /* 'udta' user data.. contains tag info */ static void read_chunk_udta(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ stream_skip(qtmovie->stream, size_remaining); } /* 'iods' */ static void read_chunk_iods(qtmovie_t *qtmovie, size_t chunk_len) { /* don't need anything from here atm, skip */ size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ stream_skip(qtmovie->stream, size_remaining); } /* 'moov' movie atom - contains other atoms */ static int read_chunk_moov(qtmovie_t *qtmovie, size_t chunk_len) { size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ while (size_remaining) { size_t sub_chunk_len; fourcc_t sub_chunk_id; sub_chunk_len = stream_read_uint32(qtmovie->stream); if (sub_chunk_len <= 1 || sub_chunk_len > size_remaining) { fprintf(stderr, "strange size for chunk inside moov\n"); return 0; } sub_chunk_id = stream_read_uint32(qtmovie->stream); switch (sub_chunk_id) { case MAKEFOURCC('m','v','h','d'): read_chunk_mvhd(qtmovie, sub_chunk_len); break; case MAKEFOURCC('t','r','a','k'): if (read_chunk_trak(qtmovie, sub_chunk_len) == 0) return 0; break; case MAKEFOURCC('u','d','t','a'): read_chunk_udta(qtmovie, sub_chunk_len); break; case MAKEFOURCC('e','l','s','t'): read_chunk_elst(qtmovie, sub_chunk_len); break; case MAKEFOURCC('i','o','d','s'): read_chunk_iods(qtmovie, sub_chunk_len); break; default: fprintf(stderr, "(moov) unknown chunk id: %c%c%c%c\n", SPLITFOURCC(sub_chunk_id)); return 0; } size_remaining -= sub_chunk_len; } return 1; } static void read_chunk_mdat(qtmovie_t *qtmovie, size_t chunk_len, int skip_mdat) { size_t size_remaining = chunk_len - 8; /* FIXME WRONG */ if (size_remaining == 0) return; qtmovie->res->mdat_len = (uint32_t)size_remaining; if (skip_mdat) { qtmovie->saved_mdat_pos = stream_tell(qtmovie->stream); stream_skip(qtmovie->stream, size_remaining); } #if 0 qtmovie->res->mdat = malloc(size_remaining); stream_read(qtmovie->stream, size_remaining, qtmovie->res->mdat); #endif } static int set_saved_mdat(qtmovie_t *qtmovie) { if (qtmovie->saved_mdat_pos == -1) { fprintf(stderr, "stream contains mdat before moov but is not seekable\n"); return 0; } if (stream_setpos(qtmovie->stream, qtmovie->saved_mdat_pos)) { fprintf(stderr, "error while seeking stream to mdat pos\n"); return 0; } return 1; } int qtmovie_read(stream_t *file, demux_res_t *demux_res) { int found_moov = 0; int found_mdat = 0; qtmovie_t *qtmovie; qtmovie = (qtmovie_t*)malloc(sizeof(qtmovie_t)); /* construct the stream */ qtmovie->stream = file; qtmovie->res = demux_res; memset(demux_res, 0, sizeof(demux_res_t)); /* read the chunks */ while (1) { size_t chunk_len; fourcc_t chunk_id; chunk_len = stream_read_uint32(qtmovie->stream); if (stream_eof(qtmovie->stream)) { return 0; } if (chunk_len == 1) { fprintf(stderr, "need 64bit support\n"); return 0; } chunk_id = stream_read_uint32(qtmovie->stream); switch (chunk_id) { case MAKEFOURCC('f','t','y','p'): read_chunk_ftyp(qtmovie, chunk_len); break; case MAKEFOURCC('m','o','o','v'): if (read_chunk_moov(qtmovie, chunk_len) == 0) return 0; /* failed to read moov, can't do anything */ if (found_mdat) { return set_saved_mdat(qtmovie); } found_moov = 1; break; /* if we hit mdat before we've found moov, record the position * and move on. We can then come back to mdat later. * This presumes the stream supports seeking backwards. */ case MAKEFOURCC('m','d','a','t'): read_chunk_mdat(qtmovie, chunk_len, !found_moov); if (found_moov) return 1; found_mdat = 1; break; /* these following atoms can be skipped !!!! */ case MAKEFOURCC('f','r','e','e'): stream_skip(qtmovie->stream, chunk_len - 8); /* FIXME not 8 */ break; default: fprintf(stderr, "(top) unknown chunk id: %c%c%c%c\n", SPLITFOURCC(chunk_id)); return 0; } } return 0; } alac_decoder/demux.h0000644000076500007650000000222011251345442014655 0ustar crazneycrazney#ifndef DEMUX_H #define DEMUX_H #ifdef _WIN32 #include "stdint_win.h" #else #include #endif #include "stream.h" typedef uint32_t fourcc_t; typedef struct { int format_read; uint16_t num_channels; uint16_t sample_size; uint32_t sample_rate; fourcc_t format; void *buf; struct { uint32_t sample_count; uint32_t sample_duration; } *time_to_sample; uint32_t num_time_to_samples; uint32_t *sample_byte_size; uint32_t num_sample_byte_sizes; uint32_t codecdata_len; void *codecdata; uint32_t mdat_len; #if 0 void *mdat; #endif } demux_res_t; int qtmovie_read(stream_t *stream, demux_res_t *demux_res); #ifndef MAKEFOURCC #define MAKEFOURCC(ch0, ch1, ch2, ch3) ( \ ( (int32_t)(char)(ch0) << 24 ) | \ ( (int32_t)(char)(ch1) << 16 ) | \ ( (int32_t)(char)(ch2) << 8 ) | \ ( (int32_t)(char)(ch3) ) ) #endif #ifndef SLPITFOURCC /* splits it into ch0, ch1, ch2, ch3 - use for printf's */ #define SPLITFOURCC(code) \ (char)((int32_t)code >> 24), \ (char)((int32_t)code >> 16), \ (char)((int32_t)code >> 8), \ (char)code #endif #endif /* DEMUX_H */ alac_decoder/main.c0000644000076500007650000002565511251345442014473 0ustar crazneycrazney/* * ALAC (Apple Lossless Audio Codec) decoder * Copyright (c) 2005 David Hammerton * All rights reserved. * * This is simply the glue for everything. It asks the demuxer to * parse the quicktime container, asks the decoder to decode * the data and writes output as either RAW PCM or WAV. * * http://crazney.net/programs/itunes/alac.html * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #include #include #ifdef _WIN32 #include "stdint_win.h" #else #include #endif #include "demux.h" #include "decomp.h" #include "stream.h" #include "wavwriter.h" int host_bigendian = 0; alac_file *alac = NULL; static FILE *input_file = NULL; static int input_opened = 0; static stream_t *input_stream; static FILE *output_file = NULL; static int output_opened = 0; static int write_wav_format = 1; static int verbose = 0; static int test_file_type = 0; static int get_sample_info(demux_res_t *demux_res, uint32_t samplenum, uint32_t *sample_duration, uint32_t *sample_byte_size) { unsigned int duration_index_accum = 0; unsigned int duration_cur_index = 0; if (samplenum >= demux_res->num_sample_byte_sizes) { fprintf(stderr, "sample %i does not exist\n", samplenum); return 0; } if (!demux_res->num_time_to_samples) { fprintf(stderr, "no time to samples\n"); return 0; } while ((demux_res->time_to_sample[duration_cur_index].sample_count + duration_index_accum) <= samplenum) { duration_index_accum += demux_res->time_to_sample[duration_cur_index].sample_count; duration_cur_index++; if (duration_cur_index >= demux_res->num_time_to_samples) { fprintf(stderr, "sample %i does not have a duration\n", samplenum); return 0; } } *sample_duration = demux_res->time_to_sample[duration_cur_index].sample_duration; *sample_byte_size = demux_res->sample_byte_size[samplenum]; return 1; } static void GetBuffer(demux_res_t *demux_res) { unsigned long destBufferSize = 1024*24; /* 24kb buffer = 4096 frames = 1 alac sample (we support max 24bps) */ void *pDestBuffer = malloc(destBufferSize); int bytes_read = 0; unsigned int buffer_size = 1024*80; /* sample big enough to hold any input for a single alac frame */ void *buffer; unsigned int i; buffer = malloc(buffer_size); for (i = 0; i < demux_res->num_sample_byte_sizes; i++) { uint32_t sample_duration; uint32_t sample_byte_size; int outputBytes; /* just get one sample for now */ if (!get_sample_info(demux_res, i, &sample_duration, &sample_byte_size)) { fprintf(stderr, "sample failed\n"); return; } if (buffer_size < sample_byte_size) { fprintf(stderr, "sorry buffer too small! (is %i want %i)\n", buffer_size, sample_byte_size); return; } stream_read(input_stream, sample_byte_size, buffer); /* now fetch */ outputBytes = destBufferSize; decode_frame(alac, buffer, pDestBuffer, &outputBytes); /* write */ bytes_read += outputBytes; if (verbose) fprintf(stderr, "read %i bytes. total: %i\n", outputBytes, bytes_read); fwrite(pDestBuffer, outputBytes, 1, output_file); } if (verbose) fprintf(stderr, "done reading, read %i frames\n", i); } static void init_sound_converter(demux_res_t *demux_res) { alac = create_alac(demux_res->sample_size, demux_res->num_channels); alac_set_info(alac, demux_res->codecdata); } static void usage() { fprintf(stderr, "Usage: alac [options] [--] file\n" "Decompresses the ALAC file specified\n" "\n" "Options:\n" " -f output.wav outputs the decompressed data to the\n" " specified file, in WAV format. Default\n" " is stdout.\n" " -r write output as raw PCM data. Default\n" " is in WAV format.\n" " -v verbose output.\n" " -t test that file is ALAC, also tests for\n" " other m4a file types.\n" "\n" "This software is Copyright (c) 2005 David Hammerton\n" "All rights reserved\n" "http://crazney.net/\n"); exit(1); } static void setup_environment(int argc, char **argv) { int i = argc; char *input_file_n = NULL; char *output_file_n = NULL; int escaped = 0; if (argc < 2) usage(); for (i = argc-1; i > 1; i--) { if (strcmp(argv[argc-i], "-f") == 0) /* output file */ { if (!--i) usage(); output_file_n = argv[argc-i]; } else if (strcmp(argv[argc-i], "-r") == 0) /* raw PCM output */ { write_wav_format = 0; } else if (strcmp(argv[argc-i], "-v") == 0) /* verbose */ { verbose = 1; } else if (strcmp(argv[argc-i], "-t") == 0) /* test file type */ { test_file_type = 1; } else if (strcmp(argv[argc-i], "--") == 0) /* filename can begin with - */ { /* must be 2nd last arg */ if (i != 2) usage(); escaped = 1; } else usage(); } if (i != 1) usage(); input_file_n = argv[argc-1]; /* if the final parameter begins with '-', and isn't just "-", * it's probably an unsupported argument, print usage and exit. * (Unless it's been escaped with --) */ if (!escaped && input_file_n[0] == '-' && input_file_n[1] != 0) usage(); if (!input_file_n) usage(); if (output_file_n) { output_file = fopen(output_file_n, "wb"); if (!output_file) { fprintf(stderr, "failed to open output file '%s': ", output_file_n); perror(NULL); exit(1); } output_opened = 1; } else { /* defaults to stdout */ output_file = stdout; } if (strcmp(input_file_n, "-") == 0) { input_file = stdin; } else { input_file = fopen(input_file_n, "rb"); if (!input_file) { fprintf(stderr, "failed to open input file '%s': ", input_file_n); perror(NULL); exit(1); } input_opened = 1; } } /* this could quite easily be done at compile time, * however I don't want to have to bother with all the * various possible #define's for endianness, worrying about * different compilers etc. and I'm too lazy to use autoconf. */ void set_endian() { uint32_t integer = 0x000000aa; unsigned char *p = (unsigned char*)&integer; if (p[0] == 0xaa) host_bigendian = 0; else host_bigendian = 1; } int main(int argc, char **argv) { demux_res_t demux_res; unsigned int output_size, i; memset(&demux_res, 0, sizeof(demux_res)); set_endian(); setup_environment(argc, argv); /*#ifdef _WIN32 setmode(fileno(stdout), O_BINARY); setmode(fileno(stdin), O_BINARY); #endif*/ input_stream = stream_create_file(input_file, 1); if (!input_stream) { fprintf(stderr, "failed to create input stream from file\n"); return 1; } /* if qtmovie_read returns successfully, the stream is up to * the movie data, which can be used directly by the decoder */ if (!qtmovie_read(input_stream, &demux_res)) { if (!test_file_type || !demux_res.format_read) { fprintf(stderr, "failed to load the QuickTime movie headers"); if (demux_res.format_read) fprintf(stderr, " (file type: %c%c%c%c)\n", SPLITFOURCC(demux_res.format)); else fprintf(stderr, "\n"); return 1; } } if (test_file_type) { /* just in case: */ if (!demux_res.format_read) { fprintf(stderr, "failed to load the QUickTime movie headers." " Probably not a quicktime file\n"); return 1; } printf("file type: %c%c%c%c\n", SPLITFOURCC(demux_res.format)); /* now, we have to return useful return codes */ switch (demux_res.format) { case MAKEFOURCC('a','l','a','c'): return 0; /* alac = 0 */ case MAKEFOURCC('m','p','4','a'): return 100; /* m4pa = unencrypted aac = 100 */ } return 1; } /* initialise the sound converter */ init_sound_converter(&demux_res); /* write wav output headers */ if (write_wav_format) { /* calculate output size */ output_size = 0; for (i = 0; i < demux_res.num_sample_byte_sizes; i++) { unsigned int thissample_duration = 0; unsigned int thissample_bytesize = 0; get_sample_info(&demux_res, i, &thissample_duration, &thissample_bytesize); output_size += thissample_duration * (demux_res.sample_size / 8) * demux_res.num_channels; } wavwriter_writeheaders(output_file, output_size, demux_res.num_channels, demux_res.sample_rate, demux_res.sample_size); } /* will convert the entire buffer */ GetBuffer(&demux_res); stream_destroy(input_stream); if (output_opened) fclose(output_file); if (input_opened) fclose(input_file); return 0; } alac_decoder/Makefile0000644000076500007650000000044411251345442015030 0ustar crazneycrazneyCC=gcc RM=rm -f CFLAGS=-ggdb -O3 -W -Wall C_SOURCES=alac.c \ demux.c \ main.c \ stream.c \ wavwriter.c OBJECTS=$(C_SOURCES:.c=.o) alac: $(OBJECTS) $(CC) -o alac $(OBJECTS) %.o: %.c $(CC) -c $(CFLAGS) $< -o $@ clean: rm -f $(OBJECTS) *.*~ alac alac_decoder/README0000644000076500007650000000175311251345442014254 0ustar crazneycrazneyINSTALLATION: ------------- Simply compile by running 'make' USAGE: ------ Then run the program, it will give you usage instructions. It's really quite trivial to use. For example, to decode input.m4a to output.wav: ./alac -f output.wav input.m4a Or, as another example, say if you wanted to stream play http://www.mplayerhq.hu/MPlayer/samples/A-codecs/lossless/luckynight.m4a and you're system uses the ALSA sound system: wget -O - http://www.mplayerhq.hu/MPlayer/samples/A-codecs/lossless/luckynight.m4a | ./alac - | aplay By default the output file is in WAV format. To output as raw PCM, provide the -r option on the command line. MORE INFORMATION: ----------------- Please visit http://crazney.net/programs/itunes/alac.html for more information. HELP NEEDED: ------------ I need help to allow myself to continue hacking on various Apple Audio things, please visit http://crazney.net/programs/itunes/help.html AUTHOR: ------- David Hammerton CONTRIBUTORS: ------------- Cody Brocious alac_decoder/stdint_win.h0000644000076500007650000000061711251345442015725 0ustar crazneycrazney #ifndef ALAC_STDINT_WIN_H__ #define ALAC_STDINT_WIN_H__ typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef signed __int64 int64_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; typedef unsigned __int64 uint64_t; #endif // ALAC_STDINT_WIN_H__alac_decoder/stream.c0000644000076500007650000001017711251345442015033 0ustar crazneycrazney/* * ALAC (Apple Lossless Audio Codec) decoder * Copyright (c) 2005 David Hammerton * All rights reserved. * * Basic stream reading * * http://crazney.net/programs/itunes/alac.html * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include #ifdef _WIN32 #include "stdint_win.h" #else #include #endif #include "stream.h" #define _Swap32(v) do { \ v = (((v) & 0x000000FF) << 0x18) | \ (((v) & 0x0000FF00) << 0x08) | \ (((v) & 0x00FF0000) >> 0x08) | \ (((v) & 0xFF000000) >> 0x18); } while(0) #define _Swap16(v) do { \ v = (((v) & 0x00FF) << 0x08) | \ (((v) & 0xFF00) >> 0x08); } while (0) extern int host_bigendian; struct stream_tTAG { FILE *f; int bigendian; int eof; }; void stream_read(stream_t *stream, size_t size, void *buf) { size_t ret; ret = fread(buf, 4, size >> 2, stream->f) * 4; ret += fread((char*)buf + ret, 1, size - ret, stream->f); if (ret == 0 && size != 0) stream->eof = 1; } int32_t stream_read_int32(stream_t *stream) { int32_t v; stream_read(stream, 4, &v); if ((stream->bigendian && !host_bigendian) || (!stream->bigendian && host_bigendian)) { _Swap32(v); } return v; } uint32_t stream_read_uint32(stream_t *stream) { uint32_t v; stream_read(stream, 4, &v); if ((stream->bigendian && !host_bigendian) || (!stream->bigendian && host_bigendian)) { _Swap32(v); } return v; } int16_t stream_read_int16(stream_t *stream) { int16_t v; stream_read(stream, 2, &v); if ((stream->bigendian && !host_bigendian) || (!stream->bigendian && host_bigendian)) { _Swap16(v); } return v; } uint16_t stream_read_uint16(stream_t *stream) { uint16_t v; stream_read(stream, 2, &v); if ((stream->bigendian && !host_bigendian) || (!stream->bigendian && host_bigendian)) { _Swap16(v); } return v; } int8_t stream_read_int8(stream_t *stream) { int8_t v; stream_read(stream, 1, &v); return v; } uint8_t stream_read_uint8(stream_t *stream) { uint8_t v; stream_read(stream, 1, &v); return v; } void stream_skip(stream_t *stream, size_t skip) { if (fseek(stream->f, (long)skip, SEEK_CUR) == 0) return; if (errno == ESPIPE) { char *buffer = malloc(skip); stream_read(stream, skip, buffer); free(buffer); } } int stream_eof(stream_t *stream) { return stream->eof; } long stream_tell(stream_t *stream) { return ftell(stream->f); /* returns -1 on error */ } int stream_setpos(stream_t *stream, long pos) { return fseek(stream->f, pos, SEEK_SET); } stream_t *stream_create_file(FILE *file, int bigendian) { stream_t *new_stream; new_stream = (stream_t*)malloc(sizeof(stream_t)); new_stream->f = file; new_stream->bigendian = bigendian; new_stream->eof = 0; return new_stream; } void stream_destroy(stream_t *stream) { free(stream); } alac_decoder/stream.h0000644000076500007650000000146011251345442015033 0ustar crazneycrazney#ifndef STREAM_H #define STREAM_H /* stream.h */ #ifdef _WIN32 #include "stdint_win.h" #else #include #endif typedef struct stream_tTAG stream_t; void stream_read(stream_t *stream, size_t len, void *buf); int32_t stream_read_int32(stream_t *stream); uint32_t stream_read_uint32(stream_t *stream); int16_t stream_read_int16(stream_t *stream); uint16_t stream_read_uint16(stream_t *stream); int8_t stream_read_int8(stream_t *stream); uint8_t stream_read_uint8(stream_t *stream); void stream_skip(stream_t *stream, size_t skip); int stream_eof(stream_t *stream); long stream_tell(stream_t *stream); int stream_setpos(stream_t *stream, long pos); stream_t *stream_create_file(FILE *file, int bigendian); void stream_destroy(stream_t *stream); #endif /* STREAM_H */ alac_decoder/wavwriter.c0000644000076500007650000000621011251345442015563 0ustar crazneycrazney/* * ALAC (Apple Lossless Audio Codec) decoder * Copyright (c) 2005 David Hammerton * All rights reserved. * * Very basic WAV file writer (just writes the header) * * http://crazney.net/programs/itunes/alac.html * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #ifdef _WIN32 #include "stdint_win.h" #else #include #endif #ifndef MAKEFOURCC #define MAKEFOURCC(ch0, ch1, ch2, ch3) ( \ ( (int32_t)(char)(ch0) << 24 ) | \ ( (int32_t)(char)(ch1) << 16 ) | \ ( (int32_t)(char)(ch2) << 8 ) | \ ( (int32_t)(char)(ch3) ) ) #endif #define _Swap32(v) do { \ v = (((v) & 0x000000FF) << 0x18) | \ (((v) & 0x0000FF00) << 0x08) | \ (((v) & 0x00FF0000) >> 0x08) | \ (((v) & 0xFF000000) >> 0x18); } while(0) #define _Swap16(v) do { \ v = (((v) & 0x00FF) << 0x08) | \ (((v) & 0xFF00) >> 0x08); } while (0) extern int host_bigendian; static void write_uint32(FILE *f, uint32_t v, int bigendian) { if (bigendian ^ host_bigendian) _Swap32(v); fwrite(&v, 4, 1, f); } static void write_uint16(FILE *f, uint16_t v, int bigendian) { if (bigendian ^ host_bigendian) _Swap16(v); fwrite(&v, 2, 1, f); } void wavwriter_writeheaders(FILE *f, int datasize, int numchannels, int samplerate, int bitspersample) { /* write RIFF header */ write_uint32(f, MAKEFOURCC('R','I','F','F'), 1); write_uint32(f, 36 + datasize, 0); write_uint32(f, MAKEFOURCC('W','A','V','E'), 1); /* write fmt header */ write_uint32(f, MAKEFOURCC('f','m','t',' '), 1); write_uint32(f, 16, 0); write_uint16(f, 1, 0); /* PCM data */ write_uint16(f, numchannels, 0); write_uint32(f, samplerate, 0); write_uint32(f, samplerate * numchannels * (bitspersample / 8), 0); /* byterate */ write_uint16(f, numchannels * (bitspersample / 8), 0); write_uint16(f, bitspersample, 0); /* write data header */ write_uint32(f, MAKEFOURCC('d','a','t','a'), 1); write_uint32(f, datasize, 0); } alac_decoder/wavwriter.h0000644000076500007650000000034411251345442015572 0ustar crazneycrazney#ifndef WAVWRITER_H #define WAVWRITER_H void wavwriter_writeheaders(FILE *f, int datasize, int numchannels, int samplerate, int bitspersample); #endif /* WAVWRITER_H */