CVSROOT: /sources/gnash Module name: gnash Changes by: Sandro Santilli <strk> 07/08/09 21:56:30
Modified files: . : ChangeLog server/swf : tag_loaders.cpp Log message: * server/swf/tag_loaders.cpp: move all ADPCM-related code in an ADPCMDecoder class. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.3976&r2=1.3977 http://cvs.savannah.gnu.org/viewcvs/gnash/server/swf/tag_loaders.cpp?cvsroot=gnash&r1=1.124&r2=1.125 Patches: Index: ChangeLog =================================================================== RCS file: /sources/gnash/gnash/ChangeLog,v retrieving revision 1.3976 retrieving revision 1.3977 diff -u -b -r1.3976 -r1.3977 --- ChangeLog 9 Aug 2007 17:46:31 -0000 1.3976 +++ ChangeLog 9 Aug 2007 21:56:29 -0000 1.3977 @@ -1,5 +1,7 @@ 2007-08-09 Sandro Santilli <[EMAIL PROTECTED]> + * server/swf/tag_loaders.cpp: move all ADPCM-related code in an + ADPCMDecoder class. * README_CVS: minimum version of automake is 1.9.6. 1.7 and 1.8 have been tried w/out success. Might be a regression, but that is... * server/button_character_instance.cpp (construct): properly construct Index: server/swf/tag_loaders.cpp =================================================================== RCS file: /sources/gnash/gnash/server/swf/tag_loaders.cpp,v retrieving revision 1.124 retrieving revision 1.125 diff -u -b -r1.124 -r1.125 --- server/swf/tag_loaders.cpp 9 Aug 2007 17:01:19 -0000 1.124 +++ server/swf/tag_loaders.cpp 9 Aug 2007 21:56:30 -0000 1.125 @@ -17,7 +17,7 @@ // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA // -/* $Id: tag_loaders.cpp,v 1.124 2007/08/09 17:01:19 strk Exp $ */ +/* $Id: tag_loaders.cpp,v 1.125 2007/08/09 21:56:30 strk Exp $ */ #ifdef HAVE_CONFIG_H #include "config.h" @@ -77,13 +77,260 @@ int sample_count, // in stereo, this is number of *pairs* of samples bool stereo); -static void adpcm_expand(unsigned char* &data, stream* in, - int sample_count, // in stereo, this is number of *pairs* of samples - bool stereo); - namespace SWF { namespace tag_loaders { +// ---------------------------------------------------------------------------- +// ADPCMDecoder class +// ---------------------------------------------------------------------------- + +/// ADPCM decoder utilities +// +/// Algo from http://www.circuitcellar.com/pastissues/articles/richey110/text.htm +/// And also Jansen. +/// Here's another reference: http://www.geocities.com/SiliconValley/8682/aud3.txt +/// Original IMA spec doesn't seem to be on the web :( +/// +/// TODO: move in it's own file +/// +class ADPCMDecoder { + +private: + + // Data from Alexis' SWF reference + static int _index_update_table_2bits[2]; + static int _index_update_table_3bits[4]; + static int _index_update_table_4bits[8]; + static int _index_update_table_5bits[16]; + + static int* s_index_update_tables[4]; + + // Data from Jansen. http://homepages.cwi.nl/~jack/ + // Check out his Dutch retro punk songs, heh heh :) + static const int STEPSIZE_CT = 89; + static int s_stepsize[STEPSIZE_CT]; + + + static void doSample(int n_bits, int& sample, int& stepsize_index, int raw_code) + { + assert(raw_code >= 0 && raw_code < (1 << n_bits)); + + static const int HI_BIT = (1 << (n_bits - 1)); + int* index_update_table = s_index_update_tables[n_bits - 2]; + + /* Core of ADPCM. */ + + int code_mag = raw_code & (HI_BIT - 1); + bool code_sign_bit = (raw_code & HI_BIT) ? 1 : 0; + int mag = (code_mag << 1) + 1; /* shift in LSB (they do this so that pos & neg zero are different)*/ + + int stepsize = s_stepsize[stepsize_index]; + + /* Compute the new sample. It's the predicted value */ + /* (i.e. the previous value), plus a delta. The delta */ + /* comes from the code times the stepsize. going for */ + /* something like: delta = stepsize * (code * 2 + 1) >> code_bits */ + int delta = (stepsize * mag) >> (n_bits - 1); + if (code_sign_bit) delta = -delta; + + sample += delta; + sample = iclamp(sample, -32768, 32767); + + /* Update our stepsize index. Use a lookup table. */ + stepsize_index += index_update_table[code_mag]; + stepsize_index = iclamp(stepsize_index, 0, STEPSIZE_CT - 1); + } + + /* Uncompress 4096 mono samples of ADPCM. */ + static void doMonoBlock(int16_t** out_data, int n_bits, int sample_count, stream* in, int sample, int stepsize_index) + { + /* First sample doesn't need to be decompressed. */ + sample_count--; + *(*out_data)++ = (int16_t) sample; + + while (sample_count--) + { + int raw_code = in->read_uint(n_bits); + doSample(n_bits, sample, stepsize_index, raw_code); /* sample & stepsize_index are in/out params */ + *(*out_data)++ = (int16_t) sample; + } + } + + + /* Uncompress 4096 stereo sample pairs of ADPCM. */ + static void doStereoBlock( + int16_t** out_data, // in/out param + int n_bits, + int sample_count, + stream* in, + int left_sample, + int left_stepsize_index, + int right_sample, + int right_stepsize_index + ) + { + /* First samples don't need to be decompressed. */ + sample_count--; + *(*out_data)++ = (int16_t) left_sample; + *(*out_data)++ = (int16_t) right_sample; + + while (sample_count--) + { + int left_raw_code = in->read_uint(n_bits); + doSample(n_bits, left_sample, left_stepsize_index, left_raw_code); + *(*out_data)++ = (int16_t) left_sample; + + int right_raw_code = in->read_uint(n_bits); + doSample(n_bits, right_sample, right_stepsize_index, right_raw_code); + *(*out_data)++ = (int16_t) right_sample; + } + } + +public: + + // Utility function: uncompress ADPCM data from in stream to + // out_data[]. The output buffer must have (sample_count*2) + // bytes for mono, or (sample_count*4) bytes for stereo. + static void adpcm_expand( + unsigned char* &data, + stream* in, + int sample_count, // in stereo, this is number of *pairs* of samples (TODO: why is this signed at all ??) + bool stereo) + { + int16_t* out_data = new int16_t[stereo ? sample_count*2 : sample_count]; + data = reinterpret_cast<unsigned char *>(out_data); + + // Read header. + in->ensureBytes(1); // nbits + unsigned int n_bits = in->read_uint(2) + 2; // 2 to 5 bits (TODO: use unsigned...) + + +#ifndef GNASH_TRUST_SWF_INPUT + + // bitsPerCompSample is the number of bits for each comp sample + unsigned int bitsPerCompSample = n_bits; + if (stereo) bitsPerCompSample *= 2; + + // There's going to be one block every 4096 samples ... + unsigned int blocksCount = sample_count/4096; + + // ... or fraction + if ( sample_count%4096 ) ++blocksCount; + + // Of the total samples, all but the first sample in a block are comp + unsigned int compSamples = sample_count - blocksCount; + + // From every block, a fixed 22 bits will be read (16 of which are the uncomp sample) + unsigned int fixedBitsPerBlock = 22; + + // Total bits needed from stream + unsigned long bitsNeeded = (compSamples*bitsPerCompSample) + (fixedBitsPerBlock*blocksCount); + + // 2 bits have been read already, so the stream position is now one byte after the + // next 6 bits we're going to read, so we strip those 6 bits from the count of bits + // we still need + bitsNeeded -= (8-2); + + // Now, we convert this number to bytes, requiring one more if any + unsigned int excessBits = bitsNeeded%8; + unsigned long bytesNeeded = bitsNeeded/8; + if ( excessBits ) ++bytesNeeded; + + //log_debug("adpcm_expand, stereo:%d, sample_count:%u, bitsPerSample:%u, " + // "blocksCount:%u, bitsPerBlock:%u, bitsNeeded:%lu, excessBits:%u, bytesNeeded:%lu", + // stereo, sample_count, bitsPerCompSample, blocksCount, fixedBitsPerBlock, bitsNeeded, excessBits, bytesNeeded); + + in->ensureBytes(bytesNeeded); + +#endif // GNASH_TRUST_SWF_INPUT + + while (sample_count) + { + // Read initial sample & index values. + + int sample = in->read_sint(16); + + int stepsize_index = in->read_uint(6); + assert(STEPSIZE_CT >= (1 << 6)); // ensure we don't need to clamp. + + int samples_this_block = imin(sample_count, 4096); + sample_count -= samples_this_block; + + if (stereo == false) + { +#define DO_MONO(n) doMonoBlock(&out_data, n, samples_this_block, in, sample, stepsize_index) + + switch (n_bits) + { + default: assert(0); break; + case 2: DO_MONO(2); break; + case 3: DO_MONO(3); break; + case 4: DO_MONO(4); break; + case 5: DO_MONO(5); break; + } + } + else + { + // Stereo. + + // Got values for left channel; now get initial sample + // & index for right channel. + int right_sample = in->read_sint(16); + + int right_stepsize_index = in->read_uint(6); + assert(STEPSIZE_CT >= (1 << 6)); // ensure we don't need to clamp. + +#define DO_STEREO(n) \ + doStereoBlock( \ + &out_data, n, samples_this_block, \ + in, sample, stepsize_index, \ + right_sample, right_stepsize_index) + + switch (n_bits) + { + default: assert(0); break; + case 2: DO_STEREO(2); break; + case 3: DO_STEREO(3); break; + case 4: DO_STEREO(4); break; + case 5: DO_STEREO(5); break; + } + } + } + + } + + +}; + +int ADPCMDecoder::_index_update_table_2bits[2] = { -1, 2 }; +int ADPCMDecoder::_index_update_table_3bits[4] = { -1, -1, 2, 4 }; +int ADPCMDecoder::_index_update_table_4bits[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; +int ADPCMDecoder::_index_update_table_5bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }; + +int* ADPCMDecoder::s_index_update_tables[4] = { + ADPCMDecoder::_index_update_table_2bits, + ADPCMDecoder::_index_update_table_3bits, + ADPCMDecoder::_index_update_table_4bits, + ADPCMDecoder::_index_update_table_5bits +}; + +int ADPCMDecoder::s_stepsize[STEPSIZE_CT] = { + 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, + 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, + 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, + 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, + 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, + 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, + 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, + 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, + 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 +}; + +// ---------------------------------------------------------------------------- +// END OF ADPCMDecoder class +// ---------------------------------------------------------------------------- + + // // Some tag implementations // @@ -1321,7 +1568,7 @@ //log_debug("ADPCM format"); // Uncompress the ADPCM before handing data to host. if (sample_count == 0) sample_count = data_bytes / ( stereo ? 4 : 2 ); - adpcm_expand(data, in, sample_count, stereo); + ADPCMDecoder::adpcm_expand(data, in, sample_count, stereo); data_bytes = sample_count * (stereo ? 4 : 2); format = sound_handler::FORMAT_NATIVE16; break; @@ -1599,80 +1846,11 @@ data = (unsigned char *)out_data; } -// -// ADPCM -// - -// Data from Alexis' SWF reference -static int s_index_update_table_2bits[2] = { -1, 2 }; -static int s_index_update_table_3bits[4] = { -1, -1, 2, 4 }; -static int s_index_update_table_4bits[8] = { -1, -1, -1, -1, 2, 4, 6, 8 }; -static int s_index_update_table_5bits[16] = { -1, -1, -1, -1, -1, -1, -1, -1, 1, 2, 4, 6, 8, 10, 13, 16 }; - -static int* s_index_update_tables[4] = { - s_index_update_table_2bits, - s_index_update_table_3bits, - s_index_update_table_4bits, - s_index_update_table_5bits, -}; - -// Data from Jansen. http://homepages.cwi.nl/~jack/ -// Check out his Dutch retro punk songs, heh heh :) -const int STEPSIZE_CT = 89; -static int s_stepsize[STEPSIZE_CT] = { - 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, - 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, - 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, - 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, - 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, - 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, - 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, - 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, - 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 -}; - - -// Algo from http://www.circuitcellar.com/pastissues/articles/richey110/text.htm -// And also Jansen. -// Here's another reference: http://www.geocities.com/SiliconValley/8682/aud3.txt -// Original IMA spec doesn't seem to be on the web :( - // @@ lots of macros here! It seems that VC6 can't correctly // handle integer template args, although it's happy to // compile them?! -// void DO_SAMPLE(int n_bits, int& sample, int& stepsize_index, int raw_code) -#define DO_SAMPLE(n_bits, sample, stepsize_index, raw_code) \ -{ \ - assert(raw_code >= 0 && raw_code < (1 << n_bits)); \ - \ - static const int HI_BIT = (1 << (n_bits - 1)); \ - int* index_update_table = s_index_update_tables[n_bits - 2]; \ - \ - /* Core of ADPCM. */ \ - \ - int code_mag = raw_code & (HI_BIT - 1); \ - bool code_sign_bit = (raw_code & HI_BIT) ? 1 : 0; \ - int mag = (code_mag << 1) + 1; /* shift in LSB (they do this so that pos & neg zero are different)*/ \ - \ - int stepsize = s_stepsize[stepsize_index]; \ - \ - /* Compute the new sample. It's the predicted value */ \ - /* (i.e. the previous value), plus a delta. The delta */ \ - /* comes from the code times the stepsize. going for */ \ - /* something like: delta = stepsize * (code * 2 + 1) >> code_bits */ \ - int delta = (stepsize * mag) >> (n_bits - 1); \ - if (code_sign_bit) delta = -delta; \ - \ - sample += delta; \ - sample = iclamp(sample, -32768, 32767); \ - \ - /* Update our stepsize index. Use a lookup table. */ \ - stepsize_index += index_update_table[code_mag]; \ - stepsize_index = iclamp(stepsize_index, 0, STEPSIZE_CT - 1); \ -} - class in_stream { @@ -1691,162 +1869,4 @@ }; -// void DO_MONO_BLOCK(int16_t** out_data, int n_bits, int sample_count, stream* in, int sample, int stepsize_index) -#define DO_MONO_BLOCK(out_data, n_bits, sample_count, in, sample, stepsize_index) \ -{ \ - /* First sample doesn't need to be decompressed. */ \ - sample_count--; \ - *(*out_data)++ = (int16_t) sample; \ - \ - while (sample_count--) \ - { \ - int raw_code = in->read_uint(n_bits); \ - DO_SAMPLE(n_bits, sample, stepsize_index, raw_code); /* sample & stepsize_index are in/out params */ \ - *(*out_data)++ = (int16_t) sample; \ - } \ -} - - -// void do_stereo_block( -// int16_t** out_data, // in/out param -// int n_bits, -// int sample_count, -// stream* in, -// int left_sample, -// int left_stepsize_index, -// int right_sample, -// int right_stepsize_index -// ) -#define DO_STEREO_BLOCK(out_data, n_bits, sample_count, in, left_sample, left_stepsize_index, right_sample, right_stepsize_index) \ -/* Uncompress 4096 stereo sample pairs of ADPCM. */ \ -{ \ - /* First samples don't need to be decompressed. */ \ - sample_count--; \ - *(*out_data)++ = (int16_t) left_sample; \ - *(*out_data)++ = (int16_t) right_sample; \ - \ - while (sample_count--) \ - { \ - int left_raw_code = in->read_uint(n_bits); \ - DO_SAMPLE(n_bits, left_sample, left_stepsize_index, left_raw_code); \ - *(*out_data)++ = (int16_t) left_sample; \ - \ - int right_raw_code = in->read_uint(n_bits); \ - DO_SAMPLE(n_bits, right_sample, right_stepsize_index, right_raw_code); \ - *(*out_data)++ = (int16_t) right_sample; \ - } \ -} - - -// Utility function: uncompress ADPCM data from in stream to -// out_data[]. The output buffer must have (sample_count*2) -// bytes for mono, or (sample_count*4) bytes for stereo. -static void adpcm_expand( - unsigned char* &data, - stream* in, - int sample_count, // in stereo, this is number of *pairs* of samples (TODO: why is this signed at all ??) - bool stereo) -{ - int16_t* out_data = new int16_t[stereo ? sample_count*2 : sample_count]; - data = reinterpret_cast<unsigned char *>(out_data); - - // Read header. - in->ensureBytes(1); // nbits - unsigned int n_bits = in->read_uint(2) + 2; // 2 to 5 bits (TODO: use unsigned...) - - -#ifndef GNASH_TRUST_SWF_INPUT - - // bitsPerCompSample is the number of bits for each comp sample - unsigned int bitsPerCompSample = n_bits; - if (stereo) bitsPerCompSample *= 2; - - // There's going to be one block every 4096 samples ... - unsigned int blocksCount = sample_count/4096; - - // ... or fraction - if ( sample_count%4096 ) ++blocksCount; - - // Of the total samples, all but the first sample in a block are comp - unsigned int compSamples = sample_count - blocksCount; - - // From every block, a fixed 22 bits will be read (16 of which are the uncomp sample) - unsigned int fixedBitsPerBlock = 22; - - // Total bits needed from stream - unsigned long bitsNeeded = (compSamples*bitsPerCompSample) + (fixedBitsPerBlock*blocksCount); - - // 2 bits have been read already, so the stream position is now one byte after the - // next 6 bits we're going to read, so we strip those 6 bits from the count of bits - // we still need - bitsNeeded -= (8-2); - - // Now, we convert this number to bytes, requiring one more if any - unsigned int excessBits = bitsNeeded%8; - unsigned long bytesNeeded = bitsNeeded/8; - if ( excessBits ) ++bytesNeeded; - - //log_debug("adpcm_expand, stereo:%d, sample_count:%u, bitsPerSample:%u, " - // "blocksCount:%u, bitsPerBlock:%u, bitsNeeded:%lu, excessBits:%u, bytesNeeded:%lu", - // stereo, sample_count, bitsPerCompSample, blocksCount, fixedBitsPerBlock, bitsNeeded, excessBits, bytesNeeded); - - in->ensureBytes(bytesNeeded); - -#endif // GNASH_TRUST_SWF_INPUT - - while (sample_count) - { - // Read initial sample & index values. - - int sample = in->read_sint(16); - - int stepsize_index = in->read_uint(6); - assert(STEPSIZE_CT >= (1 << 6)); // ensure we don't need to clamp. - - int samples_this_block = imin(sample_count, 4096); - sample_count -= samples_this_block; - - if (stereo == false) - { -#define DO_MONO(n) DO_MONO_BLOCK(&out_data, n, samples_this_block, in, sample, stepsize_index) - - switch (n_bits) - { - default: assert(0); break; - case 2: DO_MONO(2); break; - case 3: DO_MONO(3); break; - case 4: DO_MONO(4); break; - case 5: DO_MONO(5); break; - } - } - else - { - // Stereo. - - // Got values for left channel; now get initial sample - // & index for right channel. - int right_sample = in->read_sint(16); - - int right_stepsize_index = in->read_uint(6); - assert(STEPSIZE_CT >= (1 << 6)); // ensure we don't need to clamp. - -#define DO_STEREO(n) \ - DO_STEREO_BLOCK( \ - &out_data, n, samples_this_block, \ - in, sample, stepsize_index, \ - right_sample, right_stepsize_index) - - switch (n_bits) - { - default: assert(0); break; - case 2: DO_STEREO(2); break; - case 3: DO_STEREO(3); break; - case 4: DO_STEREO(4); break; - case 5: DO_STEREO(5); break; - } - } - } - -} - } // namespace gnash _______________________________________________ Gnash-commit mailing list Gnash-commit@gnu.org http://lists.gnu.org/mailman/listinfo/gnash-commit