Files
FC1/CrySoundSystem/PCMDecoder.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

280 lines
7.4 KiB
C++

#include "StdAfx.h"
#include <CrySizer.h>
#include <ISound.h>
#include <ISystem.h>
#include <ICryPak.h>
#include "pcmdecoder.h"
CPCMDecoder::CPCMDecoder(IMusicSystem *pMusicSystem) : m_b44KHz(true)
{
m_pMusicSystem=pMusicSystem;
ISystem *pSystem=m_pMusicSystem->GetSystem();
ASSERT(pSystem);
m_pPak=pSystem->GetIPak();
ASSERT(m_pPak);
m_pFile=NULL;
}
CPCMDecoder::~CPCMDecoder()
{
Close();
}
int CPCMDecoder::ReadFile(void *pBuf, int nSize, int nCount, int *pNewFilePos)
{
if (!m_pFile)
return false;
int nBytesRead=m_pPak->FRead(pBuf, nSize, nCount, m_pFile);
if (nBytesRead!=nCount)
{
m_nPosBytes=m_pPak->FTell(m_pFile);
if (pNewFilePos)
*pNewFilePos=m_nPosBytes;
return 0;
}
m_nPosBytes+=nSize*nCount;
if (pNewFilePos)
*pNewFilePos=m_nPosBytes;
return nBytesRead;
}
bool CPCMDecoder::InitStreamWAV()
{
if (!m_pFile)
return false;
SWaveHdr WaveHeader;
if (!ReadFile(&WaveHeader, sizeof(SWaveHdr), 1))
return false;
if (WaveHeader.dwDSize==0)
{
TRACE("Warning: [CPCMDecoder::InitStreamWAV()] Cannot load file %s, due to zero-data-size !", m_FileInfo.sFilename.c_str());
return false;
}
/* if (WaveHeader.dwSRate!=44100)
{
TRACE("Warning: [CPCMDecoder::InitStreamWAV()] Cannot load file %s, due to unsupported samplerate (%d Hz found; 44100 Hz needed) !", m_FileInfo.sFilename.c_str(), WaveHeader.dwSRate);
return false;
}
*/ if (WaveHeader.wChnls!=2)
{
TRACE("Warning: [CPCMDecoder::InitStreamWAV()] Cannot load file %s, due to unsupported channel-number (%d channels found; 2 channels needed) !", m_FileInfo.sFilename.c_str(), WaveHeader.wChnls);
return false;
}
if (WaveHeader.BitsPerSample!=16)
{
TRACE("Warning: [CPCMDecoder::InitStreamWAV()] Cannot load file %s, due to unsupported resolution (%d bits/sample found; 16 bits/sample needed) !", m_FileInfo.sFilename.c_str(), WaveHeader.BitsPerSample);
return false;
}
m_PCMFileInfo.nBytesPerSample=WaveHeader.BitsPerSample/8*WaveHeader.wChnls;
m_FileInfo.nHeaderSize=sizeof(SWaveHdr);
m_FileInfo.nSamples=WaveHeader.dwDSize/m_PCMFileInfo.nBytesPerSample;
if(WaveHeader.dwSRate == 22050)
{
m_FileInfo.nSamples *= 2; //correct number if different in 22 KHz mode due to different file size
m_b44KHz = false;
}
else
m_b44KHz = true;
return true;
}
bool CPCMDecoder::Open(const char *pszFilename)
{
if (m_pFile)
return false;
m_pFile=m_pPak->FOpen(pszFilename, "rb");
if (!m_pFile)
return false;
m_nPosBytes=0;
m_FileInfo.sFilename=pszFilename;
if (!InitStreamWAV())
{
Close();
return false;
}
return true;
}
bool CPCMDecoder::Close()
{
if (!m_pFile)
return false;
m_pPak->FClose(m_pFile);
m_pFile=NULL;
return true;
}
bool CPCMDecoder::GetFileInfo(SMusicPatternFileInfo &FileInfo)
{
if (!m_pFile)
return false;
FileInfo=m_FileInfo;
return true;
}
void CPCMDecoder::GetMemoryUsage(class ICrySizer* pSizer)
{
if (!pSizer->Add(*this))
return;
}
IMusicPatternDecoderInstance* CPCMDecoder::CreateInstance()
{
return new CPCMDecoderInstance(this);
}
//////////////////////////////////////////////////////////////////////////
/*** INSTANCE ***/
//////////////////////////////////////////////////////////////////////////
CPCMDecoderInstance::CPCMDecoderInstance(CPCMDecoder *pDecoder) : m_bCopyFromLastFrame(false)
{
m_pDecoder=pDecoder;
Seek0();
}
CPCMDecoderInstance::~CPCMDecoderInstance()
{
}
bool CPCMDecoderInstance::SeekBytes(int nBytes)
{
if (!m_pDecoder->m_pFile)
return false;
m_nPosBytes=nBytes;
if (m_pDecoder->m_nPosBytes==nBytes)
return true;
if (m_pDecoder->m_pPak->FSeek(m_pDecoder->m_pFile, nBytes, SEEK_SET)!=0)
return false;
m_pDecoder->m_nPosBytes=nBytes;
return true;
}
bool CPCMDecoderInstance::Seek0(int nDelay)
{
m_nPos=-nDelay;
m_bCopyFromLastFrame = false;
return SeekBytes(m_pDecoder->m_FileInfo.nHeaderSize);
}
int CPCMDecoderInstance::GetPos()
{
if (!m_pDecoder->m_pFile)
return -1;
return m_nPos;
}
bool CPCMDecoderInstance::GetPCMData(signed long *pDataOut, int nSamples, bool bLoop)
{
if (!m_pDecoder->m_pFile)
return false;
int nOfs=0;
if (m_nPos<0)
{
if (-m_nPos>=nSamples)
{
memset(pDataOut, 0, nSamples*m_pDecoder->m_pMusicSystem->GetBytesPerSample());
m_nPos+=nSamples;
return true;
}else
{
nOfs=-m_nPos;
m_nPos=0;
nSamples-=nOfs;
memset(pDataOut, 0, nOfs*m_pDecoder->m_pMusicSystem->GetBytesPerSample());
}
}
if (!SeekBytes(m_nPosBytes))
return false;
int nSamplesToRead;
for (;;)
{
if ((m_nPos+nSamples)>m_pDecoder->m_FileInfo.nSamples)
nSamplesToRead=m_pDecoder->m_FileInfo.nSamples-m_nPos;
else
nSamplesToRead=nSamples;
if(m_pDecoder->Is44KHz())
{
if (!m_pDecoder->ReadFile(&(pDataOut[nOfs]), m_pDecoder->m_PCMFileInfo.nBytesPerSample, nSamplesToRead, &m_nPosBytes))
return false;
}
else
{
//decode for 44 KHz
if (!FillPCMBuffer22KHz(&(pDataOut[nOfs]), nSamplesToRead))
return false;
}
// FIXME: conversation of samplerate might be needed here
m_nPos+=nSamplesToRead;
if (nSamplesToRead==nSamples)
break;
nOfs+=nSamplesToRead;
if (!bLoop)
{
memset(&(pDataOut[nOfs]), 0, (nSamples-nSamplesToRead)*m_pDecoder->m_pMusicSystem->GetBytesPerSample());
break;
}
nSamples-=nSamplesToRead;
Seek0();
}
return true;
}
//! fills a dest buffer with uncompressed data
const bool CPCMDecoderInstance::FillPCMBuffer22KHz(signed long *pBuffer, int nSamples)
{
//first check for copying some data from last frame (if not at starting position)
if(m_bCopyFromLastFrame && m_nPos != 0)
{
*pBuffer++ = m_lLastSample;//contains sample to start with from last encoding
nSamples -= 1;
m_bCopyFromLastFrame = false;
}
const unsigned int cuiSamplesPerBlock = scuiEncodedBlockSize / m_pDecoder->m_PCMFileInfo.nBytesPerSample;//number of samples to read per block (according to allocated static array)
const unsigned int cuiBlocks = nSamples / (cuiSamplesPerBlock*2); //blocks to read, remember samples will be doubled
for(unsigned int i=0; i<cuiBlocks;i++)
{
if (!m_pDecoder->ReadFile(m_aEncodedBlock, m_pDecoder->m_PCMFileInfo.nBytesPerSample, cuiSamplesPerBlock, &m_nPosBytes))
return false;
//now double up interleaved samples
const signed long *pEncodedData = reinterpret_cast<signed long*>(&m_aEncodedBlock[0]);
for(unsigned int j=0; j<cuiSamplesPerBlock;j++)
{
*pBuffer++ = *pEncodedData; //double up samples
*pBuffer++ = *pEncodedData++;
}
nSamples -= (2*cuiSamplesPerBlock);
}
if(nSamples > 0)
{
//differentiate between a left odd and even sample count
if(nSamples & 0x1)
{
m_bCopyFromLastFrame = true;
//read one sample more
if (!m_pDecoder->ReadFile(m_aEncodedBlock, m_pDecoder->m_PCMFileInfo.nBytesPerSample, (nSamples/2)+1, &m_nPosBytes))
return false;
const signed long *pEncodedData = reinterpret_cast<signed long*>(&m_aEncodedBlock[0]);
for(int j=0; j<nSamples/2;j++)
{
*pBuffer++ = *pEncodedData; //double up samples
*pBuffer++ = *pEncodedData++;
}
*pBuffer++ = m_lLastSample = *pEncodedData; //remember last sample, has to start with in next request
}
else
{
//even count, no special treatment
m_bCopyFromLastFrame = false;
if (!m_pDecoder->ReadFile(m_aEncodedBlock, m_pDecoder->m_PCMFileInfo.nBytesPerSample, (nSamples/2), &m_nPosBytes))
return false;
const signed long *pEncodedData = reinterpret_cast<signed long*>(&m_aEncodedBlock[0]);
for(int j=0; j<nSamples/2;j++)
{
*pBuffer++ = *pEncodedData; //double up samples
*pBuffer++ = *pEncodedData++;
}
}
}
return true;
}