diff --git a/libacm/CMakeLists.txt b/libacm/CMakeLists.txt index 01721d22..3fc57e78 100644 --- a/libacm/CMakeLists.txt +++ b/libacm/CMakeLists.txt @@ -1,7 +1,7 @@ set(HEADERS) set(CPPS aencode.cpp - libacm.cpp) + adecode.cpp) # these are the relevant source files from upstream libacm (https://github.com/markokr/libacm/) set(LIB_SRC diff --git a/libacm/adecode.cpp b/libacm/adecode.cpp new file mode 100644 index 00000000..a30202fa --- /dev/null +++ b/libacm/adecode.cpp @@ -0,0 +1,161 @@ +/* + * Descent 3 + * Copyright (C) 2024 Parallax Software + * + * 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 3 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, see . + */ + +#include "Adecode.h" + +#include "libacm.h" + +using namespace AudioDecoder; + +namespace { + +class InternalAudioDecoder : public IAudioDecoder { +public: + InternalAudioDecoder(ReadDataFunction readerFunction, void *pReaderData); + ~InternalAudioDecoder(); + + // Initialize the decoder + bool Initialize(); + + // Read data from the audio decoder. + // pBuffer: The buffer to receive the data into + // amount: How much data to read + // Returns the number of bytes read - zero when we're at the end of the file + uint32 Read(void *pBuffer, uint32 amount); + + ACMStream *m_acm = nullptr; + ReadDataFunction m_readerFunction; + void *m_pReaderData; +}; + +/**************************************************************/ +/* Construction */ +/**************************************************************/ + +int AcmReadFunc(void *ptr, int size, int n, void *datasrc) { + InternalAudioDecoder *iad = reinterpret_cast(datasrc); + int ret = + iad->m_readerFunction(iad->m_pReaderData, ptr, (unsigned int)size * n); + // ret < 0: error, ret == 0: EOF, ret > 0: read ret bytes of data + // apparently acm_io_callbacks::read() expects pretty much the same behavior, + // except that for > 0 it's not number of bytes but number of items (like in + // fread()) + if (ret > 0) { + ret /= size; + } + return ret; +} + +InternalAudioDecoder::InternalAudioDecoder(ReadDataFunction readerFunction, + void *pReaderData) + : m_readerFunction(readerFunction), m_pReaderData(pReaderData) {} + +// Initialize the decoder +bool InternalAudioDecoder::Initialize() { + + acm_io_callbacks io = { + AcmReadFunc}; // set the read function, the others are optional + + int force_channels = + 0; // 0 = let libacm figure out how many channels the file has + // TODO: the old libacm.cpp was more optimistic about the numbers of channel + // from the file header + // than libacm's decode.c, which assumes that channels are always >= 2 + // (unless it's WAVC instead of "plain ACM"), i.e. that a file header + // specifying 1 is wrong. If it turns out that we really have ACM files + // with just one channel (not unusual for ingame sounds?), we might have + // to either patch acm_open_decoder() or somehow detect the number of + // channels here and set force_channels accordingly + int ret = acm_open_decoder(&m_acm, this, io, force_channels); + return ret == ACM_OK; +} + +/**************************************************************/ +/* Destruction */ +/**************************************************************/ + +InternalAudioDecoder::~InternalAudioDecoder() { + if (m_acm != nullptr) + acm_close(m_acm); +} + +/**************************************************************/ +/* Reading */ +/**************************************************************/ + +// Read data from the audio decoder. +// pBuffer: The buffer to receive the data into +// amount: How much data to read +// Returns the number of bytes read - zero when we're at the end of the file +uint32 InternalAudioDecoder::Read(void *pBuffer, uint32 amount) { + const int bigendianp = 0; // we want little endian samples + const int wordlen = 2; // the only supported value + const int sgned = 1; // we want signed samples + uint32 totalBytesRead = 0; + + while (totalBytesRead < amount) { + int numRead = acm_read(m_acm, pBuffer, amount, bigendianp, wordlen, sgned); + // numRead < 0: error, numRead == 0: EOF, numRead > 0: amount of bytes read + if (numRead <= 0) + break; + totalBytesRead += numRead; + } + + return totalBytesRead; +} + +} // namespace + +/**************************************************************/ +/* Interface Functions */ +/**************************************************************/ + +// Create an audio decoder +// You supply a function for reading bytes from the compressed data via a +// void* pData handle, and the handle itself (typically a FILE *). +// Create_AudioDecoder returns a new AudioDecoder which can be used to +// read uncompressed decoded data from the compressed stream, +// and also returns the number of channels (1 or 2), the sample rate +// (e.g. 22050), and the number of samples contained in the compressed file +// (in case you want to pre-allocate a buffer to load them all into memory). +IAudioDecoder *AudioDecoder::CreateDecoder(ReadDataFunction readerFunction, + void *pReaderData, + uint32 &numChannels, + uint32 &sampleRate, + uint32 &sampleCount) { + // allocate our decoder + InternalAudioDecoder *pDecoder = + new InternalAudioDecoder(readerFunction, pReaderData); + if (pDecoder == nullptr) + return nullptr; + + // initialize + if (!pDecoder->Initialize()) { + // Failed + delete pDecoder; + return nullptr; + } + + // extract the header information for the caller + numChannels = pDecoder->m_acm->info.channels; + sampleRate = pDecoder->m_acm->info.rate; + sampleCount = pDecoder->m_acm->total_values; + + // return the decoder back to the user + return pDecoder; +} diff --git a/libacm/libacm.cpp b/libacm/libacm.cpp deleted file mode 100644 index db260cb3..00000000 --- a/libacm/libacm.cpp +++ /dev/null @@ -1,1046 +0,0 @@ -// Interplay ACM audio codec decoder -// -// Based on code from the decoder source of libacm, licensed under a minimal BSD/ISC license: -// Copyright (c) 2004-2008, Marko Kreen -// -// Permission to use, copy, modify, and distribute this software for any -// purpose with or without fee is hereby granted, provided that the above -// copyright notice and this permission notice appear in all copies. -// -// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -#include "Adecode.h" -#include -#ifdef MACOSX -#include -#else -#include -#endif -#include -#include "pserror.h" -#include "byteswap.h" -using namespace AudioDecoder; - -namespace { - -// Constants -const uint32 kBitBufferSize = 64 * 1024; -const uint32 kNumAmpSamples = 64 * 1024; -const uint32 kACMId = 0x032897; -const uint32 kACMVersion = 1; - -// Internal Classes -struct ACMInfo { - uint32 m_id; - uint32 m_version; - uint32 m_sampleCount; - uint32 m_numChannels; - uint32 m_sampleRate; - uint32 m_level; - uint32 m_columns; - uint32 m_rows; -}; - -class InternalAudioDecoder : public IAudioDecoder { -public: - InternalAudioDecoder(ReadDataFunction readerFunction, void *pReaderData); - ~InternalAudioDecoder(); - - // Extract the header information - const ACMInfo &GetHeader() const { return m_acm; } - - // Initialize the decoder - bool Initialize(); - - // Read data from the audio decoder. - // pBuffer: The buffer to receive the data from - // amount: How much data to read - // Returns the number of bytes read - zero when we're at the end of the file - uint32 Read(void *pBuffer, uint32 amount); - - // Unpackers - static bool UnpackZeroFill(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackIgnore(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackLinear(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK13(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK12(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK24(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK23(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK35(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK34(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK45(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackK44(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackT15(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackT27(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - static bool UnpackT37(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); - -private: - // Read data from the read function - sint32 ReadData(void *pBuffer, uint32 amount); - uint32 InternalRead(void *pBuffer, uint32 amount); - - bool LoadBitBufferFromFile(); - bool LoadBitBuffer(); - bool ReloadBits(uint32 bits, uint32 &newData, bool &hitEOF); - bool GetBits(uint32 bits, uint32 &resultData); - bool GetBitsEOF(uint32 bits, uint32 &resultData, bool &hadEOF); - - bool DecodeBlock(bool &atEOF); - bool UnpackBlock(bool &atEOF); - void OutputValues(const sint32 *pSrcData, void *pBuffer, uint32 numWords); - - void JuggleBlock(); - - ACMInfo m_acm; - ReadDataFunction m_readerFunction; - void *m_pReaderData; - - uint8 *m_pFileBitBuffer; - uint32 m_bitBufferAvailableSize; - uint32 m_bitBufferCurrPos; - uint32 m_numBitsAvailable; - uint32 m_bitData; - - uint32 m_blockLengthInSamples; - uint32 m_wrapBufferLength; - sint32 *m_pBlock; - sint32 *m_pWrapBuffer; - sint32 *m_pAmpBuffer; - sint32 *m_pMidBuffer; - - bool m_blockReady; - bool m_bitBufferAtEOF; - uint32 m_streamPos; - uint32 m_blockPos; - - // Memory management - void *m_pMemoryBuffer; -}; - -// Tables -const sint32 gMap1Bit[] = {-1, +1}; -const sint32 gMap2BitNear[] = {-2, -1, +1, +2}; -const sint32 gMap2BitFar[] = {-3, -2, +2, +3}; -const sint32 gMap3Bit[] = {-4, -3, -2, -1, +1, +2, +3, +4}; - -const uint16 gMul3x3[27] = { - 0x0000, 0x0001, 0x0002, 0x0010, 0x0011, 0x0012, 0x0020, 0x0021, 0x0022, 0x0100, 0x0101, 0x0102, 0x0110, 0x0111, - 0x0112, 0x0120, 0x0121, 0x0122, 0x0200, 0x0201, 0x0202, 0x0210, 0x0211, 0x0212, 0x0220, 0x0221, 0x0222, -}; - -const uint16 gMul3x5[125] = { - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0020, 0x0021, 0x0022, 0x0023, - 0x0024, 0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0100, 0x0101, 0x0102, - 0x0103, 0x0104, 0x0110, 0x0111, 0x0112, 0x0113, 0x0114, 0x0120, 0x0121, 0x0122, 0x0123, 0x0124, 0x0130, 0x0131, - 0x0132, 0x0133, 0x0134, 0x0140, 0x0141, 0x0142, 0x0143, 0x0144, 0x0200, 0x0201, 0x0202, 0x0203, 0x0204, 0x0210, - 0x0211, 0x0212, 0x0213, 0x0214, 0x0220, 0x0221, 0x0222, 0x0223, 0x0224, 0x0230, 0x0231, 0x0232, 0x0233, 0x0234, - 0x0240, 0x0241, 0x0242, 0x0243, 0x0244, 0x0300, 0x0301, 0x0302, 0x0303, 0x0304, 0x0310, 0x0311, 0x0312, 0x0313, - 0x0314, 0x0320, 0x0321, 0x0322, 0x0323, 0x0324, 0x0330, 0x0331, 0x0332, 0x0333, 0x0334, 0x0340, 0x0341, 0x0342, - 0x0343, 0x0344, 0x0400, 0x0401, 0x0402, 0x0403, 0x0404, 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0420, 0x0421, - 0x0422, 0x0423, 0x0424, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, -}; - -const uint8 gMul2x11[121] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0x1A, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x30, 0x31, 0x32, - 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, - 0x4A, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, - 0x66, 0x67, 0x68, 0x69, 0x6A, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x80, 0x81, - 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, - 0x99, 0x9A, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA}; -} // namespace - -/**************************************************************/ -/* Interface Functions */ -/**************************************************************/ - -// Create an audio decoder -// You supply a function for reading bytes from the compressed data via a -// void* pData handle, and the handle itself (typically a FILE *). -// Create_AudioDecoder returns a new AudioDecoder which can be used to -// read uncompressed decoded data from the compressed stream, -// and also returns the number of channels (1 or 2), the sample rate -// (e.g. 22050), and the number of samples contained in the compressed file -// (in case you want to pre-allocate a buffer to load them all into memory). -IAudioDecoder *AudioDecoder::CreateDecoder(ReadDataFunction readerFunction, void *pReaderData, uint32 &numChannels, - uint32 &sampleRate, uint32 &sampleCount) { - // allocate our decoder - InternalAudioDecoder *pDecoder = new InternalAudioDecoder(readerFunction, pReaderData); - if (pDecoder == NULL) - return NULL; - - // initialize - if (!pDecoder->Initialize()) { - // Failed - delete pDecoder; - return NULL; - } - - // extract the header information for the caller - const ACMInfo &header = pDecoder->GetHeader(); - numChannels = header.m_numChannels; - sampleRate = header.m_sampleRate; - sampleCount = header.m_sampleCount; - - // return the decoder back to the user - return pDecoder; -} - -/**************************************************************/ -/* Construction */ -/**************************************************************/ - -InternalAudioDecoder::InternalAudioDecoder(ReadDataFunction readerFunction, void *pReaderData) - : m_readerFunction(readerFunction), m_pReaderData(pReaderData), m_pFileBitBuffer(NULL), m_bitBufferAvailableSize(0), - m_bitBufferCurrPos(0), m_numBitsAvailable(0), m_bitData(0), m_blockLengthInSamples(0), m_wrapBufferLength(0), - m_pBlock(NULL), m_pWrapBuffer(NULL), m_pAmpBuffer(NULL), m_pMidBuffer(NULL), m_blockReady(false), - m_bitBufferAtEOF(false), m_streamPos(0), m_blockPos(0), m_pMemoryBuffer(NULL) { - std::memset(&m_acm, 0, sizeof(m_acm)); -} - -// Initialize the decoder -bool InternalAudioDecoder::Initialize() { - // Allocate the bit buffer before we start reading it - m_pFileBitBuffer = reinterpret_cast(malloc(kBitBufferSize)); - if (!m_pFileBitBuffer) - return false; - - // Read in the ACM header - if (!GetBits(24, m_acm.m_id)) - return false; - if (m_acm.m_id != kACMId) - return false; - if (!GetBits(8, m_acm.m_version)) - return false; - if (m_acm.m_version != kACMVersion) - return false; - - // total value count - uint32 temp; - if (!GetBits(16, m_acm.m_sampleCount)) - return false; - if (!GetBits(16, temp)) - return false; - m_acm.m_sampleCount += temp << 16; - - if (m_acm.m_sampleCount == 0) - return false; - - // num channels - if (!GetBits(16, m_acm.m_numChannels)) - return false; - - if (m_acm.m_numChannels < 1 || m_acm.m_numChannels > 2) - return false; - - // sample rate - if (!GetBits(16, m_acm.m_sampleRate)) - return false; - - if (m_acm.m_sampleRate < 4096) - return false; - - // level - if (!GetBits(4, m_acm.m_level)) - return false; - - // rows - if (!GetBits(12, m_acm.m_rows)) - return false; - - if (m_acm.m_rows == 0) - return false; - - // Calculate the blocks - m_acm.m_columns = 1 << m_acm.m_level; - m_wrapBufferLength = 2 * m_acm.m_columns - 2; - m_blockLengthInSamples = m_acm.m_rows * m_acm.m_columns; - - // Calculate the amount of memory that needs to be allocated - const size_t blockMemSize = m_blockLengthInSamples * sizeof(uint32); - const size_t wrapMemSize = m_wrapBufferLength * sizeof(uint32); - const size_t ampMemSize = kNumAmpSamples * sizeof(uint32); - const size_t totalMemSize = blockMemSize + wrapMemSize + ampMemSize; - m_pMemoryBuffer = malloc(static_cast(totalMemSize)); - if (m_pMemoryBuffer == NULL) - return false; - - // Assign buffer pointers - m_pBlock = reinterpret_cast(m_pMemoryBuffer); - m_pWrapBuffer = reinterpret_cast(m_pBlock + m_blockLengthInSamples); - m_pAmpBuffer = reinterpret_cast(m_pWrapBuffer + m_wrapBufferLength); - m_pMidBuffer = reinterpret_cast(m_pAmpBuffer + (kNumAmpSamples >> 1)); - - // Initialize data buffers - std::memset(m_pWrapBuffer, 0, m_wrapBufferLength * sizeof(uint32)); - - // Lets get going - return true; -} - -/**************************************************************/ -/* Destruction */ -/**************************************************************/ - -InternalAudioDecoder::~InternalAudioDecoder() { - if (m_pMemoryBuffer) { - free(m_pMemoryBuffer); - } - - if (m_pFileBitBuffer) { - free(m_pFileBitBuffer); - } -} - -/**************************************************************/ -/* Reading */ -/**************************************************************/ - -// Read data from the audio decoder. -// pBuffer: The buffer to receive the data from -// amount: How much data to read -// Returns the number of bytes read - zero when we're at the end of the file -uint32 InternalAudioDecoder::Read(void *pBuffer, uint32 amount) { - uint32 totalBytesRead = 0; - uint8 *pBuf = reinterpret_cast(pBuffer); - - do { - uint32 numWords = amount >> 1; - if (m_streamPos + numWords > m_acm.m_sampleCount) { - // Don't read past the end of file - numWords = m_acm.m_sampleCount - m_streamPos; - } - - if (m_acm.m_numChannels > 1) { - // Read full channel data - numWords -= numWords & 1; - } - - if (numWords == 0) - break; - - uint32 res = InternalRead(pBuf, numWords << 1); - if (res == 0) - break; - - pBuf += res; - amount -= res; - totalBytesRead += res; - } while (amount > 0); - - return totalBytesRead; -} - -uint32 InternalAudioDecoder::InternalRead(void *pBuffer, uint32 amount) { - // Check for End-of-File - if (m_streamPos >= m_acm.m_sampleCount) - return 0; - - uint32 numWords = amount >> 1; - if (!m_blockReady) { - bool atEOF; - if (!DecodeBlock(atEOF)) { - // TODO: Report proper error? - return atEOF ? 0 : 0; - } - } - - uint32 numAvailableWords = m_blockLengthInSamples - m_blockPos; - if (numAvailableWords < numWords) { - // Don't read too past the end of the block - numWords = numAvailableWords; - } - - if (m_streamPos + numWords > m_acm.m_sampleCount) { - // Don't read past the end of file - numWords = m_acm.m_sampleCount - m_streamPos; - } - - if (m_acm.m_numChannels > 1) { - // Read full channel data - numWords -= numWords & 1; - } - - const sint32 *pSrcData = m_pBlock + m_blockPos; - OutputValues(pSrcData, pBuffer, numWords); - - m_streamPos += numWords; - m_blockPos += numWords; - if (m_blockPos == m_blockLengthInSamples) { - m_blockReady = false; - } - - return numWords << 1; -} - -/**************************************************************/ -/* Output */ -/**************************************************************/ - -void InternalAudioDecoder::OutputValues(const sint32 *pSrcData, void *pBuffer, uint32 numWords) { - uint8 *pDst = reinterpret_cast(pBuffer); - - const uint32 shiftAmount = m_acm.m_level; - while (numWords--) { - sint32 src = *pSrcData++; - sint32 val = INTEL_INT(src) >> shiftAmount; - *pDst++ = val & 0xFF; - *pDst++ = (val >> 8) & 0xFF; - } -} - -/**************************************************************/ -/* Decoding */ -/**************************************************************/ - -bool InternalAudioDecoder::DecodeBlock(bool &atEOF) { - // Reset block state - m_blockReady = false; - m_blockPos = 0; - - // Read in data - uint32 bitPower; - if (!GetBitsEOF(4, bitPower, atEOF)) - return false; - - uint32 bitValue; - if (!GetBitsEOF(16, bitValue, atEOF)) - return false; - - // Process - sint32 x; - uint32 i, count = 1 << bitPower; - for (i = 0, x = 0; i < count; ++i) { - m_pMidBuffer[i] = x; - x += bitValue; - } - - for (i = 1, x = -static_cast(bitValue); i <= count; ++i) { - m_pMidBuffer[-static_cast(i)] = x; - x -= bitValue; - } - - if (!UnpackBlock(atEOF)) - return false; - - JuggleBlock(); - - m_blockReady = true; - return true; -} - -static void Juggle(sint32 *pWrap, sint32 *pBlock, uint32 subLen, uint32 subCount) { - for (uint32 i = 0; i < subLen; ++i) { - sint32 *pPtr = pBlock; - sint32 r0 = pWrap[0]; - sint32 r1 = pWrap[1]; - - uint32 cnt = subCount >> 1; - for (uint32 j = 0; j < cnt; ++j) { - sint32 r2 = *pPtr; - *pPtr = (r1 << 1) + (r0 + r2); - pPtr += subLen; - sint32 r3 = *pPtr; - *pPtr = (r2 << 1) - (r1 + r3); - pPtr += subLen; - - r0 = r2; - r1 = r3; - } - - *pWrap++ = r0; - *pWrap++ = r1; - ++pBlock; - } -} - -void InternalAudioDecoder::JuggleBlock() { - // check subblock length - if (m_acm.m_level == 0) - return; - - // Apply juggle() (rows)x(cols) - // from (step_subcount * 2) x (subblock_len/2) - // to (step_subcount * subblock_len) x (1) - const uint32 stepSubCount = (m_acm.m_level > 9) ? 1 : ((2048 >> m_acm.m_level) - 2); - uint32 todoCount = m_acm.m_rows; - sint32 *pBlock = m_pBlock; - while (true) { - sint32 *pWrap = m_pWrapBuffer; - uint32 subCount = stepSubCount; - if (subCount > todoCount) { - subCount = todoCount; - } - - uint32 subLen = m_acm.m_columns >> 1; - subCount <<= 1; - - Juggle(pWrap, pBlock, subLen, subCount); - pWrap += subLen << 1; - - uint32 i; - sint32 *pPtr; - for (i = 0, pPtr = pBlock; i < subCount; ++i) { - ++pPtr[0]; - pPtr += subLen; - } - - while (subLen > 1) { - subLen >>= 1; - subCount <<= 1; - Juggle(pWrap, pBlock, subLen, subCount); - pWrap += subLen << 1; - } - - if (todoCount <= stepSubCount) - break; - - todoCount -= stepSubCount; - pBlock += stepSubCount << m_acm.m_level; - } -} - -/**************************************************************/ -/* Unpacking */ -/**************************************************************/ - -bool InternalAudioDecoder::UnpackZeroFill(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - const sint32 midZero = decoder.m_pMidBuffer[0]; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - const uint32 pos = (i << level) + col; - pBlock[pos] = midZero; - } - - return true; -} - -bool InternalAudioDecoder::UnpackIgnore(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - return true; -} - -bool InternalAudioDecoder::UnpackLinear(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 middleIndex = 1 << (id - 1); - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(id, offset, atEOF)) - return false; - - const uint32 pos = (i << level) + col; - pBlock[pos] = decoder.m_pMidBuffer[offset - middleIndex]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK13(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 flag; - if (!decoder.GetBitsEOF(1, flag, atEOF)) - return false; - - if (flag == 0) { - pBlock[(i++ << level) + col] = midZero; - if (i >= numRows) - break; - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, flag, atEOF)) - return false; - - if (flag == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, flag, atEOF)) - return false; - - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap1Bit[flag]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK12(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - - if (offset == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap1Bit[offset]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK24(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - - if (offset == 0) { - pBlock[(i++ << level) + col] = midZero; - if (i >= numRows) - break; - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(2, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap2BitNear[offset]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK23(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - - if (offset == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(2, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap2BitNear[offset]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK35(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - - if (offset == 0) { - pBlock[(i++ << level) + col] = midZero; - if (i >= numRows) - break; - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap1Bit[offset]]; - continue; - } - - if (!decoder.GetBitsEOF(2, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap2BitFar[offset]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK34(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap1Bit[offset]]; - continue; - } - - if (!decoder.GetBitsEOF(2, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap2BitFar[offset]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK45(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - pBlock[(i++ << level) + col] = midZero; - if (i >= numRows) - break; - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(3, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap3Bit[offset]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackK44(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const sint32 midZero = decoder.m_pMidBuffer[0]; - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(1, offset, atEOF)) - return false; - if (offset == 0) { - pBlock[(i << level) + col] = midZero; - continue; - } - - if (!decoder.GetBitsEOF(3, offset, atEOF)) - return false; - pBlock[(i << level) + col] = decoder.m_pMidBuffer[gMap3Bit[offset]]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackT15(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(5, offset, atEOF)) - return false; - - uint32 n1 = (gMul3x3[offset] & 0x0F) - 1; - uint32 n2 = ((gMul3x3[offset] >> 4) & 0x0F) - 1; - uint32 n3 = ((gMul3x3[offset] >> 8) & 0x0F) - 1; - - pBlock[(i++ << level) + col] = decoder.m_pMidBuffer[n1]; - if (i >= numRows) - break; - - pBlock[(i++ << level) + col] = decoder.m_pMidBuffer[n2]; - if (i >= numRows) - break; - - pBlock[(i << level) + col] = decoder.m_pMidBuffer[n3]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackT27(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(7, offset, atEOF)) - return false; - - uint32 n1 = (gMul3x5[offset] & 0x0F) - 2; - uint32 n2 = ((gMul3x5[offset] >> 4) & 0x0F) - 2; - uint32 n3 = ((gMul3x5[offset] >> 8) & 0x0F) - 2; - - pBlock[(i++ << level) + col] = decoder.m_pMidBuffer[n1]; - if (i >= numRows) - break; - - pBlock[(i++ << level) + col] = decoder.m_pMidBuffer[n2]; - if (i >= numRows) - break; - - pBlock[(i << level) + col] = decoder.m_pMidBuffer[n3]; - } - - return true; -} - -bool InternalAudioDecoder::UnpackT37(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF) { - const uint32 numRows = decoder.m_acm.m_rows; - const uint32 level = decoder.m_acm.m_level; - sint32 *pBlock = decoder.m_pBlock; - - for (uint32 i = 0; i < numRows; ++i) { - uint32 offset; - if (!decoder.GetBitsEOF(7, offset, atEOF)) - return false; - - uint32 n1 = (gMul2x11[offset] & 0x0F) - 5; - uint32 n2 = ((gMul2x11[offset] >> 4) & 0x0F) - 5; - - pBlock[(i++ << level) + col] = decoder.m_pMidBuffer[n1]; - if (i >= numRows) - break; - - pBlock[(i << level) + col] = decoder.m_pMidBuffer[n2]; - } - - return true; -} - -typedef bool (*UnpackerFunction)(InternalAudioDecoder &decoder, uint32 id, uint32 col, bool &atEOF); -static const UnpackerFunction Unpacker[] = { - InternalAudioDecoder::UnpackZeroFill, InternalAudioDecoder::UnpackIgnore, InternalAudioDecoder::UnpackIgnore, - InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, - InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, - InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, - InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, - InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackLinear, InternalAudioDecoder::UnpackK13, - InternalAudioDecoder::UnpackK12, InternalAudioDecoder::UnpackT15, InternalAudioDecoder::UnpackK24, - InternalAudioDecoder::UnpackK23, InternalAudioDecoder::UnpackT27, InternalAudioDecoder::UnpackK35, - InternalAudioDecoder::UnpackK34, InternalAudioDecoder::UnpackIgnore, InternalAudioDecoder::UnpackK45, - InternalAudioDecoder::UnpackK44, InternalAudioDecoder::UnpackIgnore, InternalAudioDecoder::UnpackT37, - InternalAudioDecoder::UnpackIgnore, InternalAudioDecoder::UnpackIgnore, -}; - -bool InternalAudioDecoder::UnpackBlock(bool &atEOF) { - for (uint32 i = 0; i < m_acm.m_columns; ++i) { - uint32 unpackerId; - if (!GetBitsEOF(5, unpackerId, atEOF)) - return false; - - // Jump to the unpacker - if (!Unpacker[unpackerId](*this, unpackerId, i, atEOF)) - return false; - } - - return true; -} - -/**************************************************************/ -/* Loading Data */ -/**************************************************************/ - -bool InternalAudioDecoder::LoadBitBufferFromFile() { - if (m_bitBufferAtEOF) - return true; - - // Callback to the user to get more data - sint32 res = m_readerFunction(m_pReaderData, m_pFileBitBuffer, kBitBufferSize); - if (res < 0) - return false; - - if (res == 0) { - // No more data - m_bitBufferAtEOF = true; - m_pFileBitBuffer[0] = 0; - m_bitBufferAvailableSize = 1; - } else { - // We still have data - m_bitBufferAvailableSize = static_cast(res); - } - - m_bitBufferCurrPos = 0; - return true; -} - -bool InternalAudioDecoder::LoadBitBuffer() { - uint32 numLoadedBits = 0; // How many bits are still available - uint32 loadedDataBits = 0; // The bit data still available - - // How many bytes of data remain? - const uint32 bufferRemaining = m_bitBufferAvailableSize - m_bitBufferCurrPos; - ASSERT(bufferRemaining < 4); - - // Bring in the remaining bits from the buffer - const uint8 *pCurrBuffer = m_pFileBitBuffer + m_bitBufferCurrPos; - switch (bufferRemaining) { - case 3: - loadedDataBits += pCurrBuffer[2] << 16; - case 2: - loadedDataBits += pCurrBuffer[1] << 8; - case 1: - loadedDataBits += pCurrBuffer[0]; - } - numLoadedBits = bufferRemaining << 3; - - // Fill back up the file buffer - if (!LoadBitBufferFromFile()) - return false; - - // Bring in the rest of the bits that we can to fill up the 32 bits (or - // when we run out of available buffer) - while (numLoadedBits < 32) { - if (m_bitBufferAvailableSize - m_bitBufferCurrPos == 0) - break; - - // Bring in the next byte - loadedDataBits |= m_pFileBitBuffer[m_bitBufferCurrPos] << numLoadedBits; - numLoadedBits += 8; - ++m_bitBufferCurrPos; - } - - // Continue with processing - m_bitData = loadedDataBits; - m_numBitsAvailable = numLoadedBits; - return true; -} - -// Reloads the available bits back to a full 32 -bool InternalAudioDecoder::ReloadBits(uint32 bits, uint32 &newData, bool &hitEOF) { - ASSERT(bits > m_numBitsAvailable); - hitEOF = false; - - // Bring in the bits that we can - uint32 currBitData = m_bitData; - uint32 numLoadedBits = m_numBitsAvailable; - bits -= numLoadedBits; - - // Bring in more bits from the buffer - uint32 bitData, bitsAvail; - if ((m_bitBufferAvailableSize - m_bitBufferCurrPos) >= 4) { - // We have a full 32bits available - uint8 *pCurrBuffer = m_pFileBitBuffer + m_bitBufferCurrPos; - m_bitBufferCurrPos += 4; - bitData = pCurrBuffer[0] + (pCurrBuffer[1] << 8) + (pCurrBuffer[2] << 16) + (pCurrBuffer[3] << 24); - bitsAvail = 32; - } else { - // We're almost out of buffer space - fill it back up - if (!LoadBitBuffer()) - return false; - - if (m_numBitsAvailable < bits) { - // Unexpected EOF - hitEOF = true; - return false; - } - - bitData = m_bitData; - bitsAvail = m_numBitsAvailable; - } - - // Fold in the bits necessary to fill back up - currBitData |= (bitData & ((1 << bits) - 1)) << numLoadedBits; - m_bitData = bitData >> bits; - m_numBitsAvailable = bitsAvail - bits; - newData = currBitData; - return true; -} - -/**************************************************************/ -/* Data Retrieval */ -/**************************************************************/ - -bool InternalAudioDecoder::GetBits(uint32 bits, uint32 &resultData) { - if (m_numBitsAvailable >= bits) { - // We have enough data to pull from - resultData = m_bitData & ((1 << bits) - 1); - m_bitData >>= bits; - m_numBitsAvailable -= bits; - return true; - } - - // Reload our bitData - bool hadEOF; - bool res = ReloadBits(bits, resultData, hadEOF); - ASSERT(!hadEOF); - return res; -} - -bool InternalAudioDecoder::GetBitsEOF(uint32 bits, uint32 &resultData, bool &hadEOF) { - if (m_numBitsAvailable >= bits) { - // We have enough data to pull from - resultData = m_bitData & ((1 << bits) - 1); - m_bitData >>= bits; - m_numBitsAvailable -= bits; - return true; - } - - // Reload our bitData - return ReloadBits(bits, resultData, hadEOF); -}