From 0a439cc9636f26ff22d00dfc8077b9bda736d6d3 Mon Sep 17 00:00:00 2001 From: Silent Date: Fri, 3 Mar 2017 21:20:30 +0100 Subject: [PATCH] refactored WAV decoder --- SilentPatchSA/AudioHardwareSA.cpp | 14 --- SilentPatchSA/AudioHardwareSA.h | 4 - SilentPatchSA/WaveDecoderSA.cpp | 201 +++++++++++------------------- SilentPatchSA/WaveDecoderSA.h | 45 ++++--- 4 files changed, 99 insertions(+), 165 deletions(-) diff --git a/SilentPatchSA/AudioHardwareSA.cpp b/SilentPatchSA/AudioHardwareSA.cpp index dc985f5..650dc67 100644 --- a/SilentPatchSA/AudioHardwareSA.cpp +++ b/SilentPatchSA/AudioHardwareSA.cpp @@ -6,12 +6,6 @@ bool CAEDataStream::m_bUseNewStruct; static void* CAEDataStream__Initialise = AddressByVersion(0x4DC2B0, 0x4DC7A0, 0x4E7550); 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) { LARGE_INTEGER filePosition; @@ -78,12 +72,4 @@ CAEStreamingDecoder::~CAEStreamingDecoder() delete reinterpret_cast(pStream); else delete reinterpret_cast(pStream); - - if ( --nMallocRefCount == 0 ) - { - operator delete(pMalloc); - pMalloc = nullptr; - - nLastMallocSize = 0; - } } \ No newline at end of file diff --git a/SilentPatchSA/AudioHardwareSA.h b/SilentPatchSA/AudioHardwareSA.h index 5440bba..bb0c1bd 100644 --- a/SilentPatchSA/AudioHardwareSA.h +++ b/SilentPatchSA/AudioHardwareSA.h @@ -223,14 +223,10 @@ class CAEStreamingDecoder private: CAEDataStream* pStream; - static unsigned int nMallocRefCount; - public: CAEStreamingDecoder(CAEDataStream* stream) : pStream(stream) { - ++nMallocRefCount; - if ( stream != nullptr ) stream->Initialise(); } diff --git a/SilentPatchSA/WaveDecoderSA.cpp b/SilentPatchSA/WaveDecoderSA.cpp index e9cd2d7..98bf536 100644 --- a/SilentPatchSA/WaveDecoderSA.cpp +++ b/SilentPatchSA/WaveDecoderSA.cpp @@ -1,27 +1,23 @@ #include "StdAfxSA.h" #include "WaveDecoderSA.h" -extern void* pMalloc; -extern unsigned int nBlockSize; -extern unsigned int nLastMallocSize; - bool CAEWaveDecoder::Initialise() { - auto* pTheStream = GetStream(); + CAEDataStream* pTheStream = GetStream(); struct { char sectionID[4]; - unsigned int sectionSize; + uint32_t sectionSize; } chunkHeader; // Find fmt section pTheStream->Seek(12, FILE_BEGIN); 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] != ' ' ) { - nOffsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize; + m_offsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize; pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT); pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); @@ -29,171 +25,118 @@ bool CAEWaveDecoder::Initialise() } // Read fmt header - pTheStream->FillBuffer(&formatChunk, sizeof(FormatChunk)); - nOffsetToData += sizeof(FormatChunk); + pTheStream->FillBuffer(&m_formatChunk, sizeof(m_formatChunk)); + m_offsetToData += sizeof(m_formatChunk); // 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); - pTheStream->Seek(chunkHeader.sectionSize - sizeof(FormatChunk), FILE_CURRENT); + m_offsetToData += chunkHeader.sectionSize - sizeof(m_formatChunk); + pTheStream->Seek(chunkHeader.sectionSize - sizeof(m_formatChunk), FILE_CURRENT); } // Find data chunk - nOffsetToData += sizeof(chunkHeader); + m_offsetToData += sizeof(chunkHeader); pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); 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->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) { - 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 - if ( nLen / 2 > nLastMallocSize ) + int16_t* inputBuf = (int16_t*)m_buffer; + int16_t* outputBuf = (int16_t*)pBuf; + for ( size_t i = 0; i < samplesRead; ++i ) { - if ( pMalloc ) - operator delete(pMalloc); - - nLastMallocSize = nLen / 2; - pMalloc = operator new(nLastMallocSize); + *outputBuf = *(outputBuf+1) = *inputBuf++; + outputBuf += 2; } - - unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen / 2); - signed short* pOutBuf = static_cast(pBuf); - unsigned char* pInBuf = static_cast(pMalloc); - - // Convert to 16-bit - for ( unsigned int i = 0; i < nBytesWritten; i++ ) + + } + } + else if ( m_formatChunk.bitsPerSample == 8 ) + { + if ( m_formatChunk.numChannels == 2 ) + { + 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(pInBuf[i]) - 128) << 8; + *outputBuf++ = (static_cast(*inputBuf++) - 128) << 8; + *outputBuf++ = (static_cast(*inputBuf++) - 128) << 8; } - - return nBytesWritten * 2; } else { - // Mono - if ( nLen / 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 ) - operator delete(pMalloc); - - nLastMallocSize = nLen / 4; - pMalloc = operator new(nLastMallocSize); + *outputBuf = *(outputBuf+1) = (static_cast(*inputBuf++) - 128) << 8; + outputBuf += 2; } - - unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen / 4); - signed short* pOutBuf = static_cast(pBuf); - unsigned char* pInBuf = static_cast(pMalloc); - - // Convert to 16-bit - for ( unsigned int i = 0; i < nBytesWritten; i++ ) - { - pOutBuf[i * 2] = pOutBuf[i * 2 + 1] = (static_cast(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 - if ( nLen * 3 / 2 > nLastMallocSize ) + uint8_t* inputBuf = (uint8_t*)m_buffer; + int16_t* outputBuf = (int16_t*)pBuf; + for ( size_t i = 0; i < samplesRead; ++i ) { - if ( pMalloc ) - operator delete(pMalloc); - - nLastMallocSize = nLen * 3 / 2; - pMalloc = operator new(nLastMallocSize); + *outputBuf++ = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3; + *outputBuf++ = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3; } - - unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen * 3 / 2); - unsigned char* pOutBuf = static_cast(pBuf); - unsigned char* pInBuf = static_cast(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 { - 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 ) - operator delete(pMalloc); - - nLastMallocSize = nLen * 3 / 4; - pMalloc = operator new(nLastMallocSize); + *outputBuf = *(outputBuf+1) = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3; + outputBuf += 2; } - - unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen * 3 / 4); - unsigned char* pOutBuf = static_cast(pBuf); - unsigned char* pInBuf = static_cast(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; - pMalloc = operator new(nLastMallocSize); - } + return samplesRead * (2*sizeof(int16_t)); +} - unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen / 2); - signed short* pOutBuf = static_cast(pBuf); - signed short* pInBuf = static_cast(pMalloc); - const unsigned int nNumSamples = nBytesWritten / 2; - - for ( unsigned int i = 0; i < nNumSamples; i++ ) - { - pOutBuf[i*2] = pOutBuf[i*2 + 1] = pInBuf[i]; - } - - return nBytesWritten * 2; - } - } +size_t CAEWaveDecoder::CalcBufferSize( uint32_t outputBuf ) +{ + uint32_t requestedSamples = outputBuf / (2*sizeof(int16_t)); + size_t requiredSize = m_formatChunk.blockAlign * requestedSamples; + return requiredSize == outputBuf ? 0 : requiredSize; } \ No newline at end of file diff --git a/SilentPatchSA/WaveDecoderSA.h b/SilentPatchSA/WaveDecoderSA.h index f6d813e..50b29d8 100644 --- a/SilentPatchSA/WaveDecoderSA.h +++ b/SilentPatchSA/WaveDecoderSA.h @@ -5,42 +5,51 @@ class CAEWaveDecoder : public CAEStreamingDecoder { private: - unsigned int nDataSize; - unsigned int nOffsetToData; - //bool bInitialised; + uint32_t m_dataSize; + uint32_t m_offsetToData; + size_t m_maxBlockSize; + void* m_buffer; struct FormatChunk { - unsigned short audioFormat; - unsigned short numChannels; - unsigned int sampleRate; - unsigned int byteRate; - unsigned short blockAlign; - unsigned short bitsPerSample; - } formatChunk; + uint16_t audioFormat; + uint16_t numChannels; + uint32_t sampleRate; + uint32_t byteRate; + uint16_t blockAlign; + uint16_t bitsPerSample; + } m_formatChunk; public: CAEWaveDecoder(CAEDataStream* stream) - : CAEStreamingDecoder(stream) + : CAEStreamingDecoder(stream), m_buffer(nullptr), m_maxBlockSize(0) {} + virtual ~CAEWaveDecoder() override + { + delete[] m_buffer; + } + virtual bool Initialise() override; virtual uint32_t FillBuffer(void* pBuf, uint32_t nLen) override; virtual uint32_t GetStreamLengthMs() override - { return static_cast(nDataSize) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } + { return (static_cast(m_dataSize) * 1000) / m_formatChunk.blockAlign; } virtual uint32_t GetStreamPlayTimeMs() override - { return static_cast(GetStream()->GetCurrentPosition() - nOffsetToData) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } + { return (static_cast(GetStream()->GetCurrentPosition() - m_offsetToData) * 1000) / m_formatChunk.blockAlign; } virtual void SetCursor(uint32_t nTime) override - { auto nPos = static_cast(nTime) * (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels) / 8000; - auto nModulo = (formatChunk.numChannels*formatChunk.bitsPerSample/8); - auto nExtra = nPos % nModulo ? nModulo - (nPos % nModulo) : 0; - GetStream()->Seek(nOffsetToData + nPos + nExtra, FILE_BEGIN); } + { + uint64_t sampleNum = (static_cast(nTime) * m_formatChunk.sampleRate) / 1000; + GetStream()->Seek( m_offsetToData + (static_cast(sampleNum) * m_formatChunk.blockAlign), FILE_BEGIN ); + } virtual uint32_t GetSampleRate() override - { return formatChunk.sampleRate; } + { return m_formatChunk.sampleRate; } virtual uint32_t GetStreamID() override { return GetStream()->GetID(); } + +private: + size_t CalcBufferSize( uint32_t outputBuf ); }; \ No newline at end of file