diff options
author | Max Horn | 2005-06-24 19:09:12 +0000 |
---|---|---|
committer | Max Horn | 2005-06-24 19:09:12 +0000 |
commit | 6636cf102b7dcffdded5128fc724dae61a9d0279 (patch) | |
tree | fead6ef7abf6d13da2e44701cb937aa80680c782 /scumm | |
parent | 96f9571afce6ccc6827bf17893e573a27e309555 (diff) | |
download | scummvm-rg350-6636cf102b7dcffdded5128fc724dae61a9d0279.tar.gz scummvm-rg350-6636cf102b7dcffdded5128fc724dae61a9d0279.tar.bz2 scummvm-rg350-6636cf102b7dcffdded5128fc724dae61a9d0279.zip |
Heavy clean up for the iMuseDigital ADPCM codec; the code is now much easier to understand, even contains some comments ;-)
svn-id: r18460
Diffstat (limited to 'scumm')
-rw-r--r-- | scumm/imuse_digi/dimuse_codecs.cpp | 192 |
1 files changed, 93 insertions, 99 deletions
diff --git a/scumm/imuse_digi/dimuse_codecs.cpp b/scumm/imuse_digi/dimuse_codecs.cpp index 7b1157b0ea..6f10fffdd4 100644 --- a/scumm/imuse_digi/dimuse_codecs.cpp +++ b/scumm/imuse_digi/dimuse_codecs.cpp @@ -48,8 +48,10 @@ uint32 decode12BitsSample(const byte *src, byte **dst, uint32 size) { * The "IMC" codec below (see cases 13 & 15 in decompressCodec) is actually a * variant of the IMA codec, see also * <http://home.pcisys.net/~melanson/codecs/simpleaudio.html> - * Based on that information, we might be able to simplify this code. - * Thanks to LordNightmare for helping me figure this out :-) + * + * It is somewhat different, though: the standard ADPCM codecs use a fixed + * size for their data packets (4 bits), while the codec implemented here + * varies the size of each "packet" between 2 and 7 bits. */ #ifdef __PALM_OS__ @@ -74,24 +76,21 @@ static const int16 imcTable[] = { }; #endif -static const byte imxOtherTable[6][128] = { +static const byte imxOtherTable[6][64] = { { - 0xFF, 0x04, 0xFF, 0x04 + 0xFF, 0x04 }, { - 0xFF, 0xFF, 0x02, 0x08, 0xFF, 0xFF, 0x02, 0x08 + 0xFF, 0xFF, 0x02, 0x08 }, { - 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06 }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x01, 0x02, 0x04, 0x06, 0x08, 0x0C, 0x10, 0x20, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0C, 0x10, 0x20 }, @@ -99,10 +98,6 @@ static const byte imxOtherTable[6][128] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, - 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x20, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x01, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x20 }, @@ -114,22 +109,10 @@ static const byte imxOtherTable[6][128] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, - 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, - 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20 } }; -static const byte imxShortTable[] = { - 0, 0, 1, 3, 7, 15, 31, 63 -}; - #ifdef __PALM_OS__ void releaseImcTables() { free(_destImcTable); @@ -551,91 +534,105 @@ int32 decompressCodec(int32 codec, byte *comp_input, byte *comp_output, int32 in } { + // Decoder for the the IMA ADPCM variants used in COMI. + // Contrary to regular IMA ADPCM, this codec uses a variable + // bitsize for the encoded data. + const int MAX_CHANNELS = 2; - int32 left, startPos, origLeft, curTableEntry, destPos, esiReg; + int32 outputSamplesLeft; + int32 destPos; int16 firstWord; - byte sByte[MAX_CHANNELS] = {0, 0}; - int32 sDWord1[MAX_CHANNELS] = {0, 0}; - int32 sDWord2[MAX_CHANNELS] = {0, 0}; - int32 tableEntrySum, imcTableEntry, curTablePos, outputWord, adder; - byte decompTable, otherTablePos, bitMask; - byte *readPos, *dst; - uint16 readWord; - - assert(0 <= channels && channels <= MAX_CHANNELS); + byte initialTablePos[MAX_CHANNELS] = {0, 0}; + int32 initialimcTableEntry[MAX_CHANNELS] = {7, 7}; + int32 initialOutputWord[MAX_CHANNELS] = {0, 0}; + int32 totalBitOffset, curTablePos, outputWord; + byte *dst; + int i; + + // We only support mono and stereo + assert(channels == 1 || channels == 2); src = comp_input; dst = comp_output; - if (channels == 2) { - output_size = left = 0x2000; - } else { - left = 0x1000; - output_size = 0x2000; - } + output_size = 0x2000; + outputSamplesLeft = 0x1000; + + // Every data packet contains 0x2000 bytes of audio data + // when extracted. In order to encode bigger data sets, + // one has to split the data into multiple blocks. + // + // Every block starts with a 2 byte word. If that word is + // non-zero, it indicates the size of a block of raw audio + // data (not encoded) following it. That data we simply copy + // to the output buffer and the proceed by decoding the + // remaining data. + // + // If on the other hand the word is zero, then what follows + // are 7*channels bytes containing seed data for the decoder. firstWord = READ_BE_UINT16(src); src += 2; if (firstWord != 0) { + // Copy raw data memcpy(dst, src, firstWord); dst += firstWord; src += firstWord; - startPos = 0; - if (channels == 2) { - left = 0x2000 - firstWord; - output_size = left; - } else { - left = 0x1000 - (firstWord >> 1); - output_size = left << 1; - } - output_size += firstWord; + assert((firstWord & 3) == 0); + outputSamplesLeft -= firstWord / 2; } else { - startPos = 1; - for (int i = 0; i < channels; i++) { - sByte[i] = *(src++); - sDWord1[i] = READ_BE_UINT32(src); + // Read the seed values for the decoder. + for (i = 0; i < channels; i++) { + initialTablePos[i] = *src; + src += 1; + initialimcTableEntry[i] = READ_BE_UINT32(src); src += 4; - sDWord2[i] = READ_BE_UINT32(src); + initialOutputWord[i] = READ_BE_UINT32(src); src += 4; } } - origLeft = left >> (channels - 1); - tableEntrySum = 0; - for (int l = 0; l < channels; l++) { - if (startPos != 0) { - curTablePos = sByte[l]; - imcTableEntry = sDWord1[l]; - outputWord = sDWord2[l]; - } else { - curTablePos = 0; - imcTableEntry = 7; - outputWord = 0; - } - - left = origLeft; - destPos = l << 1; - - if (channels == 2) { - if (l == 0) - left++; - left >>= 1; - } - - while (left--) { - curTableEntry = _destImcTable[curTablePos]; - decompTable = (byte)(curTableEntry - 2); - bitMask = 2 << decompTable; - readPos = src + (tableEntrySum >> 3); - readWord = (uint16)(READ_BE_UINT16(readPos) << (tableEntrySum & 7)); - otherTablePos = (byte)(readWord >> (16 - curTableEntry)); - tableEntrySum += curTableEntry; - esiReg = ((imxShortTable[curTableEntry] & otherTablePos) - << (7 - curTableEntry)) + (curTablePos * 64); - imcTableEntry >>= (curTableEntry - 1); - adder = imcTableEntry + _destImcTable2[esiReg]; - if ((otherTablePos & bitMask) != 0) { - adder = -adder; + outputSamplesLeft /= channels; + totalBitOffset = 0; + // The channels are encoded separately. + for (int chan = 0; chan < channels; chan++) { + // Read initial state (this makes it possible for the data stream + // to be split & spread across multiple data chunks. + curTablePos = initialTablePos[chan]; + //imcTableEntry = initialimcTableEntry[chan]; + outputWord = initialOutputWord[chan]; + + // We need to interleave the channels in the output; we achieve + // that by using a variables dest offset: + destPos = chan * 2; + + for (i = 0; i < outputSamplesLeft; ++i) { + // Determine the size (in bits) of the next data packet + const int32 curTableEntryBitCount = _destImcTable[curTablePos]; + assert(2 <= curTableEntryBitCount && curTableEntryBitCount <= 7); + + // Read the next data packet + const byte *readPos = src + (totalBitOffset >> 3); + const uint16 readWord = (uint16)(READ_BE_UINT16(readPos) << (totalBitOffset & 7)); + const byte packet = (byte)(readWord >> (16 - curTableEntryBitCount)); + + // Advance read position to the next data packet + totalBitOffset += curTableEntryBitCount; + + // Decode the data packet into a delta value for the output signal. + const byte signBitMask = (1 << (curTableEntryBitCount - 1)); + const byte dataBitMask = (signBitMask - 1); + const byte data = (packet & dataBitMask); + + const int32 tmpA = (data << (7 - curTableEntryBitCount)); + const int32 imcTableEntry = imcTable[curTablePos] >> (curTableEntryBitCount - 1); + int32 delta = imcTableEntry + _destImcTable2[tmpA + (curTablePos * 64)]; + + // The topmost bit in the data packet tells is a sign bit + if ((packet & signBitMask) != 0) { + delta = -delta; } - outputWord += adder; + + // Accumulate the delta onto the output data + outputWord += delta; // Clip outputWord to 16 bit signed, and write it into the destination stream if (outputWord > 0x7fff) @@ -643,17 +640,14 @@ int32 decompressCodec(int32 codec, byte *comp_input, byte *comp_output, int32 in if (outputWord < -0x8000) outputWord = -0x8000; WRITE_BE_UINT16(dst + destPos, outputWord); + destPos += channels << 1; - // Adjust the curTablePos / imcTableEntry - assert(decompTable < 6); - curTablePos += (signed char)imxOtherTable[decompTable][otherTablePos]; - if (curTablePos > 88) - curTablePos = 88; + // Adjust the curTablePos + curTablePos += (int8)imxOtherTable[curTableEntryBitCount - 2][data]; if (curTablePos < 0) curTablePos = 0; - imcTableEntry = imcTable[curTablePos]; - - destPos += channels << 1; + else if (curTablePos > 88) + curTablePos = 88; } } } |