#pragma once #include #include #include namespace ctrff { class CTRFF_API BCSTM { public: BCSTM() : pReader(pFile) {} ~BCSTM() { CleanUp(); } void LoadFile(const std::string& path); void CleanUp(); void ReadGotoBeginning(bool use_loop_beg = false); void ReadBlock(PD::u32 block, PD::u8* ref); PD::u32 LeseZeiger() { return pFile.tellg(); } /** Some useful Getters */ PD::u8 GetNumChannels() const { return pInfoBlock.StreamInfo.ChannelCount; } PD::u32 GetSampleRate() const { return pInfoBlock.StreamInfo.SampleRate; } PD::u32 GetBlockSize() const { return pInfoBlock.StreamInfo.SampleBlockSize; } PD::u32 GetNumBlocks() const { return pInfoBlock.StreamInfo.SampleBlockNum; } PD::u32 GetBlockSamples() const { return pInfoBlock.StreamInfo.SampleBlockSampleNum; } PD::u32 GetLastBlockSamples() const { return pInfoBlock.StreamInfo.LastSampleBlockSampleNum; } bool IsLooping() const { return pInfoBlock.StreamInfo.Loop; } PD::u32 GetLoopStart() const { return pInfoBlock.StreamInfo.LoopStartFrame / GetNumBlocks(); } PD::u32 GetLoopEnd() const { /** Get temp references for better readability */ const PD::u32& loop_end = pInfoBlock.StreamInfo.LoopEndFrame; const PD::u32& block_samples = GetNumBlocks(); return (loop_end % block_samples ? block_samples : loop_end / block_samples); } /** Internal Data (can be made private with private: but public by default) */ enum Endianness : PD::u16 { Big = 0xfffe, ///< Big Endian Little = 0xfeff, ///< Little Endian }; enum ReferenceTypes : PD::u16 { Ref_ByteTable = 0x0100, Ref_ReferenceTable = 0x0101, Ref_DSP_ADPCM_Info = 0x0300, Ref_IMA_ADPCM_Info = 0x0301, Ref_SampleData = 0x1f00, Ref_InfoBlock = 0x4000, Ref_SeekBlock = 0x4001, Ref_DataBlock = 0x4002, Ref_StreamInfo = 0x4100, Ref_TrackInfo = 0x4101, Ref_ChannelInfo = 0x4102, }; enum Encoding : PD::u8 { PCM8 = 0, PCM16 = 1, /** Only supported encoding in BCSTM-Player */ DSP_ADPCM = 2, IMA_ADPCM = 3, }; struct Reference { PD::u16 TypeID; PD::u16 Padding; PD::u32 Offset; /** null -> uint32_max */ }; struct ReferenceTable { PD::u32 Count; PD::Vec Refs; }; struct SizedReference { Reference Ref; PD::u32 Size; }; struct StreamInfo { PD::u8 Encoding; PD::u8 Loop; PD::u8 ChannelCount; PD::u8 Padding; PD::u32 SampleRate; PD::u32 LoopStartFrame; PD::u32 LoopEndFrame; PD::u32 SampleBlockNum; PD::u32 SampleBlockSize; PD::u32 SampleBlockSampleNum; PD::u32 LastSampleBlockSize; PD::u32 LastSampleBlockSampleNum; PD::u32 LastSampleBlockPaddedSize; PD::u32 SeekDataSize; PD::u32 SeekIntervalSampleNum; Reference SampleDataRef; }; struct BlockHeader { PD::u32 Magic; PD::u32 Size; }; struct InfoBlock { BlockHeader Header; Reference StreamInfoRef; Reference TrackInfoTabRef; Reference ChannelInfoTabRef; BCSTM::StreamInfo StreamInfo; ReferenceTable TrackInfoTab; ReferenceTable ChannelInfoTab; PD::Vec ChannelInfoRefs; /** The refs of the refs ?? */ }; /** SeekDataBlock cause they are the same struct */ struct SD_Block { BlockHeader Header; PD::Vec Data; }; struct DSP_ADPCM_Param { PD::u16 Coefficients[0x10]; }; struct DSP_ADPCM_Context { PD::u8 PredictorScale; PD::u8 Reserved; PD::u16 PreviousSample; PD::u16 SecondPreviousSample; }; struct DSP_ADPCM_Info { DSP_ADPCM_Param Param; DSP_ADPCM_Context Context; DSP_ADPCM_Context LoopContext; PD::u16 Padding; }; struct ByteTable { PD::u32 Size; PD::Vec Table; }; struct TrackInfo { PD::u8 Volume; PD::u8 Pan; PD::u16 Padding; Reference ChennelIndexTabRef; ByteTable ChannelIndexTab; }; struct Header { PD::u32 Magic; /** CSTM */ PD::u16 Endianness = Little; /** Default */ PD::u16 HeaderSize; /** Header Size probably */ PD::u32 Version; /** Format Version? */ PD::u32 FileSize; /** File Size */ PD::u16 NumBlocks; /** Number of blocks */ PD::u16 Reserved; /** Reserved */ }; Header pHeader; SizedReference pInfoBlockRef; SizedReference pSeekBlockRef; SizedReference pDataBlockRef; InfoBlock pInfoBlock; SD_Block pSeekBlock; SD_Block pDataBlock; PD::Vec pDSP_ADPCM_Info; /** File Stream */ std::fstream pFile; /** Endianness based reader */ BinUtil pReader; void ReadReference(Reference& ref); void ReadSizedReference(SizedReference& ref); void ReadInfoBlock(InfoBlock& block); void ReadSeekBlock(SD_Block& block); void ReadReferenceTab(ReferenceTable& tab); static std::string Endianness2String(const Endianness& e) { switch (e) { case Little: return "Little"; case Big: return "Big"; default: return "Unknown"; } } static std::string ReferenceType2String(const ReferenceTypes& e) { switch (e) { case Ref_ByteTable: return "ByteTable"; case Ref_ReferenceTable: return "ReferenceTable"; case Ref_DSP_ADPCM_Info: return "DSP_ADPCM_Info"; case Ref_IMA_ADPCM_Info: return "IMA_ADPCM_Info"; case Ref_SampleData: return "SampleData"; case Ref_InfoBlock: return "InfoBlock"; case Ref_SeekBlock: return "SeekBlock"; case Ref_DataBlock: return "DataBlock"; case Ref_StreamInfo: return "StreamInfo"; case Ref_TrackInfo: return "TrackInfo"; case Ref_ChannelInfo: return "ChannelInfo"; default: return "Unknown"; } } static std::string Encoding2String(const Encoding& e) { switch (e) { case PCM8: return "PCM8"; case PCM16: return "PCM16"; case DSP_ADPCM: return "DSP ADPCM"; case IMA_ADPCM: return "IMA ADPCM"; default: return "Unknown"; } } }; } // namespace ctrff