mirror of
https://github.com/CookiePLMonster/SilentPatch.git
synced 2024-11-22 05:22:32 +01:00
WAVE decoder
This commit is contained in:
parent
36fb6daa37
commit
4d97733c03
@ -5,12 +5,257 @@
|
||||
// { EAXJMP(0x4DC340); }
|
||||
//WRAPPER HRESULT STDMETHODCALLTYPE CAEDataStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) { EAXJMP(0x4DC3A0); }
|
||||
|
||||
//WRAPPER unsigned int CAEDataStream::FillBuffer(void* pBuf, unsigned long nLen) { EAXJMP(0x4DC1C0); }
|
||||
WRAPPER bool CAEDataStream::Initialise() { EAXJMP(0x4DC2B0); }
|
||||
|
||||
unsigned int CAEFLACDecoder::nRefCount = 0;
|
||||
unsigned int CAEStreamingDecoder::nMallocRefCount = 0;
|
||||
|
||||
static void* pMalloc = nullptr;
|
||||
static unsigned int nBlockSize = 0;
|
||||
static unsigned int nLastMallocSize = 0;
|
||||
|
||||
static unsigned int nSamplesLeftToProcess = 0;
|
||||
|
||||
unsigned int CAEDataStream::Seek(long nToSeek, int nPoint)
|
||||
{
|
||||
LONG nRealDistToSeek;
|
||||
|
||||
switch ( nPoint )
|
||||
{
|
||||
case FILE_BEGIN:
|
||||
nRealDistToSeek = nToSeek + dwStartPosition;
|
||||
break;
|
||||
case FILE_CURRENT:
|
||||
nRealDistToSeek = nToSeek;
|
||||
break;
|
||||
case FILE_END:
|
||||
nPoint = FILE_BEGIN;
|
||||
nRealDistToSeek = dwStartPosition + dwLength - nToSeek;
|
||||
break;
|
||||
}
|
||||
|
||||
dwCurrentPosition = SetFilePointer(hHandle, nRealDistToSeek, nullptr, nPoint);
|
||||
|
||||
return dwCurrentPosition - dwStartPosition;
|
||||
}
|
||||
|
||||
unsigned int CAEDataStream::FillBuffer(void* pBuf, unsigned long nLen)
|
||||
{
|
||||
//auto nSize = min(nLen, dwCurrentPosition - dwLength - dwStartPosition);
|
||||
//auto nHah = dwCurrentPosition - dwLength - dwStartPosition;
|
||||
ReadFile(hHandle, pBuf, nLen, &nLen, nullptr);
|
||||
|
||||
dwCurrentPosition += nLen;
|
||||
return nLen;
|
||||
}
|
||||
|
||||
CAEStreamingDecoder::~CAEStreamingDecoder()
|
||||
{
|
||||
GTAdelete(pStream);
|
||||
pStream = nullptr;
|
||||
|
||||
if ( --nMallocRefCount == 0 )
|
||||
{
|
||||
operator delete(pMalloc);
|
||||
pMalloc = nullptr;
|
||||
|
||||
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.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<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] = (static_cast<signed char>(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<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 )
|
||||
{
|
||||
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<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
|
||||
{
|
||||
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<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;
|
||||
pMalloc = operator new(nLastMallocSize);
|
||||
}
|
||||
|
||||
unsigned int nBytesWritten = GetStream()->FillBuffer(pMalloc, nLen / 2);
|
||||
signed short* pOutBuf = static_cast<signed short*>(pBuf);
|
||||
signed short* pInBuf = static_cast<signed short*>(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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//static bool bEOFFlag = false;
|
||||
|
||||
FLAC__StreamDecoderReadStatus CAEFLACDecoder::read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data)
|
||||
{
|
||||
@ -26,11 +271,6 @@ FLAC__StreamDecoderReadStatus CAEFLACDecoder::read_cb(const FLAC__StreamDecoder*
|
||||
return result;
|
||||
}
|
||||
|
||||
static FLAC__int32* pMalloc = nullptr;
|
||||
static unsigned int nBlockSize = 0;
|
||||
|
||||
static unsigned int nSamplesLeftToProcess = 0;
|
||||
|
||||
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<CAEFLACDecoder*>(client_data);
|
||||
@ -42,22 +282,21 @@ FLAC__StreamDecoderWriteStatus CAEFLACDecoder::write_cb(const FLAC__StreamDecode
|
||||
|
||||
// Mono/stereo?
|
||||
unsigned int nNumChannelsToAlloc = pClientData->pStreamInfo->data.stream_info.channels > 1 ? 2 : 1;
|
||||
static unsigned int nLastMallocSize;
|
||||
|
||||
if ( !pMalloc || frame->header.blocksize * sizeof(FLAC__int32) * nNumChannelsToAlloc > nLastMallocSize )
|
||||
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 = static_cast<FLAC__int32*>(operator new(nLastMallocSize)); // TODO: More channels?
|
||||
pMalloc = operator new(nLastMallocSize); // TODO: More channels?
|
||||
}
|
||||
nBlockSize = frame->header.blocksize;
|
||||
|
||||
memcpy(pMalloc, buffer[0], nBlockSize * sizeof(FLAC__int32));
|
||||
if ( nNumChannelsToAlloc > 1 )
|
||||
memcpy(pMalloc+nBlockSize, buffer[1], nBlockSize * sizeof(FLAC__int32));
|
||||
memcpy(static_cast<FLAC__int32*>(pMalloc)+nBlockSize, buffer[1], nBlockSize * sizeof(FLAC__int32));
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
@ -130,7 +369,7 @@ bool CAEFLACDecoder::Initialise()
|
||||
{
|
||||
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 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;
|
||||
}
|
||||
@ -161,7 +400,7 @@ unsigned int CAEFLACDecoder::FillBuffer(void* pBuf, unsigned long nLen)
|
||||
else
|
||||
nToWrite = nSamplesLeftToProcess;
|
||||
|
||||
FLAC__int32* pCurrentPtr[2] = { pMalloc, pMalloc+nBlockSize };
|
||||
FLAC__int32* pCurrentPtr[2] = { static_cast<FLAC__int32*>(pMalloc), static_cast<FLAC__int32*>(pMalloc)+nBlockSize };
|
||||
const unsigned int ExtraIndex = nBlockSize - nSamplesLeftToProcess;
|
||||
|
||||
// Write channels
|
||||
@ -254,10 +493,4 @@ CAEFLACDecoder::~CAEFLACDecoder()
|
||||
FLAC__metadata_object_delete(pStreamInfo);
|
||||
pFLACDecoder = nullptr;
|
||||
}
|
||||
|
||||
if ( --nRefCount == 0 )
|
||||
{
|
||||
operator delete(pMalloc);
|
||||
pMalloc = nullptr;
|
||||
}
|
||||
}
|
@ -84,7 +84,10 @@ public:
|
||||
|
||||
public:
|
||||
// Custom methods
|
||||
//unsigned int FillBuffer(void* pBuf, unsigned long nLen);
|
||||
unsigned int Seek(long nToSeek, int nPoint);
|
||||
unsigned int FillBuffer(void* pBuf, unsigned long nLen);
|
||||
unsigned int GetCurrentPosition()
|
||||
{ return SetFilePointer(hHandle, 0, nullptr, FILE_CURRENT) - dwStartPosition; }
|
||||
bool Initialise();
|
||||
};
|
||||
|
||||
@ -94,10 +97,14 @@ class CAEStreamingDecoder
|
||||
private:
|
||||
CAEDataStream* pStream;
|
||||
|
||||
static unsigned int nMallocRefCount;
|
||||
|
||||
public:
|
||||
CAEStreamingDecoder(CAEDataStream* stream)
|
||||
: pStream(stream)
|
||||
{
|
||||
++nMallocRefCount;
|
||||
|
||||
if ( stream )
|
||||
stream->Initialise();
|
||||
}
|
||||
@ -113,15 +120,57 @@ public:
|
||||
virtual void SetCursor(unsigned int nTime)=0;
|
||||
virtual unsigned int GetSampleRate()=0;
|
||||
|
||||
virtual ~CAEStreamingDecoder()
|
||||
{
|
||||
GTAdelete(pStream);
|
||||
pStream = nullptr;
|
||||
}
|
||||
virtual ~CAEStreamingDecoder();
|
||||
|
||||
virtual unsigned int GetStreamID()=0;
|
||||
};
|
||||
|
||||
class CAEWaveDecoder : public CAEStreamingDecoder
|
||||
{
|
||||
private:
|
||||
unsigned short nNumChannels;
|
||||
unsigned short nBitRate;
|
||||
unsigned int nSampleRate;
|
||||
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)//, bInitialised(false)
|
||||
{}
|
||||
|
||||
virtual bool Initialise() override;
|
||||
virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override;
|
||||
|
||||
virtual unsigned int GetStreamLengthMs() override
|
||||
{ return static_cast<unsigned long long>(nDataSize) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); }
|
||||
virtual unsigned int GetStreamPlayTimeMs() override
|
||||
{ return static_cast<unsigned long long>(GetStream()->GetCurrentPosition() - nOffsetToData) * 8000 / (formatChunk.sampleRate*formatChunk.bitsPerSample*formatChunk.numChannels); }
|
||||
|
||||
virtual void SetCursor(unsigned int nTime) override
|
||||
{ auto nPos = static_cast<unsigned long long>(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:
|
||||
@ -129,8 +178,6 @@ private:
|
||||
FLAC__StreamMetadata* pStreamInfo;
|
||||
unsigned int nCurrentSample;
|
||||
|
||||
static unsigned int nRefCount;
|
||||
|
||||
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);
|
||||
@ -144,42 +191,21 @@ private:
|
||||
public:
|
||||
CAEFLACDecoder(CAEDataStream* stream)
|
||||
: CAEStreamingDecoder(stream), pFLACDecoder(nullptr)
|
||||
{
|
||||
++nRefCount;
|
||||
}
|
||||
{}
|
||||
|
||||
virtual ~CAEFLACDecoder();
|
||||
|
||||
virtual bool Initialise() override;
|
||||
|
||||
virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override;
|
||||
|
||||
virtual unsigned int GetStreamLengthMs() override
|
||||
{
|
||||
unsigned int nTime = pStreamInfo->data.stream_info.total_samples * 1000 / pStreamInfo->data.stream_info.sample_rate;
|
||||
return nTime;
|
||||
}
|
||||
|
||||
{ return pStreamInfo->data.stream_info.total_samples * 1000 / pStreamInfo->data.stream_info.sample_rate; }
|
||||
virtual unsigned int GetStreamPlayTimeMs() override
|
||||
{
|
||||
unsigned int nTime = nCurrentSample * 1000 / pStreamInfo->data.stream_info.sample_rate;
|
||||
return nTime;
|
||||
}
|
||||
|
||||
{ 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);
|
||||
}
|
||||
|
||||
{ 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;
|
||||
}
|
||||
|
||||
{ return pStreamInfo->data.stream_info.sample_rate; }
|
||||
virtual unsigned int GetStreamID() override
|
||||
{
|
||||
return GetStream()->GetID();
|
||||
}
|
||||
{ return GetStream()->GetID(); }
|
||||
};
|
||||
|
||||
#endif
|
@ -1336,7 +1336,7 @@ void __declspec(naked) ResetAlphaFuncRefAfterRender()
|
||||
}
|
||||
}
|
||||
|
||||
static bool bUseTwoPass = false;
|
||||
static bool bUseTwoPass = true;
|
||||
|
||||
void SetRendererForAtomic(RpAtomic* pAtomic)
|
||||
{
|
||||
@ -1776,9 +1776,9 @@ static CAEFLACDecoder* __stdcall DecoderCtor(CAEDataStream* pData)
|
||||
return new CAEFLACDecoder(pData);
|
||||
}
|
||||
|
||||
static void __stdcall StreamDtor(CAEDataStream* pData)
|
||||
static CAEWaveDecoder* __stdcall CAEWaveDecoderInit(CAEDataStream* pStream)
|
||||
{
|
||||
delete pData;
|
||||
return new CAEWaveDecoder(pStream);
|
||||
}
|
||||
|
||||
void __declspec(naked) LoadFLAC()
|
||||
@ -2032,7 +2032,10 @@ __forceinline void Patch_SA_10()
|
||||
// FLAC support
|
||||
InjectHook(0x4F373D, LoadFLAC, PATCH_JUMP);
|
||||
InjectHook(0x4F35E0, FLACInit, PATCH_JUMP);
|
||||
InjectHook(0x4F3787, CAEWaveDecoderInit);
|
||||
|
||||
Patch<WORD>(0x4F376A, 0x18EB);
|
||||
//Patch<BYTE>(0x4F378F, sizeof(CAEWaveDecoder));
|
||||
Patch<const void*>(0x4F3210, UserTrackExtensions);
|
||||
Patch<const void*>(0x4F3241, &UserTrackExtensions->Codec);
|
||||
//Patch<const void*>(0x4F35E7, &UserTrackExtensions[1].Codec);
|
||||
|
Loading…
Reference in New Issue
Block a user