mirror of
https://github.com/CookiePLMonster/SilentPatch.git
synced 2024-12-28 23:03:01 +05:00
WAVE decoder
This commit is contained in:
parent
36fb6daa37
commit
4d97733c03
3 changed files with 321 additions and 59 deletions
|
@ -5,12 +5,257 @@
|
||||||
// { EAXJMP(0x4DC340); }
|
// { EAXJMP(0x4DC340); }
|
||||||
//WRAPPER HRESULT STDMETHODCALLTYPE CAEDataStream::Stat(STATSTG* pStatstg, DWORD grfStatFlag) { EAXJMP(0x4DC3A0); }
|
//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); }
|
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)
|
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;
|
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)
|
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);
|
CAEFLACDecoder* pClientData = static_cast<CAEFLACDecoder*>(client_data);
|
||||||
|
@ -42,22 +282,21 @@ FLAC__StreamDecoderWriteStatus CAEFLACDecoder::write_cb(const FLAC__StreamDecode
|
||||||
|
|
||||||
// Mono/stereo?
|
// Mono/stereo?
|
||||||
unsigned int nNumChannelsToAlloc = pClientData->pStreamInfo->data.stream_info.channels > 1 ? 2 : 1;
|
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
|
// Realloc needed
|
||||||
if ( pMalloc )
|
if ( pMalloc )
|
||||||
operator delete(pMalloc);
|
operator delete(pMalloc);
|
||||||
|
|
||||||
nLastMallocSize = frame->header.blocksize * sizeof(FLAC__int32) * nNumChannelsToAlloc;
|
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;
|
nBlockSize = frame->header.blocksize;
|
||||||
|
|
||||||
memcpy(pMalloc, buffer[0], nBlockSize * sizeof(FLAC__int32));
|
memcpy(pMalloc, buffer[0], nBlockSize * sizeof(FLAC__int32));
|
||||||
if ( nNumChannelsToAlloc > 1 )
|
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;
|
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +369,7 @@ bool CAEFLACDecoder::Initialise()
|
||||||
{
|
{
|
||||||
FLAC__stream_decoder_process_until_end_of_metadata(pFLACDecoder);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -161,7 +400,7 @@ unsigned int CAEFLACDecoder::FillBuffer(void* pBuf, unsigned long nLen)
|
||||||
else
|
else
|
||||||
nToWrite = nSamplesLeftToProcess;
|
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;
|
const unsigned int ExtraIndex = nBlockSize - nSamplesLeftToProcess;
|
||||||
|
|
||||||
// Write channels
|
// Write channels
|
||||||
|
@ -254,10 +493,4 @@ CAEFLACDecoder::~CAEFLACDecoder()
|
||||||
FLAC__metadata_object_delete(pStreamInfo);
|
FLAC__metadata_object_delete(pStreamInfo);
|
||||||
pFLACDecoder = nullptr;
|
pFLACDecoder = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( --nRefCount == 0 )
|
|
||||||
{
|
|
||||||
operator delete(pMalloc);
|
|
||||||
pMalloc = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -84,7 +84,10 @@ public:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Custom methods
|
// 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();
|
bool Initialise();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,10 +97,14 @@ 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 )
|
if ( stream )
|
||||||
stream->Initialise();
|
stream->Initialise();
|
||||||
}
|
}
|
||||||
|
@ -113,15 +120,57 @@ public:
|
||||||
virtual void SetCursor(unsigned int nTime)=0;
|
virtual void SetCursor(unsigned int nTime)=0;
|
||||||
virtual unsigned int GetSampleRate()=0;
|
virtual unsigned int GetSampleRate()=0;
|
||||||
|
|
||||||
virtual ~CAEStreamingDecoder()
|
virtual ~CAEStreamingDecoder();
|
||||||
{
|
|
||||||
GTAdelete(pStream);
|
|
||||||
pStream = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual unsigned int GetStreamID()=0;
|
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
|
class CAEFLACDecoder : public CAEStreamingDecoder
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
@ -129,8 +178,6 @@ private:
|
||||||
FLAC__StreamMetadata* pStreamInfo;
|
FLAC__StreamMetadata* pStreamInfo;
|
||||||
unsigned int nCurrentSample;
|
unsigned int nCurrentSample;
|
||||||
|
|
||||||
static unsigned int nRefCount;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder* decoder, FLAC__byte buffer[], size_t* bytes, void* client_data);
|
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 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:
|
public:
|
||||||
CAEFLACDecoder(CAEDataStream* stream)
|
CAEFLACDecoder(CAEDataStream* stream)
|
||||||
: CAEStreamingDecoder(stream), pFLACDecoder(nullptr)
|
: CAEStreamingDecoder(stream), pFLACDecoder(nullptr)
|
||||||
{
|
{}
|
||||||
++nRefCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~CAEFLACDecoder();
|
virtual ~CAEFLACDecoder();
|
||||||
|
|
||||||
virtual bool Initialise() override;
|
virtual bool Initialise() override;
|
||||||
|
|
||||||
virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override;
|
virtual unsigned int FillBuffer(void* pBuf, unsigned long nLen) override;
|
||||||
|
|
||||||
virtual unsigned int GetStreamLengthMs() override
|
virtual unsigned int GetStreamLengthMs() override
|
||||||
{
|
{ return pStreamInfo->data.stream_info.total_samples * 1000 / pStreamInfo->data.stream_info.sample_rate; }
|
||||||
unsigned int nTime = pStreamInfo->data.stream_info.total_samples * 1000 / pStreamInfo->data.stream_info.sample_rate;
|
|
||||||
return nTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual unsigned int GetStreamPlayTimeMs() override
|
virtual unsigned int GetStreamPlayTimeMs() override
|
||||||
{
|
{ return nCurrentSample * 1000 / pStreamInfo->data.stream_info.sample_rate; }
|
||||||
unsigned int nTime = nCurrentSample * 1000 / pStreamInfo->data.stream_info.sample_rate;
|
|
||||||
return nTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void SetCursor(unsigned int nTime) override
|
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
|
virtual unsigned int GetSampleRate() override
|
||||||
{
|
{ return pStreamInfo->data.stream_info.sample_rate; }
|
||||||
return pStreamInfo->data.stream_info.sample_rate;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual unsigned int GetStreamID() override
|
virtual unsigned int GetStreamID() override
|
||||||
{
|
{ return GetStream()->GetID(); }
|
||||||
return GetStream()->GetID();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -1336,7 +1336,7 @@ void __declspec(naked) ResetAlphaFuncRefAfterRender()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bUseTwoPass = false;
|
static bool bUseTwoPass = true;
|
||||||
|
|
||||||
void SetRendererForAtomic(RpAtomic* pAtomic)
|
void SetRendererForAtomic(RpAtomic* pAtomic)
|
||||||
{
|
{
|
||||||
|
@ -1776,9 +1776,9 @@ static CAEFLACDecoder* __stdcall DecoderCtor(CAEDataStream* pData)
|
||||||
return new CAEFLACDecoder(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()
|
void __declspec(naked) LoadFLAC()
|
||||||
|
@ -2032,7 +2032,10 @@ __forceinline void Patch_SA_10()
|
||||||
// FLAC support
|
// FLAC support
|
||||||
InjectHook(0x4F373D, LoadFLAC, PATCH_JUMP);
|
InjectHook(0x4F373D, LoadFLAC, PATCH_JUMP);
|
||||||
InjectHook(0x4F35E0, FLACInit, 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*>(0x4F3210, UserTrackExtensions);
|
||||||
Patch<const void*>(0x4F3241, &UserTrackExtensions->Codec);
|
Patch<const void*>(0x4F3241, &UserTrackExtensions->Codec);
|
||||||
//Patch<const void*>(0x4F35E7, &UserTrackExtensions[1].Codec);
|
//Patch<const void*>(0x4F35E7, &UserTrackExtensions[1].Codec);
|
||||||
|
|
Loading…
Reference in a new issue