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);
-}