mirror of
https://github.com/CookiePLMonster/SilentPatch.git
synced 2024-12-29 15:23:02 +05:00
Audio decoders split into separate files
This commit is contained in:
parent
005436d348
commit
94fe7f01bd
9 changed files with 556 additions and 523 deletions
|
@ -1,10 +1,6 @@
|
||||||
#include "StdAfxSA.h"
|
#include "StdAfxSA.h"
|
||||||
#include "AudioHardwareSA.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;
|
bool CAEDataStream::m_bUseNewStruct;
|
||||||
|
|
||||||
static void* CAEDataStream__Initialise = AddressByVersion<void*>(0x4DC2B0, 0x4DC7A0, 0x4E7550);
|
static void* CAEDataStream__Initialise = AddressByVersion<void*>(0x4DC2B0, 0x4DC7A0, 0x4E7550);
|
||||||
|
@ -12,11 +8,9 @@ WRAPPER bool CAEDataStream::Initialise() { VARJMP(CAEDataStream__Initialise); }
|
||||||
|
|
||||||
unsigned int CAEStreamingDecoder::nMallocRefCount = 0;
|
unsigned int CAEStreamingDecoder::nMallocRefCount = 0;
|
||||||
|
|
||||||
static void* pMalloc = nullptr;
|
void* pMalloc = nullptr;
|
||||||
static unsigned int nBlockSize = 0;
|
unsigned int nBlockSize = 0;
|
||||||
static unsigned int nLastMallocSize = 0;
|
unsigned int nLastMallocSize = 0;
|
||||||
|
|
||||||
static unsigned int nSamplesLeftToProcess = 0;
|
|
||||||
|
|
||||||
unsigned int CAEDataStreamOld::Seek(long nToSeek, int nPoint)
|
unsigned int CAEDataStreamOld::Seek(long nToSeek, int nPoint)
|
||||||
{
|
{
|
||||||
|
@ -85,437 +79,4 @@ CAEStreamingDecoder::~CAEStreamingDecoder()
|
||||||
|
|
||||||
nLastMallocSize = 0;
|
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<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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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<CAEFLACDecoder*>(client_data);
|
|
||||||
|
|
||||||
ReadFile(pClientData->GetStream()->GetFile(), buffer, *bytes, reinterpret_cast<LPDWORD>(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<CAEFLACDecoder*>(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<FLAC__int32*>(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<CAEFLACDecoder*>(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<CAEFLACDecoder*>(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<CAEFLACDecoder*>(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<CAEFLACDecoder*>(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<FLAC__int16*>(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<FLAC__int32*>(pMalloc), static_cast<FLAC__int32*>(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;
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
// libflac
|
// libflac
|
||||||
#define FLAC__NO_DLL
|
#define FLAC__NO_DLL
|
||||||
#include "share\compat.h"
|
|
||||||
#include "FLAC\stream_decoder.h"
|
#include "FLAC\stream_decoder.h"
|
||||||
#include "FLAC\metadata.h"
|
#include "FLAC\metadata.h"
|
||||||
|
|
||||||
|
@ -234,84 +233,4 @@ public:
|
||||||
virtual unsigned int GetStreamID()=0;
|
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<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:
|
|
||||||
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
|
#endif
|
246
SilentPatchSA/FLACDecoderSA.cpp
Normal file
246
SilentPatchSA/FLACDecoderSA.cpp
Normal file
|
@ -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<CAEFLACDecoder*>(client_data);
|
||||||
|
|
||||||
|
ReadFile(pClientData->GetStream()->GetFile(), buffer, *bytes, reinterpret_cast<LPDWORD>(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<CAEFLACDecoder*>(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<FLAC__int32*>(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<CAEFLACDecoder*>(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<CAEFLACDecoder*>(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<CAEFLACDecoder*>(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<CAEFLACDecoder*>(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<FLAC__int16*>(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<FLAC__int32*>(pMalloc), static_cast<FLAC__int32*>(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;
|
||||||
|
}
|
||||||
|
}
|
40
SilentPatchSA/FLACDecoderSA.h
Normal file
40
SilentPatchSA/FLACDecoderSA.h
Normal file
|
@ -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(); }
|
||||||
|
};
|
|
@ -11,6 +11,9 @@
|
||||||
#include "LinkListSA.h"
|
#include "LinkListSA.h"
|
||||||
#include "PNGFile.h"
|
#include "PNGFile.h"
|
||||||
|
|
||||||
|
#include "WaveDecoderSA.h"
|
||||||
|
#include "FLACDecoderSA.h"
|
||||||
|
|
||||||
// RW wrappers
|
// RW wrappers
|
||||||
static void* varAtomicDefaultRenderCallBack = AddressByVersion<void*>(0x7491C0, 0x749AD0, 0x783180);
|
static void* varAtomicDefaultRenderCallBack = AddressByVersion<void*>(0x7491C0, 0x749AD0, 0x783180);
|
||||||
WRAPPER RpAtomic* AtomicDefaultRenderCallBack(RpAtomic* atomic) { WRAPARG(atomic); VARJMP(varAtomicDefaultRenderCallBack); }
|
WRAPPER RpAtomic* AtomicDefaultRenderCallBack(RpAtomic* atomic) { WRAPARG(atomic); VARJMP(varAtomicDefaultRenderCallBack); }
|
||||||
|
|
|
@ -113,6 +113,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="AudioHardwareSA.cpp" />
|
<ClCompile Include="AudioHardwareSA.cpp" />
|
||||||
|
<ClCompile Include="FLACDecoderSA.cpp" />
|
||||||
<ClCompile Include="GeneralSA.cpp" />
|
<ClCompile Include="GeneralSA.cpp" />
|
||||||
<ClCompile Include="ModelInfoSA.cpp" />
|
<ClCompile Include="ModelInfoSA.cpp" />
|
||||||
<ClCompile Include="PedSA.cpp" />
|
<ClCompile Include="PedSA.cpp" />
|
||||||
|
@ -125,6 +126,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClCompile Include="TimerSA.cpp" />
|
<ClCompile Include="TimerSA.cpp" />
|
||||||
<ClCompile Include="VehicleSA.cpp" />
|
<ClCompile Include="VehicleSA.cpp" />
|
||||||
|
<ClCompile Include="WaveDecoderSA.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<FxCompile Include="..\SilentPatch\nvc.fx">
|
<FxCompile Include="..\SilentPatch\nvc.fx">
|
||||||
|
@ -153,6 +155,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio
|
||||||
<ClInclude Include="..\SilentPatch\MemoryMgr.h" />
|
<ClInclude Include="..\SilentPatch\MemoryMgr.h" />
|
||||||
<ClInclude Include="..\SilentPatch\Timer.h" />
|
<ClInclude Include="..\SilentPatch\Timer.h" />
|
||||||
<ClInclude Include="AudioHardwareSA.h" />
|
<ClInclude Include="AudioHardwareSA.h" />
|
||||||
|
<ClInclude Include="FLACDecoderSA.h" />
|
||||||
<ClInclude Include="GeneralSA.h" />
|
<ClInclude Include="GeneralSA.h" />
|
||||||
<ClInclude Include="LinkListSA.h" />
|
<ClInclude Include="LinkListSA.h" />
|
||||||
<ClInclude Include="Maths.h" />
|
<ClInclude Include="Maths.h" />
|
||||||
|
@ -164,6 +167,7 @@ copy /y "$(TargetPath)" "D:\gry\GTA San Andreas clean\scripts\newsteam_r2_lowvio
|
||||||
<ClInclude Include="StdAfxSA.h" />
|
<ClInclude Include="StdAfxSA.h" />
|
||||||
<ClInclude Include="TimerSA.h" />
|
<ClInclude Include="TimerSA.h" />
|
||||||
<ClInclude Include="VehicleSA.h" />
|
<ClInclude Include="VehicleSA.h" />
|
||||||
|
<ClInclude Include="WaveDecoderSA.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="Shaders.rc" />
|
<ResourceCompile Include="Shaders.rc" />
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
<Filter Include="Header Files\FLAC">
|
<Filter Include="Header Files\FLAC">
|
||||||
<UniqueIdentifier>{57615a2f-8bc4-461f-b9f6-86d5f8286d7a}</UniqueIdentifier>
|
<UniqueIdentifier>{57615a2f-8bc4-461f-b9f6-86d5f8286d7a}</UniqueIdentifier>
|
||||||
</Filter>
|
</Filter>
|
||||||
|
<Filter Include="Source Files\decoders">
|
||||||
|
<UniqueIdentifier>{f4ecbe23-228b-461b-b37f-d718e7ca92ae}</UniqueIdentifier>
|
||||||
|
</Filter>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="SilentPatchSA.cpp">
|
<ClCompile Include="SilentPatchSA.cpp">
|
||||||
|
@ -51,6 +54,12 @@
|
||||||
<ClCompile Include="PedSA.cpp">
|
<ClCompile Include="PedSA.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="WaveDecoderSA.cpp">
|
||||||
|
<Filter>Source Files\decoders</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="FLACDecoderSA.cpp">
|
||||||
|
<Filter>Source Files\decoders</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\SilentPatch\MemoryMgr.h">
|
<ClInclude Include="..\SilentPatch\MemoryMgr.h">
|
||||||
|
@ -113,6 +122,12 @@
|
||||||
<ClInclude Include="resource.h">
|
<ClInclude Include="resource.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="WaveDecoderSA.h">
|
||||||
|
<Filter>Source Files\decoders</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="FLACDecoderSA.h">
|
||||||
|
<Filter>Source Files\decoders</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ResourceCompile Include="Shaders.rc">
|
<ResourceCompile Include="Shaders.rc">
|
||||||
|
|
199
SilentPatchSA/WaveDecoderSA.cpp
Normal file
199
SilentPatchSA/WaveDecoderSA.cpp
Normal file
|
@ -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<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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
46
SilentPatchSA/WaveDecoderSA.h
Normal file
46
SilentPatchSA/WaveDecoderSA.h
Normal file
|
@ -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<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(); }
|
||||||
|
};
|
Loading…
Reference in a new issue