#pragma once #include #include #include #include #include #include "lib/binarytools/BinaryWriter.h" #include #include #define NONE 0xFFFF #define ALIGN(val, al) (size_t) ((val + (al - 1)) & -al) struct Entry { uint32_t offset; uint32_t length; }; struct AudioBankSound { uint32_t offset; float tuning; bool operator==(const AudioBankSound& other) const { return offset == other.offset && tuning == other.tuning; } }; struct Instrument { bool valid; std::string name; uint32_t offset; uint8_t releaseRate; uint8_t normalRangeLo; uint8_t normalRangeHi; uint32_t envelope; std::optional soundLo; std::optional soundMed; std::optional soundHi; }; struct AdpcmBook { int32_t order{}; int32_t npredictors{}; std::vector table; bool operator==(const AdpcmBook& other) const { return order == other.order && npredictors == other.npredictors && table == other.table; } }; struct Drum { std::string name; uint32_t offset; uint8_t releaseRate; uint8_t pan; uint32_t envelope; AudioBankSound sound; bool operator==(const Drum& other) const { return name == other.name && offset == other.offset && releaseRate == other.releaseRate && pan == other.pan && envelope == other.envelope && sound == other.sound; } }; struct AdpcmLoop { uint32_t start{}; uint32_t end{}; int32_t count{}; uint32_t pad{}; std::optional> state; bool operator==(const AdpcmLoop& other) const { return start == other.start && end == other.end && count == other.count && pad == other.pad && state == other.state; } }; struct AudioBankSample { std::string name; std::vector data; AdpcmBook book; AdpcmLoop loop; std::vector tunings; }; struct SampleBank { std::string name; uint32_t offset; std::vector data; std::map entries; AudioBankSample* AddSample(uint32_t addr, size_t sampleSize, const AdpcmBook& book, const AdpcmLoop& loop); }; struct TBLFile { std::vector banks; std::vector tbls; std::map map; }; struct CTLHeader { uint32_t instruments; uint32_t numDrums; uint32_t shared; }; struct AdsrEnvelope { int16_t delay; int16_t arg; }; struct Envelope { std::string name; std::vector entries; }; struct Bank { std::string name; SampleBank* sampleBank; std::vector insts; std::vector drums; std::vector>> allInsts; std::vector instOffsets; std::map envelopes; std::map samples; void print() const; }; class AudioManager { public: static AudioManager* Instance; void initialize(std::vector& buffer, YAML::Node& data); // Optional AUDIO_HEADER yaml settings: `dialect` (US/EU opcode set) and // `frequency` (session rate the bank tunings are relative to). const std::string& GetDialect() const { return dialect; } uint32_t GetSessionFrequency() const { return sessionFrequency; } std::string dialect; uint32_t sessionFrequency = 0; void bind_sample(YAML::Node& node, const std::string& path); std::string& get_sample(uint32_t id); AudioBankSample get_aifc(int32_t index); std::map get_banks(); std::vector get_loaded_banks(); std::vector get_samples(); uint32_t get_index(AudioBankSample* bank); private: std::map banks; std::map sampleMap; TBLFile loaded_tbl; static std::vector parse_seq_file(std::vector& buffer, uint32_t offset, bool isCTL); static CTLHeader parse_ctl_header(std::vector& data); static std::optional parse_sound(std::vector data); static Drum parse_drum(std::vector& data, uint32_t addr); static Instrument parse_inst(std::vector& data, uint32_t addr); static AdpcmLoop parse_loop(uint32_t addr, std::vector& bankData); static AdpcmBook parse_book(uint32_t addr, std::vector& bankData); static AudioBankSample* parse_sample(std::vector& data, std::vector& bankData, SampleBank* sampleBank); static std::vector parse_envelope(uint32_t addr, std::vector& dataBank); static Bank parse_ctl(CTLHeader header, std::vector data, SampleBank* bank, uint32_t index); static TBLFile parse_tbl(std::vector& data, std::vector& entries); };