From 113472302904ac84d4ddf70df32ca245ad156bf2 Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Fri, 1 Sep 2023 00:51:51 -0600 Subject: Migrated disassemble audio into audio manager class --- src/audio/AudioManager.cpp | 442 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 442 insertions(+) create mode 100644 src/audio/AudioManager.cpp (limited to 'src/audio/AudioManager.cpp') diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp new file mode 100644 index 0000000..1f3e382 --- /dev/null +++ b/src/audio/AudioManager.cpp @@ -0,0 +1,442 @@ +#include "AudioManager.h" + +#include +#include +#include +#include +#include +#include "hj/pyutils.h" +#include "binarytools/BinaryReader.h" +#include "hj/zip.h" +#include + +std::unordered_map name_table; +AudioManager* AudioManager::Instance; + +std::string gen_name(const std::string& prefix){ + if(!name_table.contains(prefix)){ + name_table[prefix] = 0; + } + name_table[prefix] += 1; + return prefix + "-" + std::to_string(name_table[prefix]); +} + +AifcEntry SampleBank::AddSample(uint32_t addr, size_t sampleSize, const Book& book, const Loop& loop){ + assert(sampleSize % 2 == 0); + if(sampleSize % 9 != 0){ + assert(sampleSize % 9 == 1); + sampleSize -= 1; + } + + AifcEntry entry; + + if(this->entries.contains(addr)){ + entry = this->entries[addr]; + assert(entry.book == book); + assert(entry.loop == loop); + assert(entry.data.size() == sampleSize); + } else { + entry = { gen_name("aifc"), PyUtils::slice(this->data, addr, addr + sampleSize), book, loop }; + this->entries[addr] = entry; + } + + return entry; +} + +void Bank::print() const { + std::cout << "Bank: " << name << std::endl; + std::cout << "Instruments: " << std::to_string(insts.size()) << std::endl; + std::cout << "Drums: " << std::to_string(drums.size()) << std::endl; + std::cout << "Samples: " << std::to_string(samples.size()) << std::endl; + std::cout << "Envelopes: " << std::to_string(envelopes.size()) << std::endl; + std::cout << "All Instruments: " << std::to_string(allInsts.size()) << std::endl; + std::cout << "Inst Offsets: " << std::to_string(instOffsets.size()) << std::endl; + std::cout << "Sample Bank: " << sampleBank.name << std::endl; + std::cout << "Sample Bank Offset: " << std::to_string(sampleBank.offset) << std::endl; +} + +std::vector AudioManager::parse_seq_file(std::vector& buffer, uint32_t offset, bool isCTL){ + std::vector entries; + LUS::BinaryReader reader((char*) buffer.data(), buffer.size()); + reader.SetEndianness(LUS::Endianness::Big); + reader.Seek(offset, LUS::SeekOffsetType::Start); + + unsigned short magic = reader.ReadUInt16(); + unsigned short num_entries = reader.ReadUInt16(); + uint32_t prev = ALIGN(4 + num_entries * 8, 16); + + assert(magic == (isCTL ? 1 : 2)); + + for (int i = 0; i < num_entries; ++i) { + reader.Seek((offset + 4) + (i * 8), LUS::SeekOffsetType::Start); + uint32_t addr = reader.ReadUInt32(); + uint32_t length = reader.ReadUInt32(); + + if(isCTL){ + assert(addr == prev); + } else { + assert(addr <= prev); + } + + prev = std::max(prev, addr + length); + entries.push_back({addr, length}); + } + + reader.Close(); + return entries; +} + +CTLHeader AudioManager::parse_ctl_header(std::vector& data){ + LUS::BinaryReader reader((char*) data.data(), data.size()); + reader.SetEndianness(LUS::Endianness::Big); + + CTLHeader header = { reader.ReadUInt32(), reader.ReadUInt32(), reader.ReadUInt32() }; + + reader.Close(); + return header; +} + +std::optional AudioManager::parse_sound(std::vector data) { + LUS::BinaryReader reader((char*) data.data(), data.size()); + reader.SetEndianness(LUS::Endianness::Big); + + uint32_t addr = reader.ReadUInt32(); + float tuning = reader.ReadFloat(); + + if(addr == 0){ + assert(tuning == 0.0f); + return std::nullopt; + } + + Sound sound = { addr, tuning }; + + reader.Close(); + return sound; +} + +Drum AudioManager::parse_drum(std::vector& data, uint32_t addr) { + LUS::BinaryReader reader((char*) data.data(), data.size()); + reader.SetEndianness(LUS::Endianness::Big); + std::string name = gen_name("drum"); + + uint8_t releaseRate = reader.ReadInt8(); + uint8_t pan = reader.ReadInt8(); + + reader.Seek(12, LUS::SeekOffsetType::Start); + Sound sound = parse_sound(PyUtils::slice(data, 4, 12)).value(); + uint32_t envOffset = reader.ReadInt32(); + assert(envOffset != 0); + + Drum drum = { name, addr, releaseRate, pan, envOffset, sound }; + + return drum; +} + +Inst AudioManager::parse_inst(std::vector& data, uint32_t addr) { + std::string name = gen_name("inst"); + uint8_t normalRangeLo = data[1]; + uint8_t normalRangeHi = data[2]; + uint8_t releaseRate = data[3]; + + uint32_t envAddr; + memcpy(&envAddr, (char*) data.data() + 4, 4); + envAddr = BSWAP32(envAddr); + + assert(envAddr != 0); + + auto soundLo = parse_sound(PyUtils::slice(data, 8, 16)); + auto soundMed = parse_sound(PyUtils::slice(data, 16, 24)); + auto soundHi = parse_sound(PyUtils::slice(data, 24)); + + if (soundLo == std::nullopt) { + assert(normalRangeLo == 0); + } + if (soundHi == std::nullopt) { + assert(normalRangeHi == 127); + } + + Inst inst = { name, addr, releaseRate, normalRangeLo, normalRangeHi, envAddr, soundLo, soundMed, soundHi }; + return inst; +} + +Loop AudioManager::parse_loop(uint32_t addr, std::vector& bankData){ + LUS::BinaryReader reader((char*) bankData.data(), bankData.size()); + reader.SetEndianness(LUS::Endianness::Big); + reader.Seek(addr, LUS::SeekOffsetType::Start); + + std::optional> state = std::nullopt; + uint32_t start = reader.ReadUInt32(); + uint32_t end = reader.ReadUInt32(); + int32_t count = reader.ReadInt32(); + uint32_t pad = reader.ReadUInt32(); + if(count != 0){ + state = std::vector(); + for (size_t i = 0; i < 16; ++i) { + state.value().push_back(reader.ReadShort()); + } + } + Loop loop = { start, end, count, pad, state }; + return loop; +} + +Book AudioManager::parse_book(uint32_t addr, std::vector& bankData){ + LUS::BinaryReader reader((char*) bankData.data(), bankData.size()); + reader.SetEndianness(LUS::Endianness::Big); + reader.Seek(addr, LUS::SeekOffsetType::Start); + + uint32_t order = reader.ReadInt32(); + uint32_t npredictors = reader.ReadInt32(); + std::vector table; + std::vector tableData = PyUtils::slice(bankData, addr + 8, addr + 8 + 16 * order * npredictors); + for (size_t i = 0; i < ( 16 * order * npredictors ); i += 2) { + short dtable; + memcpy(&dtable, tableData.data() + i, 2); + table.push_back(BSWAP16(dtable)); + } + + Book book = { order, npredictors, table }; + return book; +} + +AifcEntry AudioManager::parse_sample(std::vector& data, std::vector& bankData, SampleBank& sampleBank){ + LUS::BinaryReader reader((char*) data.data(), data.size()); + reader.SetEndianness(LUS::Endianness::Big); + + uint32_t zero = reader.ReadUInt32(); + uint32_t addr = reader.ReadUInt32(); + uint32_t loop = reader.ReadUInt32(); + uint32_t book = reader.ReadUInt32(); + uint32_t sampleSize = reader.ReadUInt32(); + assert(zero == 0); + assert(loop != 0); + assert(book != 0); + + Loop loopData = parse_loop(loop, bankData); + Book bookData = parse_book(book, bankData); + + reader.Close(); + return sampleBank.AddSample(addr, sampleSize, bookData, loopData); +} + + +std::vector AudioManager::parse_envelope(uint32_t addr, std::vector& dataBank){ + std::vector entries; + LUS::BinaryReader reader((char*) dataBank.data(), dataBank.size()); + reader.SetEndianness(LUS::Endianness::Big); + + while(true){ + reader.Seek(addr, LUS::SeekOffsetType::Start); + unsigned short delay = reader.ReadUShort(); + unsigned short arg = reader.ReadUShort(); + entries.emplace_back(delay, arg); + addr += 4; + if (1 <= (-delay) % ((uint32_t) pow(2, 16)) <= 3.0){ + break; + } + } + + reader.Close(); + return entries; +} + +Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, SampleBank bank, uint32_t index) { + name_table.clear(); + std::ostringstream ss; + ss << std::hex << std::setw(2) << std::setfill('0') << index; + std::string name = ss.str(); + uint32_t numInstruments = header.instruments; + uint32_t numDrums = header.numDrums; + char* rawData = (char*) data.data(); + + uint32_t drumBaseAddr; + memcpy(&drumBaseAddr, rawData, 4); + drumBaseAddr = BSWAP32(drumBaseAddr); + + std::vector drumOffsets; + + if(numDrums != 0){ + for (size_t i = 0; i < numDrums; ++i) { + uint32_t drumOffset; + memcpy(&drumOffset, rawData + drumBaseAddr + (i * 4), 4); + drumOffsets.push_back(BSWAP32(drumOffset)); + } + } + + uint32_t instrumentBaseAddr = 4; + std::vector instrumentOffsets; + std::vector instrumentList; + + for (size_t i = 0; i < numInstruments; ++i) { + uint32_t instOffset; + memcpy(&instOffset, rawData + (instrumentBaseAddr + (i * 4)), 4); + instOffset = BSWAP32(instOffset); + if(instOffset == 0){ + instrumentList.push_back(NONE); + } else { + instrumentOffsets.push_back(instOffset); + instrumentList.push_back(instOffset); + } + } + + std::sort(instrumentOffsets.begin(), instrumentOffsets.end()); + + std::vector insts; + for(auto &offset : instrumentOffsets){ + auto rInst = PyUtils::slice(data, offset, offset + 32); + Inst inst = parse_inst(rInst, offset); + insts.push_back(inst); + } + + std::vector drums; + for(auto &offset : drumOffsets){ + auto rDrum = PyUtils::slice(data, offset, offset + 16); + Drum drum = parse_drum(rDrum, offset); + drums.push_back(drum); + } + + auto envOffsets = std::vector(); + auto sampleOffsets = std::vector(); + auto tunings = std::unordered_map(); + + for(auto &inst : insts){ + for(auto &sound : {inst.soundLo, inst.soundMed, inst.soundHi}){ + if(sound.has_value()){ + sampleOffsets.push_back(sound.value().offset); + tunings[sound.value().offset] = sound.value().tuning; + } + } + envOffsets.push_back(inst.envelope); + } + for(auto &drum : drums){ + sampleOffsets.push_back(drum.sound.offset); + tunings[drum.sound.offset] = drum.sound.tuning; + envOffsets.push_back(drum.envelope); + } + // Put drums somewhere in the middle of the instruments to make sample + // addresses come in increasing order. (This logic isn't totally right, + // but it works for our purposes.) + std::vector>> allInsts; + bool needDrums = !drums.empty(); + for(auto &inst : insts){ + std::vector> sounds = {inst.soundLo, inst.soundMed, inst.soundHi}; + + if(needDrums && std::any_of(sounds.cbegin(), sounds.cend(), [&drums](std::optional sound){ return sound.has_value() && sound.value().offset > drums[0].sound.offset; })){ + allInsts.emplace_back(drums); + needDrums = false; + } + + allInsts.emplace_back(inst); + } + + + if(needDrums){ + allInsts.emplace_back(drums); + } + + std::unordered_map samples; + std::sort(sampleOffsets.begin(), sampleOffsets.end()); + for(auto &offset : sampleOffsets){ + auto rSample = PyUtils::slice(data, offset, offset + 20); + AifcEntry sample = parse_sample(rSample, data, bank); + for(auto &tuning : tunings){ + sample.tunings.push_back(tuning.second); + } + samples[offset] = sample; + } + + std::unordered_map> envData; + std::vector usedEnvOffsets; + std::sort(envOffsets.begin(), envOffsets.end()); + for(auto &offset : envOffsets){ + auto env = parse_envelope(offset, data); + envData[offset] = env; + for(int i = 0; i < ALIGN(env.size(), 4); i++){ + usedEnvOffsets.push_back(offset + (i * 4)); + } + } + + std::vector unusedEnvOffsets; + if(!usedEnvOffsets.empty()){ + size_t min = std::min_element(usedEnvOffsets.begin(), usedEnvOffsets.end()) - usedEnvOffsets.begin(); + size_t max = std::max_element(usedEnvOffsets.begin(), usedEnvOffsets.end()) - usedEnvOffsets.begin(); + for(size_t idx = min + 4; idx < max; idx += 4){ + uint32_t addr = usedEnvOffsets[idx]; + if(std::find(usedEnvOffsets.begin(), usedEnvOffsets.end(), addr) == usedEnvOffsets.end()){ + unusedEnvOffsets.push_back(addr); + uint32_t stubMarker; + memcpy(&stubMarker, rawData + addr, 4); + stubMarker = BSWAP32(stubMarker); + assert(stubMarker == 0); + auto env = parse_envelope(addr, data); + envData[addr] = env; + for(int i = 0; i < ALIGN(env.size(), 4); i++){ + usedEnvOffsets.push_back(addr + (i * 4)); + } + } + } + } + + std::unordered_map envelopes; + for(auto &entry : envData){ + Envelope env = { gen_name("envelope"), entry.second }; + envelopes[entry.first] = env; + } + + Bank bankData = { name, bank, insts, drums, allInsts, instrumentList, envelopes, samples }; + return bankData; +} + +TBLFile AudioManager::parse_tbl(std::vector& data, std::vector& entries) { + TBLFile tbl; + std::unordered_map cache; + for(auto &entry : entries){ + if(!cache.contains(entry.offset)){ + std::string name = gen_name("sample_bank"); + SampleBank sampleBank = { + name, entry.offset, PyUtils::slice(data, entry.offset, entry.offset + entry.length) + }; + tbl.banks.push_back(sampleBank); + tbl.map[name] = tbl.banks.size() - 1; + cache[entry.offset] = name; + } + tbl.tbls.push_back(cache[entry.offset]); + } + cache.clear(); + return tbl; +} + +void AudioManager::initialize(std::vector& buffer) { + auto assets = nlohmann::json::parse(std::ifstream( "assets.json" )); + auto sound_data = assets["@sound_data"]["us"]; + auto sound_tbl = sound_data["sound_tbl"]; + auto sound_ctl = sound_data["sound_ctl"]; + + std::vector tbl = parse_seq_file(buffer, sound_tbl[0], false); + std::vector ctl = parse_seq_file(buffer, sound_ctl[0], true); + + std::cout << "Table entries: " << tbl.size() << std::endl; + std::cout << "Control entries: " << ctl.size() << std::endl; + + std::vector tbl_data = PyUtils::slice(buffer, sound_tbl[0], (size_t) sound_tbl[0] + (size_t) sound_tbl[1]); + std::vector ctl_data = PyUtils::slice(buffer, sound_ctl[0], (size_t) sound_ctl[0] + (size_t) sound_ctl[1]); + TBLFile tbl_file = parse_tbl(tbl_data, tbl); + + std::cout << "TBLs: " << tbl_file.tbls.size() << std::endl; + std::cout << "Banks: " << tbl_file.banks.size() << std::endl; + std::cout << "Map: " << tbl_file.map.size() << std::endl; + + auto zipped = zip(PyUtils::range(0, ctl.size()), ctl, tbl_file.tbls); + + std::cout << "================================" << std::endl; + for (const auto& item : zipped) { + auto [index, ctrl, sample_bank_name] = item; + auto sample_bank = tbl_file.map[sample_bank_name]; + auto entry = PyUtils::slice(ctl_data, ctrl.offset, ctrl.offset + ctrl.length); + auto headerRaw = PyUtils::slice(entry, 0, 16); + auto header = parse_ctl_header(headerRaw); + auto bank = parse_ctl(header, PyUtils::slice(entry, 16), tbl_file.banks[sample_bank], index); + banks.push_back(bank); + bank.print(); + std::cout << "================================" << std::endl; + } +} -- cgit v1.2.3 From 063224c69d564d6e10dd4febf25caa9f59fccfda Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Sun, 3 Sep 2023 20:11:35 -0600 Subject: Fixed AIFC Extraction --- src/audio/AudioManager.cpp | 231 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 202 insertions(+), 29 deletions(-) (limited to 'src/audio/AudioManager.cpp') diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index 1f3e382..f241a9b 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -8,35 +8,43 @@ #include "hj/pyutils.h" #include "binarytools/BinaryReader.h" #include "hj/zip.h" +#include "AIFCWriter.h" #include std::unordered_map name_table; AudioManager* AudioManager::Instance; +std::vector PyUtils::range(uint32_t start, uint32_t end) { + std::vector result; + for (uint32_t i = start; i < end; ++i) { + result.push_back(i); + } + return result; +} + std::string gen_name(const std::string& prefix){ if(!name_table.contains(prefix)){ name_table[prefix] = 0; } - name_table[prefix] += 1; - return prefix + "-" + std::to_string(name_table[prefix]); + return prefix + std::to_string(name_table[prefix]++); } -AifcEntry SampleBank::AddSample(uint32_t addr, size_t sampleSize, const Book& book, const Loop& loop){ +AifcEntry* SampleBank::AddSample(uint32_t addr, size_t sampleSize, const Book& book, const Loop& loop){ assert(sampleSize % 2 == 0); if(sampleSize % 9 != 0){ assert(sampleSize % 9 == 1); sampleSize -= 1; } - AifcEntry entry; + AifcEntry* entry; if(this->entries.contains(addr)){ entry = this->entries[addr]; - assert(entry.book == book); - assert(entry.loop == loop); - assert(entry.data.size() == sampleSize); + assert(entry->book == book); + assert(entry->loop == loop); + assert(entry->data.size() == sampleSize); } else { - entry = { gen_name("aifc"), PyUtils::slice(this->data, addr, addr + sampleSize), book, loop }; + entry = new AifcEntry{ gen_name("aifc"), PyUtils::slice(this->data, addr, addr + sampleSize), book, loop }; this->entries[addr] = entry; } @@ -51,8 +59,8 @@ void Bank::print() const { std::cout << "Envelopes: " << std::to_string(envelopes.size()) << std::endl; std::cout << "All Instruments: " << std::to_string(allInsts.size()) << std::endl; std::cout << "Inst Offsets: " << std::to_string(instOffsets.size()) << std::endl; - std::cout << "Sample Bank: " << sampleBank.name << std::endl; - std::cout << "Sample Bank Offset: " << std::to_string(sampleBank.offset) << std::endl; + std::cout << "Sample Bank: " << sampleBank->name << std::endl; + std::cout << "Sample Bank Offset: " << std::to_string(sampleBank->offset) << std::endl; } std::vector AudioManager::parse_seq_file(std::vector& buffer, uint32_t offset, bool isCTL){ @@ -198,7 +206,7 @@ Book AudioManager::parse_book(uint32_t addr, std::vector& bankData){ return book; } -AifcEntry AudioManager::parse_sample(std::vector& data, std::vector& bankData, SampleBank& sampleBank){ +AifcEntry* AudioManager::parse_sample(std::vector& data, std::vector& bankData, SampleBank* sampleBank){ LUS::BinaryReader reader((char*) data.data(), data.size()); reader.SetEndianness(LUS::Endianness::Big); @@ -215,7 +223,7 @@ AifcEntry AudioManager::parse_sample(std::vector& data, std::vectorAddSample(addr, sampleSize, bookData, loopData); } @@ -239,7 +247,7 @@ std::vector AudioManager::parse_envelope(uint32_t addr, std::vecto return entries; } -Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, SampleBank bank, uint32_t index) { +Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, SampleBank* bank, uint32_t index) { name_table.clear(); std::ostringstream ss; ss << std::hex << std::setw(2) << std::setfill('0') << index; @@ -333,13 +341,13 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, Sample allInsts.emplace_back(drums); } - std::unordered_map samples; + std::unordered_map samples; std::sort(sampleOffsets.begin(), sampleOffsets.end()); for(auto &offset : sampleOffsets){ auto rSample = PyUtils::slice(data, offset, offset + 20); - AifcEntry sample = parse_sample(rSample, data, bank); + AifcEntry* sample = parse_sample(rSample, data, bank); for(auto &tuning : tunings){ - sample.tunings.push_back(tuning.second); + sample->tunings.push_back(tuning.second); } samples[offset] = sample; } @@ -392,11 +400,11 @@ TBLFile AudioManager::parse_tbl(std::vector& data, std::vector& for(auto &entry : entries){ if(!cache.contains(entry.offset)){ std::string name = gen_name("sample_bank"); - SampleBank sampleBank = { - name, entry.offset, PyUtils::slice(data, entry.offset, entry.offset + entry.length) + auto* sampleBank = new SampleBank{ + name, entry.offset, PyUtils::slice(data, entry.offset, entry.offset + entry.length) }; tbl.banks.push_back(sampleBank); - tbl.map[name] = tbl.banks.size() - 1; + tbl.map[name] = sampleBank; cache[entry.offset] = name; } tbl.tbls.push_back(cache[entry.offset]); @@ -419,24 +427,189 @@ void AudioManager::initialize(std::vector& buffer) { std::vector tbl_data = PyUtils::slice(buffer, sound_tbl[0], (size_t) sound_tbl[0] + (size_t) sound_tbl[1]); std::vector ctl_data = PyUtils::slice(buffer, sound_ctl[0], (size_t) sound_ctl[0] + (size_t) sound_ctl[1]); - TBLFile tbl_file = parse_tbl(tbl_data, tbl); + this->loaded_tbl = parse_tbl(tbl_data, tbl); - std::cout << "TBLs: " << tbl_file.tbls.size() << std::endl; - std::cout << "Banks: " << tbl_file.banks.size() << std::endl; - std::cout << "Map: " << tbl_file.map.size() << std::endl; + std::cout << "TBLs: " << this->loaded_tbl.tbls.size() << std::endl; + std::cout << "Banks: " << this->loaded_tbl.banks.size() << std::endl; + std::cout << "Map: " << this->loaded_tbl.map.size() << std::endl; - auto zipped = zip(PyUtils::range(0, ctl.size()), ctl, tbl_file.tbls); + auto zipped = zip(PyUtils::range(0, ctl.size()), ctl, this->loaded_tbl.tbls); - std::cout << "================================" << std::endl; +// std::cout << "================================" << std::endl; for (const auto& item : zipped) { auto [index, ctrl, sample_bank_name] = item; - auto sample_bank = tbl_file.map[sample_bank_name]; + auto sample_bank = this->loaded_tbl.map[sample_bank_name]; auto entry = PyUtils::slice(ctl_data, ctrl.offset, ctrl.offset + ctrl.length); auto headerRaw = PyUtils::slice(entry, 0, 16); auto header = parse_ctl_header(headerRaw); - auto bank = parse_ctl(header, PyUtils::slice(entry, 16), tbl_file.banks[sample_bank], index); + auto bank = parse_ctl(header, PyUtils::slice(entry, 16), sample_bank, index); banks.push_back(bank); - bank.print(); - std::cout << "================================" << std::endl; +// bank.print(); +// std::cout << "================================" << std::endl; + } + + +} + +void serialize_f80(double num, LUS::BinaryWriter &writer) { + // Convert the input double to a uint64_t + std::uint64_t f64; + std::memcpy(&f64, &num, sizeof(double)); + + std::uint64_t f64_sign_bit = f64 & (std::uint64_t) pow(2, 63); + if (num == 0.0) { + if (f64_sign_bit) { + writer.Write(0x80000000); + } else { + writer.Write(0x00000000); + } + } + + std::uint64_t exponent = ((f64 ^ f64_sign_bit) >> 52); + + assert(exponent != 0); + assert(exponent != 0x7FF); + + exponent -= 1023; + uint64_t f64_mantissa_bits = f64 & (uint64_t) pow(2, 52) - 1; + uint64_t f80_sign_bit = f64_sign_bit << (80 - 64); + uint64_t f80_exponent = (exponent + 0x3FFF) << 64; + uint64_t f80_mantissa_bits = (uint64_t) pow(2, 63) | (f64_mantissa_bits << (63 - 52)); + uint64_t f80 = f80_sign_bit | f80_exponent | f80_mantissa_bits; + + // Split the f80 representation into two parts (high and low) + uint16_t high = BSWAP16((uint16_t) f80 >> 64); + writer.Write((char*) &high, 2); + uint64_t low = BSWAP64(f80 & ((uint64_t) pow(2, 64) - 1)); + writer.Write((char*) &low, 8); +} + +#define START_SECTION(section) \ + { \ + out.Write(BSWAP32(section)); \ + LUS::BinaryWriter tmp = LUS::BinaryWriter(); \ + tmp.SetEndianness(LUS::Endianness::Big); \ + +#define START_CUSTOM_SECTION(section) \ + { \ + LUS::BinaryWriter tmp = LUS::BinaryWriter(); \ + tmp.SetEndianness(LUS::Endianness::Big); \ + out.Write(BSWAP32(AIFC::MagicValues::AAPL)); \ + tmp.Write(AIFC::MagicValues::stoc); \ + tmp.Write(section, false); \ + +#define END_SECTION() \ + auto odata = tmp.ToVector(); \ + size_t size = odata.size(); \ + len += ALIGN(size, 2) + 8; \ + out.Write(BSWAP32((uint32_t) size)); \ + out.Write(odata.data(), odata.size()); \ + if(size % 2){ \ + out.WriteByte(0); \ + } \ + } \ + +void AudioManager::write_aifc(AifcEntry* entry, LUS::BinaryWriter &out) { + int16_t num_channels = 1; + auto data = entry->data; + size_t len = 0; + assert(data.size() % 9 == 0); + if(data.size() % 2 == 1){ + data.push_back('\0'); + } + uint32_t num_frames = data.size() * 16 / 9; + int16_t sample_size = 16; + + uint32_t sample_rate = -1; + if(entry->tunings.size() == 1){ + sample_rate = 32000 * entry->tunings[0]; + } else { + float tmin = PyUtils::min(entry->tunings); + float tmax = PyUtils::max(entry->tunings); + + if(tmin <= 0.5f <= tmax){ + sample_rate = 16000; + } else if(tmin <= 1.0f <= tmax){ + sample_rate = 32000; + } else if(tmin <= 1.5f <= tmax){ + sample_rate = 48000; + } else if(tmin <= 2.5f <= tmax){ + sample_rate = 80000; + } else { + sample_rate = 16000 * (tmin + tmax); + } + } + + out.Write(BSWAP32(AIFC::MagicValues::FORM)); + // This should be where the size is, but we need to write it later + out.Write((uint32_t) 0); + out.Write(BSWAP32(AIFC::MagicValues::AIFC)); + + START_SECTION(AIFC::MagicValues::COMM); + + tmp.Write((uint16_t) num_channels); + tmp.Write((uint32_t) num_frames); + + tmp.Write((uint16_t) sample_size); + serialize_f80(sample_rate, tmp); + tmp.Write(AIFC::MagicValues::VAPC); + tmp.Write("\u000BVADPCM ~4-1", false); + + END_SECTION(); + + START_SECTION(AIFC::MagicValues::INST) + tmp.Write(std::string(20, '\0'), false); + END_SECTION(); + + START_CUSTOM_SECTION("\u000BVADPCMCODES") + tmp.Write((uint16_t) 1); + tmp.Write((uint16_t) entry->book.order); + tmp.Write((uint16_t) entry->book.npredictors); + + for(auto x : entry->book.table){ + tmp.Write((int16_t) x); + } + END_SECTION(); + + START_SECTION(AIFC::MagicValues::SSND) + uint32_t zero = 0; + tmp.Write((char*) &zero, 4); + tmp.Write((char*) &zero, 4); + tmp.Write((char*) data.data(), data.size()); + END_SECTION(); + + if(entry->loop.count != 0){ + START_CUSTOM_SECTION("\u000BVADPCMLOOPS") + uint16_t one = BSWAP16(1); + tmp.Write((char*) &one, 2); + tmp.Write((char*) &one, 2); + tmp.Write((uint32_t) entry->loop.start); + tmp.Write((uint32_t) entry->loop.end); + tmp.Write((int32_t) entry->loop.count); + for(size_t i = 0; i < 16; i++){ + int16_t loop = BSWAP16(entry->loop.state.value()[i]); + tmp.Write((char*) &loop, 2); + } + END_SECTION(); + } + + len += 4; + out.Seek(4, LUS::SeekOffsetType::Start); + out.Write((uint32_t) BSWAP32(len)); + +} + +void AudioManager::create_aifc(int32_t index, LUS::BinaryWriter &out) { + int32_t idx = -1; + for(auto &sample_bank : this->loaded_tbl.banks){ + auto offsets = PyUtils::keys(sample_bank->entries); + std::sort(offsets.begin(), offsets.end()); + + for(auto &offset : offsets){ + if(++idx == index){ + write_aifc(sample_bank->entries[offset], out); + return; + } + } } } -- cgit v1.2.3 From 50b6c6f65bc0da4a2c07e24c75dcd19baba60083 Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Sun, 3 Sep 2023 23:29:11 -0600 Subject: Added full SM64 -> AIFF Decoding --- src/audio/AudioManager.cpp | 4 ---- 1 file changed, 4 deletions(-) (limited to 'src/audio/AudioManager.cpp') diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index f241a9b..4549658 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -8,7 +8,6 @@ #include "hj/pyutils.h" #include "binarytools/BinaryReader.h" #include "hj/zip.h" -#include "AIFCWriter.h" #include std::unordered_map name_table; @@ -435,7 +434,6 @@ void AudioManager::initialize(std::vector& buffer) { auto zipped = zip(PyUtils::range(0, ctl.size()), ctl, this->loaded_tbl.tbls); -// std::cout << "================================" << std::endl; for (const auto& item : zipped) { auto [index, ctrl, sample_bank_name] = item; auto sample_bank = this->loaded_tbl.map[sample_bank_name]; @@ -444,8 +442,6 @@ void AudioManager::initialize(std::vector& buffer) { auto header = parse_ctl_header(headerRaw); auto bank = parse_ctl(header, PyUtils::slice(entry, 16), sample_bank, index); banks.push_back(bank); -// bank.print(); -// std::cout << "================================" << std::endl; } -- cgit v1.2.3 From fc7bf4c6ec1a637bb9eb240220533af856dc5a66 Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Fri, 15 Sep 2023 20:46:06 -0600 Subject: Added full bank extraction --- src/audio/AudioManager.cpp | 387 ++++++++++++++++++++++++++------------------- 1 file changed, 220 insertions(+), 167 deletions(-) (limited to 'src/audio/AudioManager.cpp') diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index 4549658..d72bda6 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -28,14 +28,14 @@ std::string gen_name(const std::string& prefix){ return prefix + std::to_string(name_table[prefix]++); } -AifcEntry* SampleBank::AddSample(uint32_t addr, size_t sampleSize, const Book& book, const Loop& loop){ +AudioBankSample* SampleBank::AddSample(uint32_t addr, size_t sampleSize, const AdpcmBook& book, const AdpcmLoop& loop){ assert(sampleSize % 2 == 0); if(sampleSize % 9 != 0){ assert(sampleSize % 9 == 1); sampleSize -= 1; } - AifcEntry* entry; + AudioBankSample* entry; if(this->entries.contains(addr)){ entry = this->entries[addr]; @@ -43,7 +43,7 @@ AifcEntry* SampleBank::AddSample(uint32_t addr, size_t sampleSize, const Book& b assert(entry->loop == loop); assert(entry->data.size() == sampleSize); } else { - entry = new AifcEntry{ gen_name("aifc"), PyUtils::slice(this->data, addr, addr + sampleSize), book, loop }; + entry = new AudioBankSample{ gen_name("aifc"), PyUtils::slice(this->data, addr, addr + sampleSize), book, loop }; this->entries[addr] = entry; } @@ -68,8 +68,8 @@ std::vector AudioManager::parse_seq_file(std::vector& buffer, ui reader.SetEndianness(LUS::Endianness::Big); reader.Seek(offset, LUS::SeekOffsetType::Start); - unsigned short magic = reader.ReadUInt16(); - unsigned short num_entries = reader.ReadUInt16(); + uint16_t magic = reader.ReadUInt16(); + uint16_t num_entries = reader.ReadUInt16(); uint32_t prev = ALIGN(4 + num_entries * 8, 16); assert(magic == (isCTL ? 1 : 2)); @@ -103,149 +103,6 @@ CTLHeader AudioManager::parse_ctl_header(std::vector& data){ return header; } -std::optional AudioManager::parse_sound(std::vector data) { - LUS::BinaryReader reader((char*) data.data(), data.size()); - reader.SetEndianness(LUS::Endianness::Big); - - uint32_t addr = reader.ReadUInt32(); - float tuning = reader.ReadFloat(); - - if(addr == 0){ - assert(tuning == 0.0f); - return std::nullopt; - } - - Sound sound = { addr, tuning }; - - reader.Close(); - return sound; -} - -Drum AudioManager::parse_drum(std::vector& data, uint32_t addr) { - LUS::BinaryReader reader((char*) data.data(), data.size()); - reader.SetEndianness(LUS::Endianness::Big); - std::string name = gen_name("drum"); - - uint8_t releaseRate = reader.ReadInt8(); - uint8_t pan = reader.ReadInt8(); - - reader.Seek(12, LUS::SeekOffsetType::Start); - Sound sound = parse_sound(PyUtils::slice(data, 4, 12)).value(); - uint32_t envOffset = reader.ReadInt32(); - assert(envOffset != 0); - - Drum drum = { name, addr, releaseRate, pan, envOffset, sound }; - - return drum; -} - -Inst AudioManager::parse_inst(std::vector& data, uint32_t addr) { - std::string name = gen_name("inst"); - uint8_t normalRangeLo = data[1]; - uint8_t normalRangeHi = data[2]; - uint8_t releaseRate = data[3]; - - uint32_t envAddr; - memcpy(&envAddr, (char*) data.data() + 4, 4); - envAddr = BSWAP32(envAddr); - - assert(envAddr != 0); - - auto soundLo = parse_sound(PyUtils::slice(data, 8, 16)); - auto soundMed = parse_sound(PyUtils::slice(data, 16, 24)); - auto soundHi = parse_sound(PyUtils::slice(data, 24)); - - if (soundLo == std::nullopt) { - assert(normalRangeLo == 0); - } - if (soundHi == std::nullopt) { - assert(normalRangeHi == 127); - } - - Inst inst = { name, addr, releaseRate, normalRangeLo, normalRangeHi, envAddr, soundLo, soundMed, soundHi }; - return inst; -} - -Loop AudioManager::parse_loop(uint32_t addr, std::vector& bankData){ - LUS::BinaryReader reader((char*) bankData.data(), bankData.size()); - reader.SetEndianness(LUS::Endianness::Big); - reader.Seek(addr, LUS::SeekOffsetType::Start); - - std::optional> state = std::nullopt; - uint32_t start = reader.ReadUInt32(); - uint32_t end = reader.ReadUInt32(); - int32_t count = reader.ReadInt32(); - uint32_t pad = reader.ReadUInt32(); - if(count != 0){ - state = std::vector(); - for (size_t i = 0; i < 16; ++i) { - state.value().push_back(reader.ReadShort()); - } - } - Loop loop = { start, end, count, pad, state }; - return loop; -} - -Book AudioManager::parse_book(uint32_t addr, std::vector& bankData){ - LUS::BinaryReader reader((char*) bankData.data(), bankData.size()); - reader.SetEndianness(LUS::Endianness::Big); - reader.Seek(addr, LUS::SeekOffsetType::Start); - - uint32_t order = reader.ReadInt32(); - uint32_t npredictors = reader.ReadInt32(); - std::vector table; - std::vector tableData = PyUtils::slice(bankData, addr + 8, addr + 8 + 16 * order * npredictors); - for (size_t i = 0; i < ( 16 * order * npredictors ); i += 2) { - short dtable; - memcpy(&dtable, tableData.data() + i, 2); - table.push_back(BSWAP16(dtable)); - } - - Book book = { order, npredictors, table }; - return book; -} - -AifcEntry* AudioManager::parse_sample(std::vector& data, std::vector& bankData, SampleBank* sampleBank){ - LUS::BinaryReader reader((char*) data.data(), data.size()); - reader.SetEndianness(LUS::Endianness::Big); - - uint32_t zero = reader.ReadUInt32(); - uint32_t addr = reader.ReadUInt32(); - uint32_t loop = reader.ReadUInt32(); - uint32_t book = reader.ReadUInt32(); - uint32_t sampleSize = reader.ReadUInt32(); - assert(zero == 0); - assert(loop != 0); - assert(book != 0); - - Loop loopData = parse_loop(loop, bankData); - Book bookData = parse_book(book, bankData); - - reader.Close(); - return sampleBank->AddSample(addr, sampleSize, bookData, loopData); -} - - -std::vector AudioManager::parse_envelope(uint32_t addr, std::vector& dataBank){ - std::vector entries; - LUS::BinaryReader reader((char*) dataBank.data(), dataBank.size()); - reader.SetEndianness(LUS::Endianness::Big); - - while(true){ - reader.Seek(addr, LUS::SeekOffsetType::Start); - unsigned short delay = reader.ReadUShort(); - unsigned short arg = reader.ReadUShort(); - entries.emplace_back(delay, arg); - addr += 4; - if (1 <= (-delay) % ((uint32_t) pow(2, 16)) <= 3.0){ - break; - } - } - - reader.Close(); - return entries; -} - Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, SampleBank* bank, uint32_t index) { name_table.clear(); std::ostringstream ss; @@ -262,11 +119,16 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, Sample std::vector drumOffsets; if(numDrums != 0){ + assert(drumBaseAddr != 0); for (size_t i = 0; i < numDrums; ++i) { uint32_t drumOffset; - memcpy(&drumOffset, rawData + drumBaseAddr + (i * 4), 4); - drumOffsets.push_back(BSWAP32(drumOffset)); + memcpy(&drumOffset, rawData + drumBaseAddr + i * 4, 4); + drumOffset = BSWAP32(drumOffset); + assert(drumOffset != 0); + drumOffsets.push_back(drumOffset); } + } else { + assert(drumBaseAddr == 0); } uint32_t instrumentBaseAddr = 4; @@ -275,22 +137,28 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, Sample for (size_t i = 0; i < numInstruments; ++i) { uint32_t instOffset; - memcpy(&instOffset, rawData + (instrumentBaseAddr + (i * 4)), 4); + memcpy(&instOffset, rawData + (instrumentBaseAddr + i * 4), 4); instOffset = BSWAP32(instOffset); if(instOffset == 0){ instrumentList.push_back(NONE); + instrumentOffsets.push_back(NONE); } else { instrumentOffsets.push_back(instOffset); instrumentList.push_back(instOffset); } } - std::sort(instrumentOffsets.begin(), instrumentOffsets.end()); +// std::sort(instrumentOffsets.begin(), instrumentOffsets.end()); - std::vector insts; + std::vector insts; for(auto &offset : instrumentOffsets){ + if(offset == NONE){ + Instrument invalid = { .valid = false }; + insts.push_back(invalid); + continue; + } auto rInst = PyUtils::slice(data, offset, offset + 32); - Inst inst = parse_inst(rInst, offset); + Instrument inst = parse_inst(rInst, offset); insts.push_back(inst); } @@ -322,12 +190,12 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, Sample // Put drums somewhere in the middle of the instruments to make sample // addresses come in increasing order. (This logic isn't totally right, // but it works for our purposes.) - std::vector>> allInsts; + std::vector>> allInsts; bool needDrums = !drums.empty(); for(auto &inst : insts){ - std::vector> sounds = {inst.soundLo, inst.soundMed, inst.soundHi}; + std::vector> sounds = {inst.soundLo, inst.soundMed, inst.soundHi}; - if(needDrums && std::any_of(sounds.cbegin(), sounds.cend(), [&drums](std::optional sound){ return sound.has_value() && sound.value().offset > drums[0].sound.offset; })){ + if(needDrums && std::any_of(sounds.cbegin(), sounds.cend(), [&drums](std::optional sound){ return sound.has_value() && sound.value().offset > drums[0].sound.offset; })){ allInsts.emplace_back(drums); needDrums = false; } @@ -340,18 +208,18 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, Sample allInsts.emplace_back(drums); } - std::unordered_map samples; + std::map samples; std::sort(sampleOffsets.begin(), sampleOffsets.end()); for(auto &offset : sampleOffsets){ auto rSample = PyUtils::slice(data, offset, offset + 20); - AifcEntry* sample = parse_sample(rSample, data, bank); + AudioBankSample* sample = parse_sample(rSample, data, bank); for(auto &tuning : tunings){ sample->tunings.push_back(tuning.second); } samples[offset] = sample; } - std::unordered_map> envData; + std::unordered_map> envData; std::vector usedEnvOffsets; std::sort(envOffsets.begin(), envOffsets.end()); for(auto &offset : envOffsets){ @@ -383,7 +251,7 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, Sample } } - std::unordered_map envelopes; + std::map envelopes; for(auto &entry : envData){ Envelope env = { gen_name("envelope"), entry.second }; envelopes[entry.first] = env; @@ -393,6 +261,156 @@ Bank AudioManager::parse_ctl(CTLHeader header, std::vector data, Sample return bankData; } +std::optional AudioManager::parse_sound(std::vector data) { + LUS::BinaryReader reader((char*) data.data(), data.size()); + reader.SetEndianness(LUS::Endianness::Big); + + uint32_t addr = reader.ReadUInt32(); + float tuning = reader.ReadFloat(); + + if(addr == 0){ + assert(tuning == 0.0f); + return std::nullopt; + } + + AudioBankSound sound = { addr, tuning }; + + reader.Close(); + return sound; +} + +Drum AudioManager::parse_drum(std::vector& data, uint32_t addr) { + LUS::BinaryReader reader((char*) data.data(), data.size()); + reader.SetEndianness(LUS::Endianness::Big); + std::string name = gen_name("drum"); + + uint8_t releaseRate = reader.ReadInt8(); + uint8_t pan = reader.ReadInt8(); + + reader.Seek(12, LUS::SeekOffsetType::Start); + AudioBankSound sound = parse_sound(PyUtils::slice(data, 4, 12)).value(); + uint32_t envOffset = reader.ReadInt32(); + assert(envOffset != 0); + + Drum drum = { name, addr, releaseRate, pan, envOffset, sound }; + + return drum; +} + +Instrument AudioManager::parse_inst(std::vector& data, uint32_t addr) { + std::string name = gen_name("inst"); + uint8_t normalRangeLo = data[1]; + uint8_t normalRangeHi = data[2]; + uint8_t releaseRate = data[3]; + + uint32_t envAddr; + memcpy(&envAddr, (char*) data.data() + 4, 4); + envAddr = BSWAP32(envAddr); + + assert(envAddr != 0); + + auto soundLo = parse_sound(PyUtils::slice(data, 8, 16)); + auto soundMed = parse_sound(PyUtils::slice(data, 16, 24)); + auto soundHi = parse_sound(PyUtils::slice(data, 24)); + + if (soundLo == std::nullopt) { + assert(normalRangeLo == 0); + } + if (soundHi == std::nullopt) { + assert(normalRangeHi == 127); + } + + Instrument inst = { true, name, addr, releaseRate, normalRangeLo, normalRangeHi, envAddr, soundLo, soundMed, soundHi }; + return inst; +} + +AdpcmLoop AudioManager::parse_loop(uint32_t addr, std::vector& bankData){ + LUS::BinaryReader reader((char*) bankData.data(), bankData.size()); + reader.SetEndianness(LUS::Endianness::Big); + reader.Seek(addr, LUS::SeekOffsetType::Start); + + std::optional> state = std::nullopt; + uint32_t start = reader.ReadUInt32(); + uint32_t end = reader.ReadUInt32(); + int32_t count = reader.ReadInt32(); + uint32_t pad = reader.ReadUInt32(); + + std::cout << "Loop End: " << end << '\n'; + if(count != 0){ + state = std::vector(); + for (size_t i = 0; i < 16; ++i) { + state.value().push_back(reader.ReadInt16()); + } + } + AdpcmLoop loop = { start, end, count, pad, state }; + return loop; +} + +AdpcmBook AudioManager::parse_book(uint32_t addr, std::vector& bankData){ + LUS::BinaryReader reader((char*) bankData.data(), bankData.size()); + reader.SetEndianness(LUS::Endianness::Big); + reader.Seek(addr, LUS::SeekOffsetType::Start); + + int32_t order = reader.ReadInt32(); + int32_t npredictors = reader.ReadInt32(); + + assert(order == 2); + assert(npredictors == 2); + + std::vector table; + std::vector tableData = PyUtils::slice(bankData, addr + 8, addr + 8 + 16 * order * npredictors); + for (size_t i = 0; i < ( 16 * order * npredictors ); i += 2) { + int16_t dtable; + memcpy(&dtable, tableData.data() + i, 2); + table.push_back(BSWAP16(dtable)); + } + + AdpcmBook book = { order, npredictors, table }; + return book; +} + +AudioBankSample* AudioManager::parse_sample(std::vector& data, std::vector& bankData, SampleBank* sampleBank){ + LUS::BinaryReader reader((char*) data.data(), data.size()); + reader.SetEndianness(LUS::Endianness::Big); + + uint32_t zero = reader.ReadUInt32(); + uint32_t addr = reader.ReadUInt32(); + uint32_t loop = reader.ReadUInt32(); + uint32_t book = reader.ReadUInt32(); + uint32_t sampleSize = reader.ReadUInt32(); + assert(zero == 0); + assert(loop != 0); + assert(book != 0); + + AdpcmLoop loopData = parse_loop(loop, bankData); + AdpcmBook bookData = parse_book(book, bankData); + + reader.Close(); + return sampleBank->AddSample(addr, sampleSize, bookData, loopData); +} + + +std::vector AudioManager::parse_envelope(uint32_t addr, std::vector& dataBank){ + std::vector entries; + LUS::BinaryReader reader((char*) dataBank.data(), dataBank.size()); + reader.SetEndianness(LUS::Endianness::Big); + + while(true){ + reader.Seek(addr, LUS::SeekOffsetType::Start); + int16_t delay = reader.ReadInt16(); + int16_t arg = reader.ReadInt16(); + AdsrEnvelope entry = { delay, arg }; + entries.push_back(entry); + addr += 4; + if (1 <= (-delay) % (1 << 16) && (-delay) % (1 << 16) <= 3){ + break; + } + } + + reader.Close(); + return entries; +} + TBLFile AudioManager::parse_tbl(std::vector& data, std::vector& entries) { TBLFile tbl; std::unordered_map cache; @@ -441,14 +459,22 @@ void AudioManager::initialize(std::vector& buffer) { auto headerRaw = PyUtils::slice(entry, 0, 16); auto header = parse_ctl_header(headerRaw); auto bank = parse_ctl(header, PyUtils::slice(entry, 16), sample_bank, index); - banks.push_back(bank); + banks[index] = bank; } + int32_t idx = -1; + for(auto &sample_bank : this->loaded_tbl.banks){ + auto offsets = PyUtils::keys(sample_bank->entries); + std::sort(offsets.begin(), offsets.end()); + for(auto &offset : offsets){ + this->sampleMap[sample_bank->entries[offset]] = ++idx; + } + } } void serialize_f80(double num, LUS::BinaryWriter &writer) { - // Convert the input double to a uint64_t + // Convert the input double to an uint64_t std::uint64_t f64; std::memcpy(&f64, &num, sizeof(double)); @@ -505,7 +531,7 @@ void serialize_f80(double num, LUS::BinaryWriter &writer) { } \ } \ -void AudioManager::write_aifc(AifcEntry* entry, LUS::BinaryWriter &out) { +void AudioManager::write_aifc(AudioBankSample* entry, LUS::BinaryWriter &out) { int16_t num_channels = 1; auto data = entry->data; size_t len = 0; @@ -549,7 +575,7 @@ void AudioManager::write_aifc(AifcEntry* entry, LUS::BinaryWriter &out) { tmp.Write((uint16_t) sample_size); serialize_f80(sample_rate, tmp); tmp.Write(AIFC::MagicValues::VAPC); - tmp.Write("\u000BVADPCM ~4-1", false); + tmp.Write("\x0bVADPCM ~4-1", false); END_SECTION(); @@ -557,7 +583,7 @@ void AudioManager::write_aifc(AifcEntry* entry, LUS::BinaryWriter &out) { tmp.Write(std::string(20, '\0'), false); END_SECTION(); - START_CUSTOM_SECTION("\u000BVADPCMCODES") + START_CUSTOM_SECTION("\x0bVADPCMCODES") tmp.Write((uint16_t) 1); tmp.Write((uint16_t) entry->book.order); tmp.Write((uint16_t) entry->book.npredictors); @@ -575,7 +601,7 @@ void AudioManager::write_aifc(AifcEntry* entry, LUS::BinaryWriter &out) { END_SECTION(); if(entry->loop.count != 0){ - START_CUSTOM_SECTION("\u000BVADPCMLOOPS") + START_CUSTOM_SECTION("\x0bVADPCMLOOPS") uint16_t one = BSWAP16(1); tmp.Write((char*) &one, 2); tmp.Write((char*) &one, 2); @@ -609,3 +635,30 @@ void AudioManager::create_aifc(int32_t index, LUS::BinaryWriter &out) { } } } + +AudioBankSample AudioManager::get_aifc(int32_t index) { + int32_t idx = -1; + for(auto &sample_bank : this->loaded_tbl.banks){ + auto offsets = PyUtils::keys(sample_bank->entries); + std::sort(offsets.begin(), offsets.end()); + + for(auto &offset : offsets){ + if(++idx == index){ + return *sample_bank->entries[offset]; + } + } + } + + throw std::runtime_error("Invalid index"); +} + +uint32_t AudioManager::get_index(AudioBankSample* entry) { + if(!this->sampleMap.contains(entry)){ + return -1; + } + return this->sampleMap[entry]; +} + +std::map AudioManager::get_banks() { + return this->banks; +} -- cgit v1.2.3 From 98b6d598324fdcb499a2cc4d37a7a6fcd19e8ead Mon Sep 17 00:00:00 2001 From: KiritoDv Date: Sat, 16 Sep 2023 03:10:56 -0600 Subject: Added support to extract banks on each sequence --- src/audio/AudioManager.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/audio/AudioManager.cpp') diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp index d72bda6..2316141 100644 --- a/src/audio/AudioManager.cpp +++ b/src/audio/AudioManager.cpp @@ -335,7 +335,6 @@ AdpcmLoop AudioManager::parse_loop(uint32_t addr, std::vector& bankData int32_t count = reader.ReadInt32(); uint32_t pad = reader.ReadUInt32(); - std::cout << "Loop End: " << end << '\n'; if(count != 0){ state = std::vector(); for (size_t i = 0; i < 16; ++i) { @@ -433,6 +432,7 @@ TBLFile AudioManager::parse_tbl(std::vector& data, std::vector& void AudioManager::initialize(std::vector& buffer) { auto assets = nlohmann::json::parse(std::ifstream( "assets.json" )); auto sound_data = assets["@sound_data"]["us"]; + auto sound_tbl = sound_data["sound_tbl"]; auto sound_ctl = sound_data["sound_ctl"]; @@ -661,4 +661,4 @@ uint32_t AudioManager::get_index(AudioBankSample* entry) { std::map AudioManager::get_banks() { return this->banks; -} +} \ No newline at end of file -- cgit v1.2.3