void SmackerDecoder::SmackerAudioTrack::queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize) { Common::BitStream8LSB audioBS(new Common::MemoryReadStream(buffer, bufferSize), true); bool dataPresent = audioBS.getBit(); if (!dataPresent) return; bool isStereo = audioBS.getBit(); assert(isStereo == _audioInfo.isStereo); bool is16Bits = audioBS.getBit(); assert(is16Bits == _audioInfo.is16Bits); int numBytes = 1 * (isStereo ? 2 : 1) * (is16Bits ? 2 : 1); byte *unpackedBuffer = (byte *)malloc(unpackedSize); byte *curPointer = unpackedBuffer; uint32 curPos = 0; SmallHuffmanTree *audioTrees[4]; for (int k = 0; k < numBytes; k++) audioTrees[k] = new SmallHuffmanTree(audioBS); // Base values, stored as big endian int32 bases[2]; if (isStereo) { if (is16Bits) { bases[1] = SWAP_BYTES_16(audioBS.getBits(16)); } else { bases[1] = audioBS.getBits(8); } } if (is16Bits) { bases[0] = SWAP_BYTES_16(audioBS.getBits(16)); } else { bases[0] = audioBS.getBits(8); } // The bases are the first samples, too for (int i = 0; i < (isStereo ? 2 : 1); i++, curPointer += (is16Bits ? 2 : 1), curPos += (is16Bits ? 2 : 1)) { if (is16Bits) WRITE_BE_UINT16(curPointer, bases[i]); else *curPointer = (bases[i] & 0xFF) ^ 0x80; } // Next follow the deltas, which are added to the corresponding base values and // are stored as little endian // We store the unpacked bytes in big endian format while (curPos < unpackedSize) { // If the sample is stereo, the data is stored for the left and right channel, respectively // (the exact opposite to the base values) if (!is16Bits) { for (int k = 0; k < (isStereo ? 2 : 1); k++) { bases[k] += (int8) ((int16) audioTrees[k]->getCode(audioBS)); *curPointer++ = CLIP<int>(bases[k], 0, 255) ^ 0x80; curPos++; } } else { for (int k = 0; k < (isStereo ? 2 : 1); k++) { byte lo = audioTrees[k * 2]->getCode(audioBS); byte hi = audioTrees[k * 2 + 1]->getCode(audioBS); bases[k] += (int16) (lo | (hi << 8)); WRITE_BE_UINT16(curPointer, bases[k]); curPointer += 2; curPos += 2; } } } for (int k = 0; k < numBytes; k++) delete audioTrees[k]; queuePCM(unpackedBuffer, unpackedSize); }
void SmackerDecoder::queueCompressedBuffer(byte *buffer, uint32 bufferSize, uint32 unpackedSize, int streamNum) { BitStream audioBS(buffer, bufferSize); bool dataPresent = audioBS.getBit(); if (!dataPresent) return; bool isStereo = audioBS.getBit(); assert(isStereo == _header.audioInfo[streamNum].isStereo); bool is16Bits = audioBS.getBit(); assert(is16Bits == _header.audioInfo[streamNum].is16Bits); int numBytes = 1 * (isStereo ? 2 : 1) * (is16Bits ? 2 : 1); byte *unpackedBuffer = (byte *)malloc(unpackedSize); byte *curPointer = unpackedBuffer; uint32 curPos = 0; SmallHuffmanTree *audioTrees[4]; for (int k = 0; k < numBytes; k++) audioTrees[k] = new SmallHuffmanTree(audioBS); // Base values, stored as big endian int32 bases[2]; if (isStereo) { if (is16Bits) { byte hi = audioBS.getBits8(); byte lo = audioBS.getBits8(); bases[1] = (int16) ((hi << 8) | lo); } else { bases[1] = audioBS.getBits8(); } } if (is16Bits) { byte hi = audioBS.getBits8(); byte lo = audioBS.getBits8(); bases[0] = (int16) ((hi << 8) | lo); } else { bases[0] = audioBS.getBits8(); } // The bases are the first samples, too for (int i = 0; i < (isStereo ? 2 : 1); i++, curPointer += (is16Bits ? 2 : 1), curPos += (is16Bits ? 2 : 1)) { if (is16Bits) WRITE_BE_UINT16(curPointer, bases[i]); else *curPointer = (bases[i] & 0xFF) ^ 0x80; } // Next follow the deltas, which are added to the corresponding base values and // are stored as little endian // We store the unpacked bytes in big endian format while (curPos < unpackedSize) { // If the sample is stereo, the data is stored for the left and right channel, respectively // (the exact opposite to the base values) if (!is16Bits) { for (int k = 0; k < (isStereo ? 2 : 1); k++) { bases[k] += (int8) ((int16) audioTrees[k]->getCode(audioBS)); *curPointer++ = CLIP<int>(bases[k], 0, 255) ^ 0x80; curPos++; } } else { for (int k = 0; k < (isStereo ? 2 : 1); k++) { byte lo = audioTrees[k * 2]->getCode(audioBS); byte hi = audioTrees[k * 2 + 1]->getCode(audioBS); bases[k] += (int16) (lo | (hi << 8)); WRITE_BE_UINT16(curPointer, bases[k]); curPointer += 2; curPos += 2; } } } for (int k = 0; k < numBytes; k++) delete audioTrees[k]; byte flags = 0; if (_header.audioInfo[0].is16Bits) flags = flags | Audio::FLAG_16BITS; if (_header.audioInfo[0].isStereo) flags = flags | Audio::FLAG_STEREO; _audioStream->queueBuffer(unpackedBuffer, unpackedSize, DisposeAfterUse::YES, flags); // unpackedBuffer will be deleted by QueuingAudioStream }