mirror of
https://github.com/CookiePLMonster/SilentPatch.git
synced 2024-11-24 22:32:29 +01:00
refactored WAV decoder
This commit is contained in:
parent
1b4859ac25
commit
0a439cc963
@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -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 );
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user