142 lines
5.7 KiB
C++
142 lines
5.7 KiB
C++
#pragma once
|
|
|
|
#include "PatternDecoder.h"
|
|
#include <string>
|
|
|
|
struct IMusicSystem;
|
|
class CADPCMDecoderInstance;
|
|
struct ICryPak;
|
|
|
|
//specific header struct for ADPCM, data stored in a slidely different manner than usual wav
|
|
typedef struct SADPCMWaveHdr
|
|
{
|
|
char RIFF[4]; // "RIFF" tag, identifies it as WAV
|
|
unsigned long dwSize; // Size of data to follow (filesize-8)
|
|
char WAVE[4]; // "WAVE" tag
|
|
char fmt_[4]; // "fmt " tag
|
|
unsigned long dw16; // 16
|
|
unsigned short FormatTag; // should be WAVE_FORMAT_ADPCM=2
|
|
unsigned short wChnls; // Number of Channels (1 for mono, 2 for stereo), should be always 2
|
|
unsigned long dwSRate; // Sample Rate
|
|
unsigned long BytesPerSec; // Bytes per second
|
|
unsigned short wBlkAlign; // Block align, usually 2048
|
|
unsigned short BitsPerSample; // Bits Per Sample, usually 4
|
|
unsigned short wExtSize; // not important
|
|
unsigned short SamplesPerBlock; // samples per block, usually 2036
|
|
//followed by number of coeficients and coeficients themselves
|
|
} SADPCMWaveHdr;
|
|
|
|
struct MsState
|
|
{
|
|
int step;
|
|
short sCoef0;
|
|
short sCoef1;
|
|
};
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class CADPCMDecoder : public IMusicPatternDecoder
|
|
{
|
|
public:
|
|
static const unsigned int scuiSizeOfWavHeader = sizeof(SWaveHdr); //need to hardcode here since SADPCMWaveHdr is not complined with usual header
|
|
|
|
CADPCMDecoder(IMusicSystem *pMusicSystem);
|
|
void Release() { delete this; }
|
|
//! Open a music-pattern-file, does actually just store filename
|
|
bool Open(const char *pszFilename);
|
|
//! Close a music-pattern-file.
|
|
bool Close();
|
|
//! Retrieve file-info
|
|
bool GetFileInfo(SMusicPatternFileInfo &FileInfo);
|
|
//! Retrieve mem-info
|
|
void GetMemoryUsage(class ICrySizer* pSizer);
|
|
//! Create instance.
|
|
IMusicPatternDecoderInstance* CreateInstance();
|
|
//! returns new file handle
|
|
FILE* GetNewFileHandle();
|
|
//! returns new file handle
|
|
void CloseFileHandle(FILE*& pFile);
|
|
//! retreieves file name
|
|
const char* FileName() const;
|
|
//! decode function for one block
|
|
static void AdpcmBlockExpandI( int nCoef, const short* iCoef, const unsigned char* ibuff, short* obuff, int n );
|
|
const bool IsOpen()const;
|
|
//! retrieves frequency encoding
|
|
const bool Is44KHz() const {return m_b44KHz;}
|
|
|
|
protected:
|
|
bool m_b44KHz; //keeps track of encoded frequency
|
|
|
|
//! decode function for one sample, called exclusively by AdpcmBlockExpandI
|
|
static int CADPCMDecoder::AdpcmDecode( int c, MsState& rState, int sample1, int sample2 );
|
|
void SetFileInfo(const unsigned int cuiSampleCount, const bool cbIs44KHz = true);
|
|
|
|
virtual ~CADPCMDecoder();
|
|
|
|
IMusicSystem *m_pMusicSystem;
|
|
ICryPak *m_pPak;
|
|
SMusicPatternFileInfo m_FileInfo;
|
|
string m_szFilename;
|
|
bool m_bOpen; //keeps track for an open command
|
|
|
|
friend class CADPCMDecoderInstance;
|
|
};
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
class CADPCMDecoderInstance : public IMusicPatternDecoderInstance
|
|
{
|
|
public:
|
|
//hardcoded constants, can be changed when using a different format
|
|
static const unsigned int scuiBlockSize = 2048; //constant value in 44 KHz Microsoft format, half the size for 22KHz
|
|
static const unsigned int scuiSamplesPerBlock = 2036; //constant value in 44 KHz Microsoft format, half the size for 22KHz
|
|
static const unsigned int scuiNumberOfCoefs = 7; //constant number of coefs
|
|
|
|
CADPCMDecoderInstance(CADPCMDecoder *pDecoder); //initializes as well
|
|
void Release() { Close(); delete this; }
|
|
//! Seek to beginning of pattern (if nDelay is set it will wait nDelay-samples before starting playback).
|
|
bool Seek0(int nDelay=0);
|
|
//! Retrieve the current position in the file (in samples)
|
|
int GetPos();
|
|
//! Decode and retrieve pcm-data (stereo/16bit).
|
|
bool GetPCMData(signed long *pDataOut, int nSamples, bool bLoop=true);
|
|
//! closes all
|
|
void Close();
|
|
//! retrieves number of total contained samples
|
|
const unsigned int Samples();
|
|
|
|
protected:
|
|
CADPCMDecoder *m_pDecoder; // one decoder per file
|
|
int m_nPos; // current position in samples
|
|
FILE *m_pFile; // own File handle for now
|
|
int m_iFilePos; // current file pos corresponding to right file seek pos (counted from m_uiDataStartPos)
|
|
bool m_bInitialized; // functionality not available if false
|
|
bool m_bCopyFromLastFrame; // indicates some copying from last frame (due to odd sample count request)
|
|
signed long m_lLastSample; // sample to reuse for next frame
|
|
|
|
unsigned int m_uiCurrentBlockSize; // block size in file, always less than static allocated buffer
|
|
unsigned int m_uiCurrentSamplesPerBlock;// sampels per block in file(usually m_uiCurrentBlockSize-12), always less than static allocated buffer
|
|
|
|
//ADPCM specific stuff
|
|
unsigned char m_aEncodedBlock[scuiBlockSize]; //static allocated encoded block
|
|
short m_aDecodedBlock[scuiSamplesPerBlock*2]; //static allocated decoded block, 2 per channel (1:4)
|
|
short m_aCoefs[scuiNumberOfCoefs * 2/*2 per channel, stereo assumed*/]; //static allocated coeficients
|
|
|
|
unsigned int m_uiDataStartPos; // usually at position 90, set by InitStreamWav
|
|
unsigned int m_uiNumSamples; // total sample count
|
|
unsigned short m_sCoefs; // ADPCM: number of coef sets
|
|
short* m_psSamplePtr; // Pointer to current sample
|
|
int m_iState[ 16 ]; // step-size info for *ADPCM writes
|
|
|
|
protected:
|
|
//! fills a dest buffer with uncompressed data
|
|
const bool FillPCMBuffer(signed long *pBuffer, int nSamples);
|
|
//! fills a dest buffer from 22KHz compressed data
|
|
const bool FillPCMBuffer22KHz(signed long *pBuffer, int nSamples);
|
|
|
|
const bool InitStreamWAV(); // for now has every instance its own file handle
|
|
unsigned short AdpcmReadBlock(short* pDest = NULL); // decoded one block, if dest not specified, default static buffer is chosen
|
|
|
|
virtual ~CADPCMDecoderInstance(); // to hit right destructor
|
|
};
|
|
|