diff --git a/SilentPatchSA/AudioHardwareSA.cpp b/SilentPatchSA/AudioHardwareSA.cpp index 5e48c27..8393e74 100644 --- a/SilentPatchSA/AudioHardwareSA.cpp +++ b/SilentPatchSA/AudioHardwareSA.cpp @@ -1,10 +1,6 @@ #include "StdAfxSA.h" #include "AudioHardwareSA.h" -//WRAPPER HRESULT STDMETHODCALLTYPE CAEDataStream::Seek(LARGE_INTEGER liDistanceToMove, DWORD dwOrigin, ULARGE_INTEGER* lpNewFilePointer) -// { EAXJMP(0x4DC340); } -//WRAPPER HRESULT STDMETHODCALLTYPE CAEDataStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) { EAXJMP(0x4DC3A0); } - bool CAEDataStream::m_bUseNewStruct; static void* CAEDataStream__Initialise = AddressByVersion(0x4DC2B0, 0x4DC7A0, 0x4E7550); @@ -12,11 +8,9 @@ WRAPPER bool CAEDataStream::Initialise() { VARJMP(CAEDataStream__Initialise); } unsigned int CAEStreamingDecoder::nMallocRefCount = 0; -static void* pMalloc = nullptr; -static unsigned int nBlockSize = 0; -static unsigned int nLastMallocSize = 0; - -static unsigned int nSamplesLeftToProcess = 0; +void* pMalloc = nullptr; +unsigned int nBlockSize = 0; +unsigned int nLastMallocSize = 0; unsigned int CAEDataStreamOld::Seek(long nToSeek, int nPoint) { @@ -85,437 +79,4 @@ CAEStreamingDecoder::~CAEStreamingDecoder() nLastMallocSize = 0; } -} - - -bool CAEWaveDecoder::Initialise() -{ - auto* pTheStream = GetStream(); - struct { - char sectionID[4]; - unsigned int sectionSize; - } chunkHeader; - - // Find fmt section - pTheStream->Seek(12, FILE_BEGIN); - - pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); - nOffsetToData = 12 + sizeof(chunkHeader); - - while ( chunkHeader.sectionID[0] != 'f' || chunkHeader.sectionID[1] != 'm' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != ' ' ) - { - nOffsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize; - - pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT); - pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); - - } - - // Read fmt header - pTheStream->FillBuffer(&formatChunk, sizeof(FormatChunk)); - nOffsetToData += sizeof(FormatChunk); - - // Now skip through the rest of a chunk - if ( chunkHeader.sectionSize - sizeof(FormatChunk) > 0 ) - { - nOffsetToData += chunkHeader.sectionSize - sizeof(FormatChunk); - pTheStream->Seek(chunkHeader.sectionSize - sizeof(FormatChunk), FILE_CURRENT); - } - - // Find data chunk - nOffsetToData += 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; - - pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT); - pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); - } - - nDataSize = chunkHeader.sectionSize; - - return formatChunk.sampleRate <= 48000 && formatChunk.numChannels <= 2 && (formatChunk.bitsPerSample == 8 || formatChunk.bitsPerSample == 16 || formatChunk.bitsPerSample == 24); -} - -unsigned int CAEWaveDecoder::FillBuffer(void* pBuf, unsigned long nLen) -{ - if ( formatChunk.bitsPerSample == 8 ) - { - if ( formatChunk.numChannels == 2 ) - { - // Stereo - if ( nLen / 2 > nLastMallocSize ) - { - if ( pMalloc ) - operator delete(pMalloc); - - nLastMallocSize = nLen / 2; - pMalloc = operator new(nLastMallocSize); - } - - 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++ ) - { - pOutBuf[i] = (static_cast(pInBuf[i]) - 128) << 8; - } - - return nBytesWritten * 2; - } - else - { - // Mono - if ( nLen / 4 > nLastMallocSize ) - { - if ( pMalloc ) - operator delete(pMalloc); - - nLastMallocSize = nLen / 4; - pMalloc = operator new(nLastMallocSize); - } - - 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 ) - { - if ( formatChunk.numChannels == 2 ) - { - // Stereo - if ( nLen * 3 / 2 > nLastMallocSize ) - { - if ( pMalloc ) - operator delete(pMalloc); - - nLastMallocSize = nLen * 3 / 2; - pMalloc = operator new(nLastMallocSize); - } - - 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 ) - { - if ( pMalloc ) - operator delete(pMalloc); - - nLastMallocSize = nLen * 3 / 4; - pMalloc = operator new(nLastMallocSize); - } - - 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); - } - - 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; - } - } -} - - -FLAC__StreamDecoderReadStatus CAEFLACDecoder::read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data) -{ - UNREFERENCED_PARAMETER(decoder); - CAEFLACDecoder* pClientData = static_cast(client_data); - - ReadFile(pClientData->GetStream()->GetFile(), buffer, *bytes, reinterpret_cast(bytes), nullptr); //*bytes = pClientData->GetStream()->FillBuffer(buffer, *bytes); - //*bytes = pClientData->GetStream()->FillBuffer(buffer, *bytes); - //bEOFFlag = GetLastError() == ERROR_HANDLE_EOF; - - auto result = *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - - return result; -} - -FLAC__StreamDecoderWriteStatus CAEFLACDecoder::write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) -{ - CAEFLACDecoder* pClientData = static_cast(client_data); - - // Obtain current sample - pClientData->nCurrentSample = frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER ? - frame->header.number.sample_number : - frame->header.number.frame_number * frame->header.blocksize; - - // Mono/stereo? - unsigned int nNumChannelsToAlloc = pClientData->pStreamInfo->data.stream_info.channels > 1 ? 2 : 1; - - if ( frame->header.blocksize * sizeof(FLAC__int32) * nNumChannelsToAlloc > nLastMallocSize ) - { - // Realloc needed - if ( pMalloc ) - operator delete(pMalloc); - - nLastMallocSize = frame->header.blocksize * sizeof(FLAC__int32) * nNumChannelsToAlloc; - pMalloc = operator new(nLastMallocSize); // TODO: More channels? - } - nBlockSize = frame->header.blocksize; - - memcpy(pMalloc, buffer[0], nBlockSize * sizeof(FLAC__int32)); - if ( nNumChannelsToAlloc > 1 ) - memcpy(static_cast(pMalloc)+nBlockSize, buffer[1], nBlockSize * sizeof(FLAC__int32)); - - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -void CAEFLACDecoder::meta_cb(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata *metadata, void *client_data) -{ - if ( metadata->type == FLAC__METADATA_TYPE_STREAMINFO ) - { - // Cache the header - CAEFLACDecoder* pClientData = static_cast(client_data); - pClientData->pStreamInfo = FLAC__metadata_object_clone(metadata); - } -} - -FLAC__StreamDecoderSeekStatus CAEFLACDecoder::seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) -{ - CAEFLACDecoder* pClientData = static_cast(client_data); - LARGE_INTEGER li; - li.QuadPart = absolute_byte_offset; - - li.LowPart = SetFilePointer(pClientData->GetStream()->GetFile(), li.LowPart, &li.HighPart, FILE_BEGIN); - - return li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ? FLAC__STREAM_DECODER_SEEK_STATUS_ERROR : FLAC__STREAM_DECODER_SEEK_STATUS_OK; -} - -FLAC__StreamDecoderTellStatus CAEFLACDecoder::tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) -{ - CAEFLACDecoder* pClientData = static_cast(client_data); - LARGE_INTEGER li; - li.QuadPart = 0; - - li.LowPart = SetFilePointer(pClientData->GetStream()->GetFile(), 0, &li.HighPart, FILE_CURRENT); - *absolute_byte_offset = li.QuadPart; - - return li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ? FLAC__STREAM_DECODER_TELL_STATUS_ERROR : FLAC__STREAM_DECODER_TELL_STATUS_OK; -} - -FLAC__StreamDecoderLengthStatus CAEFLACDecoder::length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) -{ - CAEFLACDecoder* pClientData = static_cast(client_data); - LARGE_INTEGER li; - - BOOL bResult = GetFileSizeEx(pClientData->GetStream()->GetFile(), &li); - *stream_length = li.QuadPart; - - return bResult ? FLAC__STREAM_DECODER_LENGTH_STATUS_OK: FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; -} - -FLAC__bool CAEFLACDecoder::eof_cb(const FLAC__StreamDecoder* decoder, void* client_data) -{ - // Not implemented - UNREFERENCED_PARAMETER(decoder); - UNREFERENCED_PARAMETER(client_data); - return false; -} - -void CAEFLACDecoder::error_cb(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data) -{ - // Not implemented - UNREFERENCED_PARAMETER(decoder); - UNREFERENCED_PARAMETER(status); - UNREFERENCED_PARAMETER(client_data); -} - - -bool CAEFLACDecoder::Initialise() -{ - pFLACDecoder = FLAC__stream_decoder_new(); - if ( FLAC__stream_decoder_init_stream(pFLACDecoder, read_cb, seek_cb, tell_cb, length_cb, eof_cb, write_cb, meta_cb, error_cb, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) - { - FLAC__stream_decoder_process_until_end_of_metadata(pFLACDecoder); - - return pStreamInfo->data.stream_info.sample_rate <= 48000 && (pStreamInfo->data.stream_info.bits_per_sample == 8 || pStreamInfo->data.stream_info.bits_per_sample == 16 || pStreamInfo->data.stream_info.bits_per_sample == 24); - } - return false; -} - -unsigned int CAEFLACDecoder::FillBuffer(void* pBuf, unsigned long nLen) -{ - unsigned int nBytesDecoded = 0; - FLAC__int16* pBuffer = static_cast(pBuf); - - const unsigned int nSampleRate = pStreamInfo->data.stream_info.bits_per_sample; - const bool bStereo = pStreamInfo->data.stream_info.channels > 1; - - while ( nBytesDecoded < nLen ) - { - unsigned int nToWrite; - // No samples left from a previous fetch? - if ( !nSamplesLeftToProcess ) - { - FLAC__stream_decoder_process_single(pFLACDecoder); - - if ( (nLen - nBytesDecoded) / 4 >= nBlockSize ) - nToWrite = nBlockSize; - else - nToWrite = (nLen - nBytesDecoded) / 4; - - nSamplesLeftToProcess = nBlockSize; - } - else - nToWrite = nSamplesLeftToProcess; - - FLAC__int32* pCurrentPtr[2] = { static_cast(pMalloc), static_cast(pMalloc)+nBlockSize }; - const unsigned int ExtraIndex = nBlockSize - nSamplesLeftToProcess; - - // Write channels - if ( nSampleRate == 8 ) - { - // 8-bit - if ( bStereo ) - { - for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) - { - pBuffer[0] = pCurrentPtr[0][ExtraIndex+i] << 8; - pBuffer[1] = pCurrentPtr[1][ExtraIndex+i] << 8; - - pBuffer += 2; - } - } - else - { - for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) - { - pBuffer[0] = pBuffer[1] = pCurrentPtr[0][ExtraIndex+i] << 8; - - pBuffer += 2; - } - } - } - else if ( nSampleRate == 24 ) - { - // 24-bit - if ( bStereo ) - { - for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) - { - pBuffer[0] = pCurrentPtr[0][ExtraIndex+i] >> 8; - pBuffer[1] = pCurrentPtr[1][ExtraIndex+i] >> 8; - - pBuffer += 2; - } - } - else - { - for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) - { - pBuffer[0] = pBuffer[1] = pCurrentPtr[0][ExtraIndex+i] >> 8; - - pBuffer += 2; - } - } - } - else - { - // 16-bit - if ( bStereo ) - { - for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) - { - pBuffer[0] = pCurrentPtr[0][ExtraIndex+i]; - pBuffer[1] = pCurrentPtr[1][ExtraIndex+i]; - - pBuffer += 2; - } - } - else - { - for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) - { - pBuffer[0] = pBuffer[1] = pCurrentPtr[0][ExtraIndex+i]; - - pBuffer += 2; - } - } - } - - nBytesDecoded += nToWrite*4; - - if ( FLAC__stream_decoder_get_state(pFLACDecoder) == FLAC__STREAM_DECODER_END_OF_STREAM ) - break; - } - return nBytesDecoded; -} - -CAEFLACDecoder::~CAEFLACDecoder() -{ - nSamplesLeftToProcess = 0; - if ( pFLACDecoder ) - { - FLAC__stream_decoder_finish(pFLACDecoder); - FLAC__stream_decoder_delete(pFLACDecoder); - - FLAC__metadata_object_delete(pStreamInfo); - pFLACDecoder = nullptr; - } } \ No newline at end of file diff --git a/SilentPatchSA/AudioHardwareSA.h b/SilentPatchSA/AudioHardwareSA.h index 93f9309..c18725e 100644 --- a/SilentPatchSA/AudioHardwareSA.h +++ b/SilentPatchSA/AudioHardwareSA.h @@ -3,7 +3,6 @@ // libflac #define FLAC__NO_DLL -#include "share\compat.h" #include "FLAC\stream_decoder.h" #include "FLAC\metadata.h" @@ -234,84 +233,4 @@ public: virtual unsigned int GetStreamID()=0; }; -class CAEWaveDecoder : public CAEStreamingDecoder -{ -private: - unsigned int nDataSize; - unsigned int nOffsetToData; - //bool bInitialised; - - struct FormatChunk - { - unsigned short audioFormat; - unsigned short numChannels; - unsigned int sampleRate; - unsigned int byteRate; - unsigned short blockAlign; - unsigned short bitsPerSample; - } formatChunk; - -public: - CAEWaveDecoder(CAEDataStream* stream) - : CAEStreamingDecoder(stream) - {} - - virtual bool Initialise() override; - virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override; - - virtual unsigned int GetStreamLengthMs() override - { return static_cast(nDataSize) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } - virtual unsigned int GetStreamPlayTimeMs() override - { return static_cast(GetStream()->GetCurrentPosition() - nOffsetToData) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } - - virtual void SetCursor(unsigned int 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); } - - virtual unsigned int GetSampleRate() override - { return formatChunk.sampleRate; } - - virtual unsigned int GetStreamID() override - { return GetStream()->GetID(); } -}; - -class CAEFLACDecoder : public CAEStreamingDecoder -{ -private: - FLAC__StreamDecoder* pFLACDecoder; - FLAC__StreamMetadata* pStreamInfo; - unsigned int nCurrentSample; - -private: - static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data); - static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data); - static void meta_cb(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata *metadata, void *client_data); - static void error_cb(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data); - static FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); - static FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - static FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); - static FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data); - -public: - CAEFLACDecoder(CAEDataStream* stream) - : CAEStreamingDecoder(stream), pFLACDecoder(nullptr) - {} - - virtual ~CAEFLACDecoder(); - virtual bool Initialise() override; - virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override; - virtual unsigned int GetStreamLengthMs() override - { return pStreamInfo->data.stream_info.total_samples * 1000 / pStreamInfo->data.stream_info.sample_rate; } - virtual unsigned int GetStreamPlayTimeMs() override - { return nCurrentSample * 1000 / pStreamInfo->data.stream_info.sample_rate; } - virtual void SetCursor(unsigned int nTime) override - { FLAC__stream_decoder_seek_absolute(pFLACDecoder, nTime * pStreamInfo->data.stream_info.sample_rate / 1000); } - virtual unsigned int GetSampleRate() override - { return pStreamInfo->data.stream_info.sample_rate; } - virtual unsigned int GetStreamID() override - { return GetStream()->GetID(); } -}; - #endif \ No newline at end of file diff --git a/SilentPatchSA/FLACDecoderSA.cpp b/SilentPatchSA/FLACDecoderSA.cpp new file mode 100644 index 0000000..cf56b09 --- /dev/null +++ b/SilentPatchSA/FLACDecoderSA.cpp @@ -0,0 +1,246 @@ +#include "StdAfxSA.h" +#include "FLACDecoderSA.h" + +extern void* pMalloc; +extern unsigned int nBlockSize; +extern unsigned int nLastMallocSize; + +static unsigned int nSamplesLeftToProcess = 0; + +FLAC__StreamDecoderReadStatus CAEFLACDecoder::read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data) +{ + UNREFERENCED_PARAMETER(decoder); + CAEFLACDecoder* pClientData = static_cast(client_data); + + ReadFile(pClientData->GetStream()->GetFile(), buffer, *bytes, reinterpret_cast(bytes), nullptr); //*bytes = pClientData->GetStream()->FillBuffer(buffer, *bytes); + //*bytes = pClientData->GetStream()->FillBuffer(buffer, *bytes); + //bEOFFlag = GetLastError() == ERROR_HANDLE_EOF; + + auto result = *bytes ? FLAC__STREAM_DECODER_READ_STATUS_CONTINUE : FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; + + return result; +} + +FLAC__StreamDecoderWriteStatus CAEFLACDecoder::write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data) +{ + CAEFLACDecoder* pClientData = static_cast(client_data); + + // Obtain current sample + pClientData->nCurrentSample = frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER ? + frame->header.number.sample_number : + frame->header.number.frame_number * frame->header.blocksize; + + // Mono/stereo? + unsigned int nNumChannelsToAlloc = pClientData->pStreamInfo->data.stream_info.channels > 1 ? 2 : 1; + + if ( frame->header.blocksize * sizeof(FLAC__int32) * nNumChannelsToAlloc > nLastMallocSize ) + { + // Realloc needed + if ( pMalloc ) + operator delete(pMalloc); + + nLastMallocSize = frame->header.blocksize * sizeof(FLAC__int32) * nNumChannelsToAlloc; + pMalloc = operator new(nLastMallocSize); // TODO: More channels? + } + nBlockSize = frame->header.blocksize; + + memcpy(pMalloc, buffer[0], nBlockSize * sizeof(FLAC__int32)); + if ( nNumChannelsToAlloc > 1 ) + memcpy(static_cast(pMalloc)+nBlockSize, buffer[1], nBlockSize * sizeof(FLAC__int32)); + + return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; +} + +void CAEFLACDecoder::meta_cb(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata *metadata, void *client_data) +{ + if ( metadata->type == FLAC__METADATA_TYPE_STREAMINFO ) + { + // Cache the header + CAEFLACDecoder* pClientData = static_cast(client_data); + pClientData->pStreamInfo = FLAC__metadata_object_clone(metadata); + } +} + +FLAC__StreamDecoderSeekStatus CAEFLACDecoder::seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) +{ + CAEFLACDecoder* pClientData = static_cast(client_data); + LARGE_INTEGER li; + li.QuadPart = absolute_byte_offset; + + li.LowPart = SetFilePointer(pClientData->GetStream()->GetFile(), li.LowPart, &li.HighPart, FILE_BEGIN); + + return li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ? FLAC__STREAM_DECODER_SEEK_STATUS_ERROR : FLAC__STREAM_DECODER_SEEK_STATUS_OK; +} + +FLAC__StreamDecoderTellStatus CAEFLACDecoder::tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) +{ + CAEFLACDecoder* pClientData = static_cast(client_data); + LARGE_INTEGER li; + li.QuadPart = 0; + + li.LowPart = SetFilePointer(pClientData->GetStream()->GetFile(), 0, &li.HighPart, FILE_CURRENT); + *absolute_byte_offset = li.QuadPart; + + return li.LowPart == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR ? FLAC__STREAM_DECODER_TELL_STATUS_ERROR : FLAC__STREAM_DECODER_TELL_STATUS_OK; +} + +FLAC__StreamDecoderLengthStatus CAEFLACDecoder::length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) +{ + CAEFLACDecoder* pClientData = static_cast(client_data); + LARGE_INTEGER li; + + BOOL bResult = GetFileSizeEx(pClientData->GetStream()->GetFile(), &li); + *stream_length = li.QuadPart; + + return bResult ? FLAC__STREAM_DECODER_LENGTH_STATUS_OK: FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; +} + +FLAC__bool CAEFLACDecoder::eof_cb(const FLAC__StreamDecoder* decoder, void* client_data) +{ + // Not implemented + UNREFERENCED_PARAMETER(decoder); + UNREFERENCED_PARAMETER(client_data); + return false; +} + +void CAEFLACDecoder::error_cb(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data) +{ + // Not implemented + UNREFERENCED_PARAMETER(decoder); + UNREFERENCED_PARAMETER(status); + UNREFERENCED_PARAMETER(client_data); +} + + +bool CAEFLACDecoder::Initialise() +{ + pFLACDecoder = FLAC__stream_decoder_new(); + if ( FLAC__stream_decoder_init_stream(pFLACDecoder, read_cb, seek_cb, tell_cb, length_cb, eof_cb, write_cb, meta_cb, error_cb, this) == FLAC__STREAM_DECODER_INIT_STATUS_OK ) + { + FLAC__stream_decoder_process_until_end_of_metadata(pFLACDecoder); + + return pStreamInfo->data.stream_info.sample_rate <= 48000 && (pStreamInfo->data.stream_info.bits_per_sample == 8 || pStreamInfo->data.stream_info.bits_per_sample == 16 || pStreamInfo->data.stream_info.bits_per_sample == 24); + } + return false; +} + +unsigned int CAEFLACDecoder::FillBuffer(void* pBuf, unsigned long nLen) +{ + unsigned int nBytesDecoded = 0; + FLAC__int16* pBuffer = static_cast(pBuf); + + const unsigned int nSampleRate = pStreamInfo->data.stream_info.bits_per_sample; + const bool bStereo = pStreamInfo->data.stream_info.channels > 1; + + while ( nBytesDecoded < nLen ) + { + unsigned int nToWrite; + // No samples left from a previous fetch? + if ( !nSamplesLeftToProcess ) + { + FLAC__stream_decoder_process_single(pFLACDecoder); + + if ( (nLen - nBytesDecoded) / 4 >= nBlockSize ) + nToWrite = nBlockSize; + else + nToWrite = (nLen - nBytesDecoded) / 4; + + nSamplesLeftToProcess = nBlockSize; + } + else + nToWrite = nSamplesLeftToProcess; + + FLAC__int32* pCurrentPtr[2] = { static_cast(pMalloc), static_cast(pMalloc)+nBlockSize }; + const unsigned int ExtraIndex = nBlockSize - nSamplesLeftToProcess; + + // Write channels + if ( nSampleRate == 8 ) + { + // 8-bit + if ( bStereo ) + { + for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) + { + pBuffer[0] = pCurrentPtr[0][ExtraIndex+i] << 8; + pBuffer[1] = pCurrentPtr[1][ExtraIndex+i] << 8; + + pBuffer += 2; + } + } + else + { + for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) + { + pBuffer[0] = pBuffer[1] = pCurrentPtr[0][ExtraIndex+i] << 8; + + pBuffer += 2; + } + } + } + else if ( nSampleRate == 24 ) + { + // 24-bit + if ( bStereo ) + { + for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) + { + pBuffer[0] = pCurrentPtr[0][ExtraIndex+i] >> 8; + pBuffer[1] = pCurrentPtr[1][ExtraIndex+i] >> 8; + + pBuffer += 2; + } + } + else + { + for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) + { + pBuffer[0] = pBuffer[1] = pCurrentPtr[0][ExtraIndex+i] >> 8; + + pBuffer += 2; + } + } + } + else + { + // 16-bit + if ( bStereo ) + { + for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) + { + pBuffer[0] = pCurrentPtr[0][ExtraIndex+i]; + pBuffer[1] = pCurrentPtr[1][ExtraIndex+i]; + + pBuffer += 2; + } + } + else + { + for ( unsigned int i = 0; i < nToWrite; i++, nSamplesLeftToProcess-- ) + { + pBuffer[0] = pBuffer[1] = pCurrentPtr[0][ExtraIndex+i]; + + pBuffer += 2; + } + } + } + + nBytesDecoded += nToWrite*4; + + if ( FLAC__stream_decoder_get_state(pFLACDecoder) == FLAC__STREAM_DECODER_END_OF_STREAM ) + break; + } + return nBytesDecoded; +} + +CAEFLACDecoder::~CAEFLACDecoder() +{ + nSamplesLeftToProcess = 0; + if ( pFLACDecoder ) + { + FLAC__stream_decoder_finish(pFLACDecoder); + FLAC__stream_decoder_delete(pFLACDecoder); + + FLAC__metadata_object_delete(pStreamInfo); + pFLACDecoder = nullptr; + } +} \ No newline at end of file diff --git a/SilentPatchSA/FLACDecoderSA.h b/SilentPatchSA/FLACDecoderSA.h new file mode 100644 index 0000000..9964250 --- /dev/null +++ b/SilentPatchSA/FLACDecoderSA.h @@ -0,0 +1,40 @@ +#pragma once + +#include "AudioHardwareSA.h" + +class CAEFLACDecoder : public CAEStreamingDecoder +{ +private: + FLAC__StreamDecoder* pFLACDecoder; + FLAC__StreamMetadata* pStreamInfo; + unsigned int nCurrentSample; + +private: + static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data); + static FLAC__StreamDecoderWriteStatus write_cb(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 *const buffer[], void *client_data); + static void meta_cb(const FLAC__StreamDecoder* decoder, const FLAC__StreamMetadata *metadata, void *client_data); + static void error_cb(const FLAC__StreamDecoder* decoder, FLAC__StreamDecoderErrorStatus status, void* client_data); + static FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); + static FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); + static FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); + static FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data); + +public: + CAEFLACDecoder(CAEDataStream* stream) + : CAEStreamingDecoder(stream), pFLACDecoder(nullptr) + {} + + virtual ~CAEFLACDecoder(); + virtual bool Initialise() override; + virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override; + virtual unsigned int GetStreamLengthMs() override + { return pStreamInfo->data.stream_info.total_samples * 1000 / pStreamInfo->data.stream_info.sample_rate; } + virtual unsigned int GetStreamPlayTimeMs() override + { return nCurrentSample * 1000 / pStreamInfo->data.stream_info.sample_rate; } + virtual void SetCursor(unsigned int nTime) override + { FLAC__stream_decoder_seek_absolute(pFLACDecoder, nTime * pStreamInfo->data.stream_info.sample_rate / 1000); } + virtual unsigned int GetSampleRate() override + { return pStreamInfo->data.stream_info.sample_rate; } + virtual unsigned int GetStreamID() override + { return GetStream()->GetID(); } +}; \ No newline at end of file diff --git a/SilentPatchSA/SilentPatchSA.cpp b/SilentPatchSA/SilentPatchSA.cpp index 198c667..e7112aa 100644 --- a/SilentPatchSA/SilentPatchSA.cpp +++ b/SilentPatchSA/SilentPatchSA.cpp @@ -11,6 +11,9 @@ #include "LinkListSA.h" #include "PNGFile.h" +#include "WaveDecoderSA.h" +#include "FLACDecoderSA.h" + // RW wrappers static void* varAtomicDefaultRenderCallBack = AddressByVersion(0x7491C0, 0x749AD0, 0x783180); WRAPPER RpAtomic* AtomicDefaultRenderCallBack(RpAtomic* atomic) { WRAPARG(atomic); VARJMP(varAtomicDefaultRenderCallBack); } diff --git a/SilentPatchSA/SilentPatchSA.vcxproj b/SilentPatchSA/SilentPatchSA.vcxproj index cb2d8ac..563f0cf 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj +++ b/SilentPatchSA/SilentPatchSA.vcxproj @@ -113,6 +113,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio + @@ -125,6 +126,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio + @@ -153,6 +155,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio + @@ -164,6 +167,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio + diff --git a/SilentPatchSA/SilentPatchSA.vcxproj.filters b/SilentPatchSA/SilentPatchSA.vcxproj.filters index 5df3d0f..3a79c92 100644 --- a/SilentPatchSA/SilentPatchSA.vcxproj.filters +++ b/SilentPatchSA/SilentPatchSA.vcxproj.filters @@ -19,6 +19,9 @@ {57615a2f-8bc4-461f-b9f6-86d5f8286d7a} + + {f4ecbe23-228b-461b-b37f-d718e7ca92ae} + @@ -51,6 +54,12 @@ Source Files + + Source Files\decoders + + + Source Files\decoders + @@ -113,6 +122,12 @@ Header Files + + Source Files\decoders + + + Source Files\decoders + diff --git a/SilentPatchSA/WaveDecoderSA.cpp b/SilentPatchSA/WaveDecoderSA.cpp new file mode 100644 index 0000000..c0314a0 --- /dev/null +++ b/SilentPatchSA/WaveDecoderSA.cpp @@ -0,0 +1,199 @@ +#include "StdAfxSA.h" +#include "WaveDecoderSA.h" + +extern void* pMalloc; +extern unsigned int nBlockSize; +extern unsigned int nLastMallocSize; + +bool CAEWaveDecoder::Initialise() +{ + auto* pTheStream = GetStream(); + struct { + char sectionID[4]; + unsigned int sectionSize; + } chunkHeader; + + // Find fmt section + pTheStream->Seek(12, FILE_BEGIN); + + pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); + nOffsetToData = 12 + sizeof(chunkHeader); + + while ( chunkHeader.sectionID[0] != 'f' || chunkHeader.sectionID[1] != 'm' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != ' ' ) + { + nOffsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize; + + pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT); + pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); + + } + + // Read fmt header + pTheStream->FillBuffer(&formatChunk, sizeof(FormatChunk)); + nOffsetToData += sizeof(FormatChunk); + + // Now skip through the rest of a chunk + if ( chunkHeader.sectionSize - sizeof(FormatChunk) > 0 ) + { + nOffsetToData += chunkHeader.sectionSize - sizeof(FormatChunk); + pTheStream->Seek(chunkHeader.sectionSize - sizeof(FormatChunk), FILE_CURRENT); + } + + // Find data chunk + nOffsetToData += 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; + + pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT); + pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader)); + } + + nDataSize = chunkHeader.sectionSize; + + return formatChunk.sampleRate <= 48000 && formatChunk.numChannels <= 2 && (formatChunk.bitsPerSample == 8 || formatChunk.bitsPerSample == 16 || formatChunk.bitsPerSample == 24); +} + +unsigned int CAEWaveDecoder::FillBuffer(void* pBuf, unsigned long nLen) +{ + if ( formatChunk.bitsPerSample == 8 ) + { + if ( formatChunk.numChannels == 2 ) + { + // Stereo + if ( nLen / 2 > nLastMallocSize ) + { + if ( pMalloc ) + operator delete(pMalloc); + + nLastMallocSize = nLen / 2; + pMalloc = operator new(nLastMallocSize); + } + + 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++ ) + { + pOutBuf[i] = (static_cast(pInBuf[i]) - 128) << 8; + } + + return nBytesWritten * 2; + } + else + { + // Mono + if ( nLen / 4 > nLastMallocSize ) + { + if ( pMalloc ) + operator delete(pMalloc); + + nLastMallocSize = nLen / 4; + pMalloc = operator new(nLastMallocSize); + } + + 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 ) + { + if ( formatChunk.numChannels == 2 ) + { + // Stereo + if ( nLen * 3 / 2 > nLastMallocSize ) + { + if ( pMalloc ) + operator delete(pMalloc); + + nLastMallocSize = nLen * 3 / 2; + pMalloc = operator new(nLastMallocSize); + } + + 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 ) + { + if ( pMalloc ) + operator delete(pMalloc); + + nLastMallocSize = nLen * 3 / 4; + pMalloc = operator new(nLastMallocSize); + } + + 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); + } + + 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; + } + } +} \ No newline at end of file diff --git a/SilentPatchSA/WaveDecoderSA.h b/SilentPatchSA/WaveDecoderSA.h new file mode 100644 index 0000000..98d2c19 --- /dev/null +++ b/SilentPatchSA/WaveDecoderSA.h @@ -0,0 +1,46 @@ +#pragma once + +#include "AudioHardwareSA.h" + +class CAEWaveDecoder : public CAEStreamingDecoder +{ +private: + unsigned int nDataSize; + unsigned int nOffsetToData; + //bool bInitialised; + + struct FormatChunk + { + unsigned short audioFormat; + unsigned short numChannels; + unsigned int sampleRate; + unsigned int byteRate; + unsigned short blockAlign; + unsigned short bitsPerSample; + } formatChunk; + +public: + CAEWaveDecoder(CAEDataStream* stream) + : CAEStreamingDecoder(stream) + {} + + virtual bool Initialise() override; + virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override; + + virtual unsigned int GetStreamLengthMs() override + { return static_cast(nDataSize) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } + virtual unsigned int GetStreamPlayTimeMs() override + { return static_cast(GetStream()->GetCurrentPosition() - nOffsetToData) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); } + + virtual void SetCursor(unsigned int 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); } + + virtual unsigned int GetSampleRate() override + { return formatChunk.sampleRate; } + + virtual unsigned int GetStreamID() override + { return GetStream()->GetID(); } +}; \ No newline at end of file