refactored WAV decoder

This commit is contained in:
Silent 2017-03-03 21:20:30 +01:00
parent 1b4859ac25
commit 0a439cc963
4 changed files with 99 additions and 165 deletions

View file

@ -6,12 +6,6 @@ bool CAEDataStream::m_bUseNewStruct;
static void* CAEDataStream__Initialise = AddressByVersion<void*>(0x4DC2B0, 0x4DC7A0, 0x4E7550); static void* CAEDataStream__Initialise = AddressByVersion<void*>(0x4DC2B0, 0x4DC7A0, 0x4E7550);
WRAPPER bool CAEDataStream::Initialise() { VARJMP(CAEDataStream__Initialise); } WRAPPER bool CAEDataStream::Initialise() { VARJMP(CAEDataStream__Initialise); }
unsigned int CAEStreamingDecoder::nMallocRefCount = 0;
void* pMalloc = nullptr;
unsigned int nBlockSize = 0;
unsigned int nLastMallocSize = 0;
DWORD CAEDataStreamOld::Seek(LONG nToSeek, DWORD nPoint) DWORD CAEDataStreamOld::Seek(LONG nToSeek, DWORD nPoint)
{ {
LARGE_INTEGER filePosition; LARGE_INTEGER filePosition;
@ -78,12 +72,4 @@ CAEStreamingDecoder::~CAEStreamingDecoder()
delete reinterpret_cast<CAEDataStreamNew*>(pStream); delete reinterpret_cast<CAEDataStreamNew*>(pStream);
else else
delete reinterpret_cast<CAEDataStreamOld*>(pStream); delete reinterpret_cast<CAEDataStreamOld*>(pStream);
if ( --nMallocRefCount == 0 )
{
operator delete(pMalloc);
pMalloc = nullptr;
nLastMallocSize = 0;
}
} }

View file

@ -223,14 +223,10 @@ class CAEStreamingDecoder
private: private:
CAEDataStream* pStream; CAEDataStream* pStream;
static unsigned int nMallocRefCount;
public: public:
CAEStreamingDecoder(CAEDataStream* stream) CAEStreamingDecoder(CAEDataStream* stream)
: pStream(stream) : pStream(stream)
{ {
++nMallocRefCount;
if ( stream != nullptr ) if ( stream != nullptr )
stream->Initialise(); stream->Initialise();
} }

View file

