WAVE decoder

This commit is contained in:
Silent 2014-06-14 02:15:14 +02:00
parent 36fb6daa37
commit 4d97733c03
3 changed files with 321 additions and 59 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);