Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

dimuse_codecs.cpp

/* ScummVM - Scumm Interpreter
 * Copyright (C) 2001-2005 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.
 *
 * $Header: /cvsroot/scummvm/scummvm/scumm/imuse_digi/dimuse_codecs.cpp,v 1.14.2.1 2005/10/18 02:11:25 sev Exp $
 */

#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://home.pcisys.net/~melanson/codecs/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.
 */

#ifdef PALMOS_68K
static byte *_destImcTable = NULL;        // save 23k of memory !
static uint32 *_destImcTable2 = NULL;

static const int16 *imcTable;
#else
static byte _destImcTable[89];
static uint32 _destImcTable2[89 * 64];

static const int16 imcTable[] = {
      0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x0010, 0x0011,
      0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F, 0x0022, 0x0025, 0x0029, 0x002D,
      0x0032, 0x0037, 0x003C, 0x0042, 0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076,
      0x0082, 0x008F, 0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133,
      0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292, 0x02D4, 0x031C,
      0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583, 0x0610, 0x06AB, 0x0756, 0x0812,
      0x08E0, 0x09C3, 0x0ABD, 0x0BD0, 0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE,
      0x1706, 0x1954, 0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B,
      0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
};
#endif

static const byte imxOtherTable[6][64] = {
      {
            0xFF, 0x04
      },

      {
            0xFF, 0xFF, 0x02, 0x08
      },

      {
            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,
            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,
            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
      }
};

#ifdef PALMOS_68K
void releaseImcTables() {
      free(_destImcTable);
      free(_destImcTable2);
}
#endif

void initializeImcTables() {
      int pos;

#ifdef PALMOS_68K
      if (!_destImcTable) _destImcTable = (byte *)calloc(89, sizeof(byte));
      if (!_destImcTable2) _destImcTable2 = (uint32 *)calloc(89 * 64, sizeof(uint32));
#endif

      for (pos = 0; pos <= 88; ++pos) {
            byte put = 1;
            int32 tableValue = ((imcTable[pos] * 4) / 7) / 2;
            while (tableValue != 0) {
                  tableValue /= 2;
                  put++;
            }
            if (put < 3) {
                  put = 3;
            }
            if (put > 8) {
                  put = 8;
            }
            _destImcTable[pos] = put - 1;
      }

      for (int n = 0; n < 64; n++) {
            for (pos = 0; pos <= 88; ++pos) {
                  int32 count = 32;
                  int32 put = 0;
                  int32 tableValue = imcTable[pos];
                  do {
                        if ((count & n) != 0) {
                              put += tableValue;
                        }
                        count /= 2;
                        tableValue /= 2;
                  } while (count != 0);
                  _destImcTable2[n + pos * 64] = 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);
            memset(t_table, 0, 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);
            memset(t_table, 0, 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);
            memset(t_table, 0, 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 = _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;
                              }

                              // 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 > 88)
                                    curTablePos = 88;
                        }
                  }
            }
            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

Generated by  Doxygen 1.6.0   Back to index