2017-03-02 04:40:55 +05:00
|
|
|
#include "StdAfxSA.h"
|
|
|
|
#include "WaveDecoderSA.h"
|
|
|
|
|
|
|
|
bool CAEWaveDecoder::Initialise()
|
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
CAEDataStream* pTheStream = GetStream();
|
2017-03-02 04:40:55 +05:00
|
|
|
struct {
|
|
|
|
char sectionID[4];
|
2017-03-04 01:20:30 +05:00
|
|
|
uint32_t sectionSize;
|
2017-03-02 04:40:55 +05:00
|
|
|
} chunkHeader;
|
|
|
|
|
|
|
|
// Find fmt section
|
|
|
|
pTheStream->Seek(12, FILE_BEGIN);
|
|
|
|
|
|
|
|
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
|
2017-03-04 01:20:30 +05:00
|
|
|
m_offsetToData = 12 + sizeof(chunkHeader);
|
2017-03-02 04:40:55 +05:00
|
|
|
|
|
|
|
while ( chunkHeader.sectionID[0] != 'f' || chunkHeader.sectionID[1] != 'm' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != ' ' )
|
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
m_offsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize;
|
2017-03-02 04:40:55 +05:00
|
|
|
|
|
|
|
pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT);
|
|
|
|
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read fmt header
|
2017-03-04 01:20:30 +05:00
|
|
|
pTheStream->FillBuffer(&m_formatChunk, sizeof(m_formatChunk));
|
|
|
|
m_offsetToData += sizeof(m_formatChunk);
|
2017-03-02 04:40:55 +05:00
|
|
|
|
|
|
|
// Now skip through the rest of a chunk
|
2017-03-04 01:20:30 +05:00
|
|
|
if ( chunkHeader.sectionSize - sizeof(m_formatChunk) > 0 )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
m_offsetToData += chunkHeader.sectionSize - sizeof(m_formatChunk);
|
|
|
|
pTheStream->Seek(chunkHeader.sectionSize - sizeof(m_formatChunk), FILE_CURRENT);
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Find data chunk
|
2017-03-04 01:20:30 +05:00
|
|
|
m_offsetToData += sizeof(chunkHeader);
|
2017-03-02 04:40:55 +05:00
|
|
|
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
|
|
|
|
|
|
|
|
while ( chunkHeader.sectionID[0] != 'd' || chunkHeader.sectionID[1] != 'a' || chunkHeader.sectionID[2] != 't' || chunkHeader.sectionID[3] != 'a' )
|
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
m_offsetToData += sizeof(chunkHeader) + chunkHeader.sectionSize;
|
2017-03-02 04:40:55 +05:00
|
|
|
|
|
|
|
pTheStream->Seek(chunkHeader.sectionSize, FILE_CURRENT);
|
|
|
|
pTheStream->FillBuffer(&chunkHeader, sizeof(chunkHeader));
|
|
|
|
}
|
|
|
|
|
2017-03-04 01:20:30 +05:00
|
|
|
m_dataSize = chunkHeader.sectionSize;
|
2017-03-02 04:40:55 +05:00
|
|
|
|
2017-03-04 01:20:30 +05:00
|
|
|
return m_formatChunk.sampleRate <= 48000 && m_formatChunk.numChannels <= 2 && (m_formatChunk.bitsPerSample == 8 || m_formatChunk.bitsPerSample == 16 || m_formatChunk.bitsPerSample == 24);
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
|
|
|
|
2017-03-02 05:35:13 +05:00
|
|
|
uint32_t CAEWaveDecoder::FillBuffer(void* pBuf, uint32_t nLen)
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
size_t curBlockSize = CalcBufferSize( nLen );
|
|
|
|
if ( curBlockSize > m_maxBlockSize )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
delete[] m_buffer;
|
|
|
|
m_buffer = new uint8_t[curBlockSize];
|
|
|
|
m_maxBlockSize = curBlockSize;
|
|
|
|
}
|
|
|
|
else if ( curBlockSize == 0 )
|
|
|
|
{
|
|
|
|
return GetStream()->FillBuffer( pBuf, nLen );
|
|
|
|
}
|
2017-03-02 04:40:55 +05:00
|
|
|
|
2017-03-04 01:20:30 +05:00
|
|
|
uint32_t bytesRead = GetStream()->FillBuffer( m_buffer, curBlockSize );
|
|
|
|
size_t samplesRead = bytesRead / m_formatChunk.blockAlign;
|
2017-03-02 04:40:55 +05:00
|
|
|
|
2017-03-04 01:20:30 +05:00
|
|
|
if ( m_formatChunk.bitsPerSample == 16 )
|
|
|
|
{
|
|
|
|
assert( m_formatChunk.numChannels == 1 );
|
|
|
|
if ( m_formatChunk.numChannels == 1 )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
int16_t* inputBuf = (int16_t*)m_buffer;
|
|
|
|
int16_t* outputBuf = (int16_t*)pBuf;
|
|
|
|
for ( size_t i = 0; i < samplesRead; ++i )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
*outputBuf = *(outputBuf+1) = *inputBuf++;
|
|
|
|
outputBuf += 2;
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
2017-03-04 01:20:30 +05:00
|
|
|
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
|
|
|
}
|
2017-03-04 01:20:30 +05:00
|
|
|
else if ( m_formatChunk.bitsPerSample == 8 )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
if ( m_formatChunk.numChannels == 2 )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
uint8_t* inputBuf = (uint8_t*)m_buffer;
|
|
|
|
int16_t* outputBuf = (int16_t*)pBuf;
|
|
|
|
for ( size_t i = 0; i < samplesRead; ++i )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
*outputBuf++ = (static_cast<signed char>(*inputBuf++) - 128) << 8;
|
|
|
|
*outputBuf++ = (static_cast<signed char>(*inputBuf++) - 128) << 8;
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
uint8_t* inputBuf = (uint8_t*)m_buffer;
|
|
|
|
int16_t* outputBuf = (int16_t*)pBuf;
|
|
|
|
for ( size_t i = 0; i < samplesRead; ++i )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
*outputBuf = *(outputBuf+1) = (static_cast<signed char>(*inputBuf++) - 128) << 8;
|
|
|
|
outputBuf += 2;
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-04 01:20:30 +05:00
|
|
|
else if ( m_formatChunk.bitsPerSample == 24 )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
if ( m_formatChunk.numChannels == 2 )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
uint8_t* inputBuf = (uint8_t*)m_buffer;
|
|
|
|
int16_t* outputBuf = (int16_t*)pBuf;
|
|
|
|
for ( size_t i = 0; i < samplesRead; ++i )
|
|
|
|
{
|
|
|
|
*outputBuf++ = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3;
|
|
|
|
*outputBuf++ = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3;
|
|
|
|
}
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
uint8_t* inputBuf = (uint8_t*)m_buffer;
|
|
|
|
int16_t* outputBuf = (int16_t*)pBuf;
|
|
|
|
for ( size_t i = 0; i < samplesRead; ++i )
|
2017-03-02 04:40:55 +05:00
|
|
|
{
|
2017-03-04 01:20:30 +05:00
|
|
|
*outputBuf = *(outputBuf+1) = *(inputBuf+1) | (*(inputBuf+2) << 8); inputBuf += 3;
|
|
|
|
outputBuf += 2;
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-03-04 01:20:30 +05:00
|
|
|
|
|
|
|
return samplesRead * (2*sizeof(int16_t));
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t CAEWaveDecoder::CalcBufferSize( uint32_t outputBuf )
|
|
|
|
{
|
|
|
|
uint32_t requestedSamples = outputBuf / (2*sizeof(int16_t));
|
|
|
|
size_t requiredSize = m_formatChunk.blockAlign * requestedSamples;
|
|
|
|
return requiredSize == outputBuf ? 0 : requiredSize;
|
2017-03-02 04:40:55 +05:00
|
|
|
}
|