mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-01-22 19:55:23 +00:00
9e6ebbc8fb
Linux-specific byteswap.h just includes BYTESWAP.H, so there no need platform-specific header. Fixes "non-portable path to file" ([-Wnonportable-include-path]) warnings.
1090 lines
34 KiB
C++
1090 lines
34 KiB
C++
// 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 <stdlib.h>
|
|
#ifdef MACOSX
|
|
#include <sys/malloc.h>
|
|
#else
|
|
#include <malloc.h>
|
|
#endif
|
|
#include <cstring>
|
|
#include "pserror.h"
|
|
#include "byteswap.h"
|
|
using namespace AudioDecoder;
|
|
|
|
namespace {
|
|
// default memory allocation function
|
|
void *DefaultMalloc(uint32 size) { return malloc(size); }
|
|
|
|
// default memory release function
|
|
void DefaultFree(void *pPtr) { free(pPtr); }
|
|
|
|
// 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);
|
|
|
|
// Operator overloads
|
|
void *operator new(size_t numBytes);
|
|
void operator delete(void *pPtr);
|
|
|
|
// 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);
|
|
|
|
static void SetMemoryFunctions(MemoryAllocFunc memAlloc, MemoryFreeFunc memFree);
|
|
|
|
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;
|
|
static MemoryAllocFunc s_Malloc;
|
|
static MemoryFreeFunc s_Free;
|
|
};
|
|
|
|
// 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 */
|
|
/**************************************************************/
|
|
|
|
// Optional interface for supplying your own malloc and free functions
|
|
// Default is to use standard malloc and free.
|
|
void RegisterMemoryFunctions(MemoryAllocFunc memAlloc, MemoryFreeFunc memFree) {
|
|
InternalAudioDecoder::SetMemoryFunctions(memAlloc, memFree);
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
|
|
/**************************************************************/
|
|
/* Memory Management */
|
|
/**************************************************************/
|
|
|
|
// Static memory
|
|
MemoryAllocFunc InternalAudioDecoder::s_Malloc = DefaultMalloc;
|
|
MemoryFreeFunc InternalAudioDecoder::s_Free = DefaultFree;
|
|
|
|
void InternalAudioDecoder::SetMemoryFunctions(MemoryAllocFunc memAlloc, MemoryFreeFunc memFree) {
|
|
if ((memAlloc && !memFree) || (!memAlloc && memFree))
|
|
return;
|
|
|
|
s_Malloc = (memAlloc) ? memAlloc : DefaultMalloc;
|
|
s_Free = (memFree) ? memFree : DefaultFree;
|
|
}
|
|
|
|
void *InternalAudioDecoder::operator new(size_t numBytes) { return s_Malloc(static_cast<uint32>(numBytes)); }
|
|
|
|
void InternalAudioDecoder::operator delete(void *pPtr) {
|
|
if (pPtr) {
|
|
s_Free(pPtr);
|
|
}
|
|
}
|
|
|
|
/**************************************************************/
|
|
/* 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<uint8 *>(s_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 = s_Malloc(static_cast<uint32>(totalMemSize));
|
|
if (m_pMemoryBuffer == NULL)
|
|
return false;
|
|
|
|
// Assign buffer pointers
|
|
m_pBlock = reinterpret_cast<sint32 *>(m_pMemoryBuffer);
|
|
m_pWrapBuffer = reinterpret_cast<sint32 *>(m_pBlock + m_blockLengthInSamples);
|
|
m_pAmpBuffer = reinterpret_cast<sint32 *>(m_pWrapBuffer + m_wrapBufferLength);
|
|
m_pMidBuffer = reinterpret_cast<sint32 *>(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) {
|
|
s_Free(m_pMemoryBuffer);
|
|
}
|
|
|
|
if (m_pFileBitBuffer) {
|
|
s_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<uint8 *>(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<uint8 *>(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<sint32>(bitValue); i <= count; ++i) {
|
|
m_pMidBuffer[-static_cast<sint32>(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<uint32>(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);
|
|
}
|