@ -1,27 +1,23 @@
#include "StdAfxSA.h" #include "StdAfxSA.h"
#include "WaveDecoderSA.h" #include "WaveDecoderSA.h"
extern void* pMalloc;
extern unsigned int nBlockSize;
extern unsigned int nLastMallocSize;
bool CAEWaveDecoder::Initialise() bool CAEWaveDecoder::Initialise()
{ {
auto* pTheStream = GetStream(); CAEDataStream* pTheStream = GetStream();
struct { struct {
char sectionID[4]; char sectionID[4];
unsigned int sectionSize; uint32_t sectionSize;
} chunkHeader; } chunkHeader;
// Find fmt section // Find fmt section
pTheStream->Seek(12, FILE_BEGIN); pTheStream->Seek(12, FILE_BEGIN);
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
nOffsetToData = 12 + sizeof(chunkHeader); m_offsetToData = 12 + sizeof(chunkHeader);
while ( chunkHeader.sectionID[0] != 'f' || chunkHeader.sectionID[1] != 'm' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != ' ' ) while ( chunkHeader.sectionID[0] != 'f' || chunkHeader.sectionID[1] != 'm' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != ' ' )
{ {
nOffsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize; m_offsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize;
pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT); pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT);
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
@ -29,171 +25,118 @@ bool CAEWaveDecoder::Initialise()
} }
// Read fmt header // Read fmt header
pTheStream->FillBuffer(&formatChunk, sizeof(FormatChunk)); pTheStream->FillBuffer(&m_formatChunk, sizeof(m_formatChunk));
nOffsetToData += sizeof(FormatChunk); m_offsetToData += sizeof(m_formatChunk);
// Now skip through the rest of a chunk // Now skip through the rest of a chunk
if ( chunkHeader.sectionSize - sizeof(FormatChunk) > 0 ) if ( chunkHeader.sectionSize - sizeof(m_formatChunk) > 0 )
{ {
nOffsetToData += chunkHeader.sectionSize - sizeof(FormatChunk); m_offsetToData += chunkHeader.sectionSize - sizeof(m_formatChunk);
pTheStream->Seek(chunkHeader.sectionSize - sizeof(FormatChunk), FILE_CURRENT); pTheStream->Seek(chunkHeader.sectionSize - sizeof(m_formatChunk), FILE_CURRENT);
} }
// Find data chunk // Find data chunk
nOffsetToData += sizeof(chunkHeader); m_offsetToData += sizeof(chunkHeader);
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
while ( chunkHeader.sectionID[0] != 'd' || chunkHeader.sectionID[1] != 'a' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != 'a' ) while ( chunkHeader.sectionID[0] != 'd' || chunkHeader.sectionID[1] != 'a' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != 'a' )
{ {
nOffsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize; m_offsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize;
pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT); pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT);
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
} }
nDataSize = chunkHeader.sectionSize; m_dataSize = chunkHeader.sectionSize;
return formatChunk.sampleRate <= 48000 && formatChunk.numChannels <= 2 && (formatChunk.bitsPerSample == 8 || formatChunk.bitsPerSample == 16 || formatChunk.bitsPerSample == 24); return m_formatChunk.sampleRate <= 48000 && m_formatChunk.numChannels <= 2 && (m_formatChunk.bitsPerSample == 8 || m_formatChunk.bitsPerSample == 16 || m_formatChunk.bitsPerSample == 24);
} }
uint32_t CAEWaveDecoder::FillBuffer(void* pBuf, uint32_t nLen) uint32_t CAEWaveDecoder::FillBuffer(void* pBuf, uint32_t nLen)
{ {
if ( formatChunk.bitsPerSample == 8 ) size_t curBlockSize = CalcBufferSize( nLen );
if ( curBlockSize > m_maxBlockSize )
{ {
if ( formatChunk.numChannels == 2 ) delete[] m_buffer;
m_buffer = new uint8_t[curBlockSize];
m_maxBlockSize = curBlockSize;
}
else if ( curBlockSize == 0 )
{
return GetStream()->FillBuffer( pBuf, nLen );
}
uint32_t bytesRead = GetStream()->FillBuffer( m_buffer, curBlockSize );
size_t samplesRead = bytesRead / m_formatChunk.blockAlign;
if ( m_formatChunk.bitsPerSample == 16 )
{
assert( m_formatChunk.numChannels == 1 );
if ( m_formatChunk.numChannels == 1 )
{ {
// Stereo int16_t* inputBuf = (int16_t*)m_buffer;
if ( nLen / 2 > nLastMallocSize ) int16_t* outputBuf = (int16_t*)pBuf;
for ( size_t i = 0; i < samplesRead; ++i )
{ {
if ( pMalloc ) *outputBuf = *(outputBuf+1) = *inputBuf++;
operator delete(pMalloc); outputBuf += 2;
nLastMallocSize = nLen / 2;
pMalloc = operator new(nLastMallocSize);
} }
unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen / 2); }
signed short* pOutBuf = static_cast<signed short*>(pBuf); }
unsigned char* pInBuf = static_cast<unsigned char*>(pMalloc); else if ( m_formatChunk.bitsPerSample == 8 )
{
// Convert to 16-bit if ( m_formatChunk.numChannels == 2 )
for ( unsigned int i = 0; i < nBytesWritten; i++ ) {
uint8_t* inputBuf = (uint8_t*)m_buffer;
int16_t* outputBuf = (int16_t*)pBuf;
for ( size_t i = 0; i < samplesRead; ++i )
{ {
pOutBuf[i] = (static_cast<signed char>(pInBuf[i]) - 128) << 8; *outputBuf++ = (static_cast<signed char>(*inputBuf++) - 128) << 8;
*outputBuf++ = (static_cast<signed char>(*inputBuf++) - 128) << 8;
} }
return nBytesWritten * 2;
} }
else else
{ {
// Mono uint8_t* inputBuf = (uint8_t*)m_buffer;
if ( nLen / 4 > nLastMallocSize ) int16_t* outputBuf = (int16_t*)pBuf;
for ( size_t i = 0; i < samplesRead; ++i )
{ {
if ( pMalloc ) *outputBuf = *(outputBuf+1) = (static_cast<signed char>(*inputBuf++) - 128) << 8;
operator delete(pMalloc); outputBuf += 2;
nLastMallocSize = nLen / 4;
pMalloc = operator new(nLastMallocSize);
} }
unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen / 4);
signed short* pOutBuf = static_cast<signed short*>(pBuf);
unsigned char* pInBuf = static_cast<unsigned char*>(pMalloc);
// Convert to 16-bit
for ( unsigned int i = 0; i < nBytesWritten; i++ )
{
pOutBuf[i * 2] = pOutBuf[i * 2 + 1] = (static_cast<signed char>(pInBuf[i]) - 128) << 8;
}
return nBytesWritten * 4;
} }
} }
else if ( formatChunk.bitsPerSample == 24 ) else if ( m_formatChunk.bitsPerSample == 24 )
{ {
if ( formatChunk.numChannels == 2 ) if ( m_formatChunk.numChannels == 2 )
{ {
// Stereo uint8_t* inputBuf = (uint8_t*)m_buffer;
if ( nLen * 3 / 2 > nLastMallocSize ) int16_t* outputBuf = (int16_t*)pBuf;
for ( size_t i = 0; i < samplesRead; ++i )
{ {
if ( pMalloc ) *outputBuf++ = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3;
operator delete(pMalloc); *outputBuf++ = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3;
nLastMallocSize = nLen * 3 / 2;
pMalloc = operator new(nLastMallocSize);
} }
unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen * 3 / 2);
unsigned char* pOutBuf = static_cast<unsigned char*>(pBuf);
unsigned char* pInBuf = static_cast<unsigned char*>(pMalloc);
const unsigned int nNumSamples = nBytesWritten / 3;
// Convert to 16-bit
for ( unsigned int i = 0; i < nNumSamples; i++ )
{
pOutBuf[i*2] = pInBuf[i*3 + 1];
pOutBuf[i*2 + 1] = pInBuf[i*3 + 2];
}
return nNumSamples * 2;
} }
else else
{ {
if ( nLen * 3 / 4 > nLastMallocSize ) uint8_t* inputBuf = (uint8_t*)m_buffer;
int16_t* outputBuf = (int16_t*)pBuf;
for ( size_t i = 0; i < samplesRead; ++i )
{ {
if ( pMalloc ) *outputBuf = *(outputBuf+1) = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3;
operator delete(pMalloc); outputBuf += 2;
nLastMallocSize = nLen * 3 / 4;
pMalloc = operator new(nLastMallocSize);
} }
unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen * 3 / 4);
unsigned char* pOutBuf = static_cast<unsigned char*>(pBuf);
unsigned char* pInBuf = static_cast<unsigned char*>(pMalloc);
const unsigned int nNumSamples = nBytesWritten / 3;
// Convert to 16-bit
for ( unsigned int i = 0; i < nNumSamples; i++ )
{
pOutBuf[i*4] = pOutBuf[i*4 + 2] = pInBuf[i*3 + 1];
pOutBuf[i*4 + 1] = pOutBuf[i*4 + 3] = pInBuf[i*3 + 2];
}
return nNumSamples * 4;
} }
} }
else
{
// 16-bit
if ( formatChunk.numChannels == 2 )
{
// Stereo, optimised fetch
return GetStream()->FillBuffer(pBuf, nLen);
}
else
{
// Mono
if ( nLen / 2 > nLastMallocSize )
{
if ( pMalloc )
operator delete(pMalloc);
nLastMallocSize = nLen / 2; return samplesRead * (2*sizeof(int16_t));
pMalloc = operator new(nLastMallocSize); }
}
unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen / 2); size_t CAEWaveDecoder::CalcBufferSize( uint32_t outputBuf )
signed short* pOutBuf = static_cast<signed short*>(pBuf); {
signed short* pInBuf = static_cast<signed short*>(pMalloc); uint32_t requestedSamples = outputBuf / (2*sizeof(int16_t));
const unsigned int nNumSamples = nBytesWritten / 2; size_t requiredSize = m_formatChunk.blockAlign * requestedSamples;
return requiredSize == outputBuf ? 0 : requiredSize;
for ( unsigned int i = 0; i < nNumSamples; i++ )
{
pOutBuf[i*2] = pOutBuf[i*2 + 1] = pInBuf[i];
}
return nBytesWritten * 2;
}
}
} }

