aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/imuse_digi/dimuse_codecs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/imuse_digi/dimuse_codecs.cpp')
-rw-r--r--engines/scumm/imuse_digi/dimuse_codecs.cpp655
1 files changed, 655 insertions, 0 deletions
diff --git a/engines/scumm/imuse_digi/dimuse_codecs.cpp b/engines/scumm/imuse_digi/dimuse_codecs.cpp
new file mode 100644
index 0000000000..dccae928b0
--- /dev/null
+++ b/engines/scumm/imuse_digi/dimuse_codecs.cpp
@@ -0,0 +1,655 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ */
+
+#include "common/stdafx.h"
+#include "common/scummsys.h"
+#include "common/util.h"
+
+namespace Scumm {
+
+namespace BundleCodecs {
+
+uint32 decode12BitsSample(const byte *src, byte **dst, uint32 size) {
+ uint32 loop_size = size / 3;
+ uint32 s_size = loop_size * 4;
+ byte *ptr = *dst = (byte *)malloc(s_size);
+
+ uint32 tmp;
+ while (loop_size--) {
+ byte v1 = *src++;
+ byte v2 = *src++;
+ byte v3 = *src++;
+ tmp = ((((v2 & 0x0f) << 8) | v1) << 4) - 0x8000;
+ WRITE_BE_UINT16(ptr, tmp); ptr += 2;
+ tmp = ((((v2 & 0xf0) << 4) | v3) << 4) - 0x8000;
+ WRITE_BE_UINT16(ptr, tmp); ptr += 2;
+ }
+ return s_size;
+}
+
+/*
+ * The "IMC" codec below (see cases 13 & 15 in decompressCodec) is actually a
+ * variant of the IMA codec, see also
+ * <http://www.multimedia.cx/simpleaudio.html>
+ *
+ * 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.
+ */
+
+static byte _imcTableEntryBitCount[89];
+
+#ifdef PALMOS_68K
+static const int16 *imcTable;
+#else
+static const int16 imcTable[89] = {
+ 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
+};
+#endif
+
+static const byte imxOtherTable[6][64] = {
+ {
+ 0xFF,
+ 4
+ },
+
+ {
+ 0xFF, 0xFF,
+ 2, 8
+ },
+
+ {
+ 0xFF, 0xFF, 0xFF, 0xFF,
+ 1, 2, 4, 6
+ },
+
+ {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 1, 2, 4, 6, 8, 12, 16, 32
+ },
+
+ {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 1, 2, 4, 6, 8, 10, 12, 14,
+ 16, 18, 20, 22, 24, 26, 28, 32
+ },
+
+ {
+ 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,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32
+ }
+};
+
+void initializeImcTables() {
+ int pos;
+
+ for (pos = 0; pos < ARRAYSIZE(imcTable); ++pos) {
+ byte put = 0;
+ int32 tableValue = ((imcTable[pos] * 4) / 7) / 2;
+ while (tableValue != 0) {
+ tableValue /= 2;
+ put++;
+ }
+ if (put < 2) {
+ put = 2;
+ }
+ if (put > 7) {
+ put = 7;
+ }
+ _imcTableEntryBitCount[pos] = put;
+ }
+}
+
+#define NextBit \
+ do { \
+ bit = mask & 1; \
+ mask >>= 1; \
+ if (!--bitsleft) { \
+ mask = READ_LE_UINT16(srcptr); \
+ srcptr += 2; \
+ bitsleft = 16; \
+ } \
+ } while (0)
+
+static int32 compDecode(byte *src, byte *dst) {
+ byte *result, *srcptr = src, *dstptr = dst;
+ int data, size, bit, bitsleft = 16, mask = READ_LE_UINT16(srcptr);
+ srcptr += 2;
+
+ for (;;) {
+ NextBit;
+ if (bit) {
+ *dstptr++ = *srcptr++;
+ } else {
+ NextBit;
+ if (!bit) {
+ NextBit;
+ size = bit << 1;
+ NextBit;
+ size = (size | bit) + 3;
+ data = *srcptr++ | 0xffffff00;
+ } else {
+ data = *srcptr++;
+ size = *srcptr++;
+
+ data |= 0xfffff000 + ((size & 0xf0) << 4);
+ size = (size & 0x0f) + 3;
+
+ if (size == 3)
+ if (((*srcptr++) + 1) == 1)
+ return dstptr - dst;
+ }
+ result = dstptr + data;
+ while (size--)
+ *dstptr++ = *result++;
+ }
+ }
+}
+#undef NextBit
+
+int32 decompressCodec(int32 codec, byte *comp_input, byte *comp_output, int32 input_size) {
+ int32 output_size, channels;
+ int32 offset1, offset2, offset3, length, k, c, s, j, r, t, z;
+ byte *src, *t_table, *p, *ptr;
+ byte t_tmp1, t_tmp2;
+
+ switch (codec) {
+ case 0:
+ memcpy(comp_output, comp_input, input_size);
+ output_size = input_size;
+ break;
+
+ case 1:
+ output_size = compDecode(comp_input, comp_output);
+ break;
+
+ case 2:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+ break;
+
+ case 3:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+ break;
+
+ case 4:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+
+ src = comp_output;
+ length = (output_size << 3) / 12;
+ k = 0;
+ if (length > 0) {
+ c = -12;
+ s = 0;
+ j = 0;
+ do {
+ ptr = src + length + (k >> 1);
+ t_tmp2 = src[j];
+ if (k & 1) {
+ r = c >> 3;
+ t_table[r + 2] = ((t_tmp2 & 0x0f) << 4) | (ptr[1] >> 4);
+ t_table[r + 1] = (t_tmp2 & 0xf0) | (t_table[r + 1]);
+ } else {
+ r = s >> 3;
+ t_table[r + 0] = ((t_tmp2 & 0x0f) << 4) | (ptr[0] & 0x0f);
+ t_table[r + 1] = t_tmp2 >> 4;
+ }
+ s += 12;
+ c += 12;
+ k++;
+ j++;
+ } while (k < length);
+ }
+ offset1 = ((length - 1) * 3) >> 1;
+ t_table[offset1 + 1] = (t_table[offset1 + 1]) | (src[length - 1] & 0xf0);
+ memcpy(src, t_table, output_size);
+ free(t_table);
+ break;
+
+ case 5:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+
+ src = comp_output;
+ length = (output_size << 3) / 12;
+ k = 1;
+ c = 0;
+ s = 12;
+ t_table[0] = src[length] >> 4;
+ t = length + k;
+ j = 1;
+ if (t > k) {
+ do {
+ t_tmp1 = *(src + length + (k >> 1));
+ t_tmp2 = src[j - 1];
+ if (k & 1) {
+ r = c >> 3;
+ t_table[r + 0] = (t_tmp2 & 0xf0) | t_table[r];
+ t_table[r + 1] = ((t_tmp2 & 0x0f) << 4) | (t_tmp1 & 0x0f);
+ } else {
+ r = s >> 3;
+ t_table[r + 0] = t_tmp2 >> 4;
+ t_table[r - 1] = ((t_tmp2 & 0x0f) << 4) | (t_tmp1 >> 4);
+ }
+ s += 12;
+ c += 12;
+ k++;
+ j++;
+ } while (k < t);
+ }
+ memcpy(src, t_table, output_size);
+ free(t_table);
+ break;
+
+ case 6:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+
+ src = comp_output;
+ length = (output_size << 3) / 12;
+ k = 0;
+ c = 0;
+ j = 0;
+ s = -12;
+ t_table[0] = src[output_size - 1];
+ t_table[output_size - 1] = src[length - 1];
+ t = length - 1;
+ if (t > 0) {
+ do {
+ t_tmp1 = *(src + length + (k >> 1));
+ t_tmp2 = src[j];
+ if (k & 1) {
+ r = s >> 3;
+ t_table[r + 2] = (t_tmp2 & 0xf0) | t_table[r + 2];
+ t_table[r + 3] = ((t_tmp2 & 0x0f) << 4) | (t_tmp1 >> 4);
+ } else {
+ r = c >> 3;
+ t_table[r + 2] = t_tmp2 >> 4;
+ t_table[r + 1] = ((t_tmp2 & 0x0f) << 4) | (t_tmp1 & 0x0f);
+ }
+ s += 12;
+ c += 12;
+ k++;
+ j++;
+ } while (k < t);
+ }
+ memcpy(src, t_table, output_size);
+ free(t_table);
+ break;
+
+ case 10:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memcpy(t_table, p, output_size);
+
+ offset1 = output_size / 3;
+ offset2 = offset1 << 1;
+ offset3 = offset2;
+ src = comp_output;
+
+ while (offset1--) {
+ offset2 -= 2;
+ offset3--;
+ t_table[offset2 + 0] = src[offset1];
+ t_table[offset2 + 1] = src[offset3];
+ }
+
+ src = comp_output;
+ length = (output_size << 3) / 12;
+ k = 0;
+ if (length > 0) {
+ c = -12;
+ s = 0;
+ do {
+ j = length + (k >> 1);
+ t_tmp1 = t_table[k];
+ if (k & 1) {
+ r = c >> 3;
+ t_tmp2 = t_table[j + 1];
+ src[r + 2] = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 >> 4);
+ src[r + 1] = (src[r + 1]) | (t_tmp1 & 0xf0);
+ } else {
+ r = s >> 3;
+ t_tmp2 = t_table[j];
+ src[r + 0] = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
+ src[r + 1] = t_tmp1 >> 4;
+ }
+ s += 12;
+ c += 12;
+ k++;
+ } while (k < length);
+ }
+ offset1 = ((length - 1) * 3) >> 1;
+ src[offset1 + 1] = (t_table[length] & 0xf0) | src[offset1 + 1];
+ free(t_table);
+ break;
+
+ case 11:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memcpy(t_table, p, output_size);
+
+ offset1 = output_size / 3;
+ offset2 = offset1 << 1;
+ offset3 = offset2;
+ src = comp_output;
+
+ while (offset1--) {
+ offset2 -= 2;
+ offset3--;
+ t_table[offset2 + 0] = src[offset1];
+ t_table[offset2 + 1] = src[offset3];
+ }
+
+ src = comp_output;
+ length = (output_size << 3) / 12;
+ k = 1;
+ c = 0;
+ s = 12;
+ t_tmp1 = t_table[length] >> 4;
+ src[0] = t_tmp1;
+ t = length + k;
+ if (t > k) {
+ do {
+ j = length + (k >> 1);
+ t_tmp1 = t_table[k - 1];
+ t_tmp2 = t_table[j];
+ if (k & 1) {
+ r = c >> 3;
+ src[r + 0] = (src[r]) | (t_tmp1 & 0xf0);
+ src[r + 1] = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
+ } else {
+ r = s >> 3;
+ src[r + 0] = t_tmp1 >> 4;
+ src[r - 1] = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 >> 4);
+ }
+ s += 12;
+ c += 12;
+ k++;
+ } while (k < t);
+ }
+ free(t_table);
+ break;
+
+ case 12:
+ output_size = compDecode(comp_input, comp_output);
+ p = comp_output;
+ for (z = 2; z < output_size; z++)
+ p[z] += p[z - 1];
+ for (z = 1; z < output_size; z++)
+ p[z] += p[z - 1];
+
+ t_table = (byte *)malloc(output_size);
+ memcpy(t_table, p, output_size);
+
+ offset1 = output_size / 3;
+ offset2 = offset1 << 1;
+ offset3 = offset2;
+ src = comp_output;
+
+ while (offset1--) {
+ offset2 -= 2;
+ offset3--;
+ t_table[offset2 + 0] = src[offset1];
+ t_table[offset2 + 1] = src[offset3];
+ }
+
+ src = comp_output;
+ length = (output_size << 3) / 12;
+ k = 0;
+ c = 0;
+ s = -12;
+ src[0] = t_table[output_size - 1];
+ src[output_size - 1] = t_table[length - 1];
+ t = length - 1;
+ if (t > 0) {
+ do {
+ j = length + (k >> 1);
+ t_tmp1 = t_table[k];
+ t_tmp2 = t_table[j];
+ if (k & 1) {
+ r = s >> 3;
+ src[r + 2] = (src[r + 2]) | (t_tmp1 & 0xf0);
+ src[r + 3] = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 >> 4);
+ } else {
+ r = c >> 3;
+ src[r + 2] = t_tmp1 >> 4;
+ src[r + 1] = ((t_tmp1 & 0x0f) << 4) | (t_tmp2 & 0x0f);
+ }
+ s += 12;
+ c += 12;
+ k++;
+ } while (k < t);
+ }
+ free(t_table);
+ break;
+
+ case 13:
+ case 15:
+ if (codec == 13) {
+ channels = 1;
+ } else {
+ channels = 2;
+ }
+
+ {
+ // 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 outputSamplesLeft;
+ int32 destPos;
+ int16 firstWord;
+ 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;
+ 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;
+ assert((firstWord & 1) == 0);
+ outputSamplesLeft -= firstWord / 2;
+ } else {
+ // 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;
+ initialOutputWord[i] = READ_BE_UINT32(src);
+ src += 4;
+ }
+ }
+
+ 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;
+
+ const int bound = (channels == 1)
+ ? outputSamplesLeft
+ : ((chan == 0)
+ ? (outputSamplesLeft+1) / 2
+ : outputSamplesLeft / 2);
+ for (i = 0; i < bound; ++i) {
+ // Determine the size (in bits) of the next data packet
+ const int32 curTableEntryBitCount = _imcTableEntryBitCount[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);
+
+ int32 delta = imcTable[curTablePos] * (2 * data + 1) >> (curTableEntryBitCount - 1);
+
+ // The topmost bit in the data packet tells is a sign bit
+ if ((packet & signBitMask) != 0) {
+ delta = -delta;
+ }
+
+ // 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)
+ outputWord = 0x7fff;
+ if (outputWord < -0x8000)
+ outputWord = -0x8000;
+ WRITE_BE_UINT16(dst + destPos, outputWord);
+ destPos += channels << 1;
+
+ // Adjust the curTablePos
+ curTablePos += (int8)imxOtherTable[curTableEntryBitCount - 2][data];
+ if (curTablePos < 0)
+ curTablePos = 0;
+ else if (curTablePos >= ARRAYSIZE(imcTable))
+ curTablePos = ARRAYSIZE(imcTable) - 1;
+ }
+ }
+ }
+ break;
+
+ default:
+ error("BundleCodecs::decompressCodec() Unknown codec %d!", (int)codec);
+ output_size = 0;
+ break;
+ }
+
+ return output_size;
+}
+
+} // End of namespace BundleCodecs
+
+} // End of namespace Scumm
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(DimuseCodecs)
+_GSETPTR(Scumm::BundleCodecs::imcTable, GBVARS_IMCTABLE_INDEX, int16, GBVARS_SCUMM)
+_GEND
+
+_GRELEASE(DimuseCodecs)
+_GRELEASEPTR(GBVARS_IMCTABLE_INDEX, GBVARS_SCUMM)
+_GEND
+
+#endif