mirror of
https://github.com/kevinbentley/Descent3.git
synced 2026-04-03 17:00:03 -04:00
1220 lines
35 KiB
C++
1220 lines
35 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
|
|
};
|
|
}
|
|
|
|
/**************************************************************/
|
|
/* 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 );
|
|
}
|