View file

@ -5,42 +5,51 @@
class CAEWaveDecoder : public CAEStreamingDecoder class CAEWaveDecoder : public CAEStreamingDecoder
{ {
private: private:
unsigned int nDataSize; uint32_t m_dataSize;
unsigned int nOffsetToData; uint32_t m_offsetToData;
//bool bInitialised; size_t m_maxBlockSize;
void* m_buffer;
struct FormatChunk struct FormatChunk
{ {
unsigned short audioFormat; uint16_t audioFormat;
unsigned short numChannels; uint16_t numChannels;
unsigned int sampleRate; uint32_t sampleRate;
unsigned int byteRate; uint32_t byteRate;
unsigned short blockAlign; uint16_t blockAlign;
unsigned short bitsPerSample; uint16_t bitsPerSample;
} formatChunk; } m_formatChunk;
public: public:
CAEWaveDecoder(CAEDataStream* stream) CAEWaveDecoder(CAEDataStream* stream)
: CAEStreamingDecoder(stream) : CAEStreamingDecoder(stream), m_buffer(nullptr), m_maxBlockSize(0)
{} {}
virtual ~CAEWaveDecoder() override
{
delete[] m_buffer;
}
virtual bool Initialise() override; virtual bool Initialise() override;
virtual uint32_t FillBuffer(void* pBuf, uint32_t nLen) override; virtual uint32_t FillBuffer(void* pBuf, uint32_t nLen) override;
virtual uint32_t GetStreamLengthMs() override virtual uint32_t GetStreamLengthMs() override
{ return static_cast<unsigned long long>(nDataSize) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } { return (static_cast<uint64_t>(m_dataSize) * 1000) / m_formatChunk.blockAlign; }
virtual uint32_t GetStreamPlayTimeMs() override virtual uint32_t GetStreamPlayTimeMs() override
{ return static_cast<unsigned long long>(GetStream()->GetCurrentPosition() - nOffsetToData) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } { return (static_cast<uint64_t>(GetStream()->GetCurrentPosition() - m_offsetToData) * 1000) / m_formatChunk.blockAlign; }
virtual void SetCursor(uint32_t nTime) override virtual void SetCursor(uint32_t nTime) override
{ auto nPos = static_cast<unsigned long long>(nTime) * (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels) / 8000; {
auto nModulo = (formatChunk.numChannels*formatChunk.bitsPerSample/8); uint64_t sampleNum = (static_cast<uint64_t>(nTime) * m_formatChunk.sampleRate) / 1000;
auto nExtra = nPos % nModulo ? nModulo - (nPos % nModulo) : 0; GetStream()->Seek( m_offsetToData + (static_cast<uint32_t>(sampleNum) * m_formatChunk.blockAlign), FILE_BEGIN );
GetStream()->Seek(nOffsetToData + nPos + nExtra, FILE_BEGIN); } }
virtual uint32_t GetSampleRate() override virtual uint32_t GetSampleRate() override
{ return formatChunk.sampleRate; } { return m_formatChunk.sampleRate; }
virtual uint32_t GetStreamID() override virtual uint32_t GetStreamID() override
{ return GetStream()->GetID(); } { return GetStream()->GetID(); }
private:
size_t CalcBufferSize( uint32_t outputBuf );
}; };