diff options
| author | KiritoDv <kiritodev01@gmail.com> | 2024-11-19 16:40:24 -0600 |
|---|---|---|
| committer | Lywx <kiritodev01@gmail.com> | 2024-11-21 00:05:17 -0600 |
| commit | 528ea6090bbc39f77d320b3fb9b8caa4fe958948 (patch) | |
| tree | f176350645d478cc80fa1505120591936ff9ba3b /src | |
| parent | 4451ae28dba815411a39fcda22a3455d1ea69343 (diff) | |
Recreated audio export system to something more generic
Diffstat (limited to 'src')
33 files changed, 1144 insertions, 12 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp index 8059e8c..19c4f1a 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -26,10 +26,6 @@ #include "factories/AssetArrayFactory.h" #include "factories/ViewportFactory.h" -#include "factories/sm64/audio/BankFactory.h" -#include "factories/sm64/audio/AudioHeaderFactory.h" -#include "factories/sm64/audio/SampleFactory.h" -#include "factories/sm64/audio/SequenceFactory.h" #include "factories/sm64/AnimationFactory.h" #include "factories/sm64/BehaviorScriptFactory.h" #include "factories/sm64/CollisionFactory.h" @@ -66,6 +62,21 @@ #include "factories/sf64/ObjInitFactory.h" #include "factories/sf64/TriangleFactory.h" +#include "factories/naudio/v0/AudioHeaderFactory.h" +#include "factories/naudio/v0/BankFactory.h" +#include "factories/naudio/v0/SampleFactory.h" +#include "factories/naudio/v0/SequenceFactory.h" + +#include "factories/naudio/v1/AudioContext.h" +#include "factories/naudio/v1/SoundFontFactory.h" +#include "factories/naudio/v1/AudioTableFactory.h" +#include "factories/naudio/v1/InstrumentFactory.h" +#include "factories/naudio/v1/SampleFactory.h" +#include "factories/naudio/v1/DrumFactory.h" +#include "factories/naudio/v1/EnvelopeFactory.h" +#include "factories/naudio/v1/LoopFactory.h" +#include "factories/naudio/v1/BookFactory.h" + using namespace std::chrono; namespace fs = std::filesystem; @@ -95,10 +106,6 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("VP", std::make_shared<ViewportFactory>()); // SM64 specific - this->RegisterFactory("SM64:AUDIO_HEADER", std::make_shared<AudioHeaderFactory>()); - this->RegisterFactory("SM64:SEQUENCE", std::make_shared<SequenceFactory>()); - this->RegisterFactory("SM64:SAMPLE", std::make_shared<SampleFactory>()); - this->RegisterFactory("SM64:BANK", std::make_shared<BankFactory>()); this->RegisterFactory("SM64:DIALOG", std::make_shared<SM64::DialogFactory>()); this->RegisterFactory("SM64:TEXT", std::make_shared<SM64::TextFactory>()); this->RegisterFactory("SM64:DICTIONARY", std::make_shared<SM64::DictionaryFactory>()); @@ -137,6 +144,22 @@ void Companion::Init(const ExportType type) { this->RegisterFactory("SF64:COLPOLY", std::make_shared<SF64::ColPolyFactory>()); this->RegisterFactory("SF64:TRIANGLE", std::make_shared<SF64::TriangleFactory>()); + // NAudio specific + this->RegisterFactory("NAUDIO:V0:AUDIO_HEADER", std::make_shared<AudioHeaderFactory>()); + this->RegisterFactory("NAUDIO:V0:SEQUENCE", std::make_shared<SequenceFactory>()); + this->RegisterFactory("NAUDIO:V0:SAMPLE", std::make_shared<SampleFactory>()); + this->RegisterFactory("NAUDIO:V0:BANK", std::make_shared<BankFactory>()); + + this->RegisterFactory("NAUDIO:V1:AUDIO_SETUP", std::make_shared<AudioContextFactory>()); + this->RegisterFactory("NAUDIO:V1:AUDIO_TABLE", std::make_shared<AudioTableFactory>()); + this->RegisterFactory("NAUDIO:V1:SOUND_FONT", std::make_shared<SoundFontFactory>()); + this->RegisterFactory("NAUDIO:V1:INSTRUMENT", std::make_shared<InstrumentFactory>()); + this->RegisterFactory("NAUDIO:V1:DRUM", std::make_shared<DrumFactory>()); + this->RegisterFactory("NAUDIO:V1:SAMPLE", std::make_shared<NSampleFactory>()); + this->RegisterFactory("NAUDIO:V1:ENVELOPE", std::make_shared<EnvelopeFactory>()); + this->RegisterFactory("NAUDIO:V1:ADPCM_LOOP", std::make_shared<ADPCMLoopFactory>()); + this->RegisterFactory("NAUDIO:V1:ADPCM_BOOK", std::make_shared<ADPCMBookFactory>()); + this->Process(); } @@ -1451,6 +1474,9 @@ std::optional<YAML::Node> Companion::AddAsset(YAML::Node asset) { } else { output = this->NormalizeAsset(typeId + "_" + Torch::to_hex(offset, false)); } + + std::replace(output.begin(), output.end(), ':', '_'); + asset["autogen"] = true; asset["symbol"] = output; diff --git a/src/factories/BaseFactory.h b/src/factories/BaseFactory.h index d7b71e9..0320605 100644 --- a/src/factories/BaseFactory.h +++ b/src/factories/BaseFactory.h @@ -111,5 +111,7 @@ public: return std::nullopt; } private: - virtual std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() = 0; + virtual std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() { + return {}; + } };
\ No newline at end of file diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h index 7039dbc..4f00098 100644 --- a/src/factories/ResourceType.h +++ b/src/factories/ResourceType.h @@ -15,9 +15,6 @@ enum class ResourceType { Array = 0x4F415252, // OARR Blob = 0x4F424C42, // OBLB Texture = 0x4F544558, // OTEX - Bank = 0x42414E4B, // BANK - Sample = 0x41554643, // AIFC - Sequence = 0x53455143, // SEQC Lights = 0x46669697, // LGTS Vec3f = 0x56433346, // VC3F Vec3s = 0x56433353, // VC3S @@ -63,5 +60,18 @@ enum class ResourceType { ScriptCmd = 0x53434D44, // SCMD Hitbox = 0x48544258, // HTBX ObjectInit = 0x4F42494E, // OBIN + + // NAudio v0 + Bank = 0x42414E4B, // BANK + Sample = 0x41554643, // AIFC + Sequence = 0x53455143, // SEQC + + // NAudio v1 + SoundFont = 0x53464E54, // SFNT + Drum = 0x4452554D, // DRUM + Instrument = 0x494E5354, // INST + AdpcmLoop = 0x4150434C, // APCL + AdpcmBook = 0x41504342, // APCB + Envelope = 0x45564C50, // EVLP }; } // namespace LUS diff --git a/src/factories/sm64/audio/AIFCDecode.cpp b/src/factories/naudio/v0/AIFCDecode.cpp index e627ad0..e627ad0 100644 --- a/src/factories/sm64/audio/AIFCDecode.cpp +++ b/src/factories/naudio/v0/AIFCDecode.cpp diff --git a/src/factories/sm64/audio/AIFCDecode.h b/src/factories/naudio/v0/AIFCDecode.h index e141a80..e141a80 100644 --- a/src/factories/sm64/audio/AIFCDecode.h +++ b/src/factories/naudio/v0/AIFCDecode.h diff --git a/src/factories/sm64/audio/AudioHeaderFactory.cpp b/src/factories/naudio/v0/AudioHeaderFactory.cpp index dc4d547..dc4d547 100644 --- a/src/factories/sm64/audio/AudioHeaderFactory.cpp +++ b/src/factories/naudio/v0/AudioHeaderFactory.cpp diff --git a/src/factories/sm64/audio/AudioHeaderFactory.h b/src/factories/naudio/v0/AudioHeaderFactory.h index 1c5c0b1..1c5c0b1 100644 --- a/src/factories/sm64/audio/AudioHeaderFactory.h +++ b/src/factories/naudio/v0/AudioHeaderFactory.h diff --git a/src/factories/sm64/audio/AudioManager.cpp b/src/factories/naudio/v0/AudioManager.cpp index c168a39..c168a39 100644 --- a/src/factories/sm64/audio/AudioManager.cpp +++ b/src/factories/naudio/v0/AudioManager.cpp diff --git a/src/factories/sm64/audio/AudioManager.h b/src/factories/naudio/v0/AudioManager.h index b5a9dcc..b5a9dcc 100644 --- a/src/factories/sm64/audio/AudioManager.h +++ b/src/factories/naudio/v0/AudioManager.h diff --git a/src/factories/sm64/audio/BankFactory.cpp b/src/factories/naudio/v0/BankFactory.cpp index 6e72c53..6e72c53 100644 --- a/src/factories/sm64/audio/BankFactory.cpp +++ b/src/factories/naudio/v0/BankFactory.cpp diff --git a/src/factories/sm64/audio/BankFactory.h b/src/factories/naudio/v0/BankFactory.h index 9f4b260..9f4b260 100644 --- a/src/factories/sm64/audio/BankFactory.h +++ b/src/factories/naudio/v0/BankFactory.h diff --git a/src/factories/sm64/audio/SampleFactory.cpp b/src/factories/naudio/v0/SampleFactory.cpp index b8bc7fa..b8bc7fa 100644 --- a/src/factories/sm64/audio/SampleFactory.cpp +++ b/src/factories/naudio/v0/SampleFactory.cpp diff --git a/src/factories/sm64/audio/SampleFactory.h b/src/factories/naudio/v0/SampleFactory.h index ae940e2..ae940e2 100644 --- a/src/factories/sm64/audio/SampleFactory.h +++ b/src/factories/naudio/v0/SampleFactory.h diff --git a/src/factories/sm64/audio/SequenceFactory.cpp b/src/factories/naudio/v0/SequenceFactory.cpp index 1090bac..1090bac 100644 --- a/src/factories/sm64/audio/SequenceFactory.cpp +++ b/src/factories/naudio/v0/SequenceFactory.cpp diff --git a/src/factories/sm64/audio/SequenceFactory.h b/src/factories/naudio/v0/SequenceFactory.h index b26242c..b26242c 100644 --- a/src/factories/sm64/audio/SequenceFactory.h +++ b/src/factories/naudio/v0/SequenceFactory.h diff --git a/src/factories/naudio/v1/AudioContext.cpp b/src/factories/naudio/v1/AudioContext.cpp new file mode 100644 index 0000000..3800eb2 --- /dev/null +++ b/src/factories/naudio/v1/AudioContext.cpp @@ -0,0 +1,78 @@ +#include "AudioContext.h" +#include "spdlog/spdlog.h" +#include "Companion.h" + +std::unordered_map<AudioTableType, std::unordered_map<uint32_t, AudioTableEntry>> AudioContext::tables; +std::unordered_map<AudioTableType, std::vector<uint8_t>> AudioContext::data; +std::unordered_map<AudioTableType, AudioTableData> AudioContext::tableData; + +std::optional<std::shared_ptr<IParsedData>> AudioContextFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto seq = GetSafeNode<YAML::Node>(node, "audio_seq"); + auto seqSize = GetSafeNode<uint32_t>(seq, "size"); + auto seqOffset = GetSafeNode<uint32_t>(seq, "offset"); + + auto bank = GetSafeNode<YAML::Node>(node, "audio_bank"); + auto bankSize = GetSafeNode<uint32_t>(bank, "size"); + auto bankOffset = GetSafeNode<uint32_t>(bank, "offset"); + + auto table = GetSafeNode<YAML::Node>(node, "audio_table"); + auto tableSize = GetSafeNode<uint32_t>(table, "size"); + auto tableOffset = GetSafeNode<uint32_t>(table, "offset"); + + AudioContext::data[AudioTableType::SEQ_TABLE] = std::vector<uint8_t>(buffer.begin() + seqOffset, buffer.begin() + seqOffset + seqSize); + AudioContext::data[AudioTableType::FONT_TABLE] = std::vector<uint8_t>(buffer.begin() + bankOffset, buffer.begin() + bankOffset + bankSize); + AudioContext::data[AudioTableType::SAMPLE_TABLE] = std::vector<uint8_t>(buffer.begin() + tableOffset, buffer.begin() + tableOffset + tableSize); + + SPDLOG_INFO("Sequence Table 0x{:X}", seqOffset); + SPDLOG_INFO("Sound Font Table 0x{:X}", bankOffset); + SPDLOG_INFO("Sample Bank Table 0x{:X}", tableOffset); + + return std::nullopt; +} + +LUS::BinaryReader AudioContext::MakeReader(AudioTableType type, uint32_t offset) { + auto entry = AudioContext::data[type]; + + LUS::BinaryReader reader(entry.data(), entry.size()); + reader.SetEndianness(Torch::Endianness::Big); + reader.Seek(offset, LUS::SeekOffsetType::Start); + + return reader; +} + +TunedSample AudioContext::LoadTunedSample(LUS::BinaryReader& reader, uint32_t parent, uint32_t sampleBankId) { + auto sampleAddr = reader.ReadUInt32(); + auto tuning = reader.ReadFloat(); + + if(sampleAddr == 0){ + if(tuning != 0.0f){ + throw std::runtime_error("The provided tuned sample is invalid"); + } + return { 0, 0, 0.0f }; + } + + YAML::Node node; + node["type"] = "NAUDIO:V1:SAMPLE"; + node["parent"] = parent; + node["offset"] = parent + sampleAddr; + node["sampleBankId"] = sampleBankId; + Companion::Instance->AddAsset(node); + + return { parent + sampleAddr, sampleBankId, tuning }; +} + +uint64_t AudioContext::GetPathByAddr(uint32_t addr) { + if(addr == 0){ + return 0; + } + + auto dec = Companion::Instance->GetNodeByAddr(addr); + if (dec.has_value()) { + std::string path = std::get<0>(dec.value()); + uint64_t hash = CRC64(path.c_str()); + SPDLOG_INFO("Found path of 0x{:X} {}", addr, path); + return hash; + } else { + throw std::runtime_error("Failed to find node by addr"); + } +}
\ No newline at end of file diff --git a/src/factories/naudio/v1/AudioContext.h b/src/factories/naudio/v1/AudioContext.h new file mode 100644 index 0000000..0ea5014 --- /dev/null +++ b/src/factories/naudio/v1/AudioContext.h @@ -0,0 +1,35 @@ +#pragma once + +#include "AudioTableFactory.h" +#include "factories/naudio/v0/AudioHeaderFactory.h" +#include "factories/BaseFactory.h" + +struct TunedSample { + uint32_t sample; + uint32_t sampleBankId; + float tuning; +}; + +class AudioContext { +public: + static std::unordered_map<AudioTableType, std::unordered_map<uint32_t, AudioTableEntry>> tables; + static std::unordered_map<AudioTableType, std::shared_ptr<AudioTableData>> tableData; + static std::unordered_map<AudioTableType, std::vector<uint8_t>> data; + + static LUS::BinaryReader MakeReader(AudioTableType type, uint32_t offset); + static TunedSample LoadTunedSample(LUS::BinaryReader& reader, uint32_t parent, uint32_t sampleBankId); + static uint64_t GetPathByAddr(uint32_t addr); +}; + +class AudioContextFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, AudioDummyExporter) + REGISTER(Binary, AudioDummyExporter) + REGISTER(Code, AudioDummyExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/AudioTableFactory.cpp b/src/factories/naudio/v1/AudioTableFactory.cpp new file mode 100644 index 0000000..2dcd665 --- /dev/null +++ b/src/factories/naudio/v1/AudioTableFactory.cpp @@ -0,0 +1,131 @@ +#include "AudioTableFactory.h" +#include "utils/Decompressor.h" +#include "spdlog/spdlog.h" +#include "AudioContext.h" +#include "Companion.h" +#include <iomanip> + +#define INT2(c) std::dec << std::setfill(' ') << c +#define HEX(c) "0x" << std::hex << std::setw(4) << std::setfill('0') << c +#define ADDR(c) "0x" << std::hex << std::setw(5) << std::setfill('0') << c + +static const std::unordered_map <std::string, AudioTableType> gTableTypes = { + { "SOUNDFONT", AudioTableType::FONT_TABLE }, + { "SAMPLE", AudioTableType::SAMPLE_TABLE }, + { "SEQUENCE", AudioTableType::SEQ_TABLE } +}; + +ExportResult AudioTableHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern AudioTable " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult AudioTableCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + const auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto table = std::static_pointer_cast<AudioTableData>(raw); + + if(table->type == AudioTableType::FONT_TABLE){ + write << "#define SOUNDFONT_ENTRY(offset, size, medium, cachePolicy, bank1, bank2, numInst, numDrums) { \\\n"; + write << fourSpaceTab << "offset, size, medium, cachePolicy, (((bank1) &0xFF) << 8) | ((bank2) &0xFF), \\\n"; + write << fourSpaceTab << fourSpaceTab << "(((numInst) &0xFF) << 8) | ((numDrums) &0xFF) \\\n}\n\n"; + } + + write << "AudioTable " << symbol << " = {\n"; + write << fourSpaceTab << "{ " << table->entries.size() << ", " << table->medium << ", " << table->addr << " },\n"; + write << fourSpaceTab << "{ \n"; + + for(size_t i = 0; i < table->entries.size(); i++){ + auto &entry = table->entries[i]; + + if(table->type == AudioTableType::FONT_TABLE) { + uint32_t numInstruments = (entry.shortData2 >> 8) & 0xFFu; + uint32_t numDrums = entry.shortData2 & 0xFFu; + uint32_t sampleBankId1 = (entry.shortData1 >> 8) & 0xFFu; + uint32_t sampleBankId2 = entry.shortData1 & 0xFFu; + + write << fourSpaceTab << fourSpaceTab << "SOUNDFONT_ENTRY(" << ADDR(entry.addr) << ", " << HEX(entry.size) << ", " << INT2((uint32_t) entry.medium) << ", " << INT2((uint32_t) entry.cachePolicy) << ", " << INT2(numInstruments) << ", " << INT2(numDrums) << ", " << INT2(sampleBankId1) << ", " << INT2(sampleBankId2) << "),\n" ; + } else { + write << fourSpaceTab << fourSpaceTab << "{ " << ADDR(entry.addr) << ", " << HEX(entry.size) << ", " << (uint32_t) entry.medium << ", " << (uint32_t) entry.cachePolicy << " },\n"; + } + } + + write << fourSpaceTab << "},\n"; + write << "};\n"; + + if (Companion::Instance->IsDebug()) { + write << "// Count: " << table->entries.size() << "\n"; + } + + return offset + 0x10 + (table->entries.size() * sizeof(AudioTableEntry)); +} + +ExportResult AudioTableBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + // auto data = std::static_pointer_cast<AudioTableEntry>(raw)->mBuffer; + + // WriteHeader(writer, Torch::ResourceType::Blob, 0); + // writer.Write((uint32_t) data.size()); + // writer.Write((char*) data.data(), data.size()); + // writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> AudioTableFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + // Parse table entry + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto [_, segment] = Decompressor::AutoDecode(node, buffer); + LUS::BinaryReader reader(segment.data, segment.size); + reader.SetEndianness(Torch::Endianness::Big); + + auto format = GetSafeNode<std::string>(node, "format"); + std::transform(format.begin(), format.end(), format.begin(), ::toupper); + + if(!gTableTypes.contains(format)) { + return std::nullopt; + } + + auto type = gTableTypes.at(format); + auto count = reader.ReadInt16(); + auto bmedium = reader.ReadInt16(); + auto baddr = reader.ReadUInt32(); + reader.Read(0x8); // PAD + + SPDLOG_INFO("count: {}", count); + SPDLOG_INFO("medium: {}", bmedium); + SPDLOG_INFO("addr: {}", baddr); + + std::vector<AudioTableEntry> entries; + for(size_t i = 0; i < count; i++){ + auto addr = reader.ReadUInt32(); + auto size = reader.ReadUInt32(); + auto medium = reader.ReadInt8(); + auto policy = reader.ReadInt8(); + auto sd1 = reader.ReadInt16(); + auto sd2 = reader.ReadInt16(); + auto sd3 = reader.ReadInt16(); + auto entry = AudioTableEntry { addr, size, medium, policy, sd1, sd2, sd3 }; + entries.push_back(entry); + + if(type == AudioTableType::FONT_TABLE){ + YAML::Node font; + font["type"] = "NAUDIO:V1:SOUND_FONT"; + font["offset"] = addr; + Companion::Instance->AddAsset(font); + } + + AudioContext::tables[type][addr] = entry; + } + + auto table = std::make_shared<AudioTableData>(bmedium, offset, type, entries); + AudioContext::tableData[type] = table; + return table; +} diff --git a/src/factories/naudio/v1/AudioTableFactory.h b/src/factories/naudio/v1/AudioTableFactory.h new file mode 100644 index 0000000..8d83dc0 --- /dev/null +++ b/src/factories/naudio/v1/AudioTableFactory.h @@ -0,0 +1,53 @@ +#pragma once + +#include <factories/BaseFactory.h> + +struct AudioTableEntry { + uint32_t addr; + uint32_t size; + int8_t medium; + int8_t cachePolicy; + int16_t shortData1; + int16_t shortData2; + int16_t shortData3; +}; + +enum class AudioTableType { + SAMPLE_TABLE, + SEQ_TABLE, + FONT_TABLE +}; + +class AudioTableData : public IParsedData { +public: + int16_t medium; + uint32_t addr; + AudioTableType type; + std::vector<AudioTableEntry> entries; + + AudioTableData(int16_t medium, uint32_t addr, AudioTableType type, std::vector<AudioTableEntry> entries) : medium(medium), addr(addr), type(type), entries(entries) {} +}; + +class AudioTableHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class AudioTableBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class AudioTableCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class AudioTableFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, AudioTableHeaderExporter) + REGISTER(Binary, AudioTableBinaryExporter) + REGISTER(Code, AudioTableCodeExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/BookFactory.cpp b/src/factories/naudio/v1/BookFactory.cpp new file mode 100644 index 0000000..96d1e53 --- /dev/null +++ b/src/factories/naudio/v1/BookFactory.cpp @@ -0,0 +1,58 @@ +#include "BookFactory.h" +#include "utils/Decompressor.h" +#include "Companion.h" + +ExportResult ADPCMBookHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern AdpcmBook " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult ADPCMBookCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + return std::nullopt; +} + +ExportResult ADPCMBookBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast<ADPCMBookData>(raw); + + WriteHeader(writer, Torch::ResourceType::AdpcmBook, 0); + writer.Write(data->order); + writer.Write(data->numPredictors); + writer.Write((uint32_t) data->book.size()); + + for(auto& page : data->book){ + writer.Write(page); + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> ADPCMBookFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset); + + auto book = std::make_shared<ADPCMBookData>(); + + book->order = reader.ReadInt32(); + book->numPredictors = reader.ReadInt32(); + size_t length = 8 * book->order * book->numPredictors; + + if(length > 0x40){ + return std::nullopt; + } + + for(size_t i = 0; i < length; i++){ + book->book.push_back(reader.ReadInt16()); + } + + return book; +} diff --git a/src/factories/naudio/v1/BookFactory.h b/src/factories/naudio/v1/BookFactory.h new file mode 100644 index 0000000..a761f22 --- /dev/null +++ b/src/factories/naudio/v1/BookFactory.h @@ -0,0 +1,35 @@ +#pragma once + +#include <factories/BaseFactory.h> +#include "AudioContext.h" + +class ADPCMBookData : public IParsedData { +public: + int32_t order; + int32_t numPredictors; + std::vector<int16_t> book; +}; + +class ADPCMBookHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ADPCMBookBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ADPCMBookCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ADPCMBookFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, ADPCMBookHeaderExporter) + REGISTER(Binary, ADPCMBookBinaryExporter) + REGISTER(Code, ADPCMBookCodeExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/DrumFactory.cpp b/src/factories/naudio/v1/DrumFactory.cpp new file mode 100644 index 0000000..bceaaae --- /dev/null +++ b/src/factories/naudio/v1/DrumFactory.cpp @@ -0,0 +1,63 @@ +#include "DrumFactory.h" +#include "utils/Decompressor.h" +#include "Companion.h" + +ExportResult DrumHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern Drum " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult DrumCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + return std::nullopt; +} + +ExportResult DrumBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast<DrumData>(raw); + + WriteHeader(writer, Torch::ResourceType::Drum, 0); + writer.Write(data->adsrDecayIndex); + writer.Write(data->pan); + writer.Write(data->isRelocated); + writer.Write(AudioContext::GetPathByAddr(data->tunedSample.sample)); + writer.Write(data->tunedSample.tuning); + writer.Write(AudioContext::GetPathByAddr(data->envelope)); + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> DrumFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto parent = GetSafeNode<uint32_t>(node, "parent"); + auto sampleBankId = GetSafeNode<uint32_t>(node, "sampleBankId"); + + auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(parent); + + auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset); + + auto drum = std::make_shared<DrumData>(); + drum->adsrDecayIndex = reader.ReadInt8(); + drum->pan = reader.ReadInt8(); + drum->isRelocated = reader.ReadUByte(); + reader.ReadUByte();; + + drum->tunedSample = AudioContext::LoadTunedSample(reader, parent, sampleBankId); + + auto envAddr = entry.addr + reader.ReadUInt32(); + YAML::Node envelope; + envelope["type"] = "NAUDIO:V1:ENVELOPE"; + envelope["offset"] = envAddr; + drum->envelope = envAddr; + Companion::Instance->AddAsset(envelope); + + return drum; +} diff --git a/src/factories/naudio/v1/DrumFactory.h b/src/factories/naudio/v1/DrumFactory.h new file mode 100644 index 0000000..e417e9a --- /dev/null +++ b/src/factories/naudio/v1/DrumFactory.h @@ -0,0 +1,37 @@ +#pragma once + +#include <factories/BaseFactory.h> +#include "AudioContext.h" + +class DrumData : public IParsedData { +public: + uint8_t adsrDecayIndex; + uint8_t pan; + uint8_t isRelocated; + TunedSample tunedSample; + uint32_t envelope; +}; + +class DrumHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class DrumBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class DrumCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class DrumFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, DrumHeaderExporter) + REGISTER(Binary, DrumBinaryExporter) + REGISTER(Code, DrumCodeExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/EnvelopeFactory.cpp b/src/factories/naudio/v1/EnvelopeFactory.cpp new file mode 100644 index 0000000..3ba6755 --- /dev/null +++ b/src/factories/naudio/v1/EnvelopeFactory.cpp @@ -0,0 +1,54 @@ +#include "EnvelopeFactory.h" +#include "utils/Decompressor.h" +#include "Companion.h" + +ExportResult EnvelopeHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern Envelope " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult EnvelopeCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + return std::nullopt; +} + +ExportResult EnvelopeBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast<EnvelopeData>(raw); + + WriteHeader(writer, Torch::ResourceType::Envelope, 0); + writer.Write((uint32_t) data->points.size()); + for(auto& point : data->points){ + writer.Write(point.delay); + writer.Write(point.arg); + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> EnvelopeFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset); + + std::vector<EnvelopePoint> temp; + while(true) { + int16_t delay = BSWAP16(reader.ReadInt16()); + int16_t arg = BSWAP16(reader.ReadInt16()); + + temp.push_back({delay, arg}); + + if (1 <= (-delay) % (1 << 16) && (-delay) % (1 << 16) <= 3){ + break; + } + } + + return std::make_shared<EnvelopeData>(temp); +} diff --git a/src/factories/naudio/v1/EnvelopeFactory.h b/src/factories/naudio/v1/EnvelopeFactory.h new file mode 100644 index 0000000..a75d031 --- /dev/null +++ b/src/factories/naudio/v1/EnvelopeFactory.h @@ -0,0 +1,41 @@ +#pragma once + +#include <factories/BaseFactory.h> +#include <vector> +#include "AudioContext.h" + +struct EnvelopePoint { + int16_t delay; + int16_t arg; +}; + +class EnvelopeData : public IParsedData { +public: + std::vector<EnvelopePoint> points; + + EnvelopeData(std::vector<EnvelopePoint> points) : points(points) {}; +}; + +class EnvelopeHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EnvelopeBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EnvelopeCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class EnvelopeFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, EnvelopeHeaderExporter) + REGISTER(Binary, EnvelopeBinaryExporter) + REGISTER(Code, EnvelopeCodeExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/InstrumentFactory.cpp b/src/factories/naudio/v1/InstrumentFactory.cpp new file mode 100644 index 0000000..acfada1 --- /dev/null +++ b/src/factories/naudio/v1/InstrumentFactory.cpp @@ -0,0 +1,70 @@ +#include "InstrumentFactory.h" +#include "utils/Decompressor.h" +#include "Companion.h" + +ExportResult InstrumentHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern Instrument " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult InstrumentCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + return std::nullopt; +} + +ExportResult InstrumentBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast<InstrumentData>(raw); + + WriteHeader(writer, Torch::ResourceType::Instrument, 0); + writer.Write(data->isRelocated); + writer.Write(data->normalRangeLo); + writer.Write(data->normalRangeHi); + writer.Write(data->adsrDecayIndex); + writer.Write(AudioContext::GetPathByAddr(data->envelope)); + writer.Write(AudioContext::GetPathByAddr(data->lowPitchTunedSample.sample)); + writer.Write(data->lowPitchTunedSample.tuning); + writer.Write(AudioContext::GetPathByAddr(data->normalPitchTunedSample.sample)); + writer.Write(data->normalPitchTunedSample.tuning); + writer.Write(AudioContext::GetPathByAddr(data->highPitchTunedSample.sample)); + writer.Write(data->highPitchTunedSample.tuning); + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> InstrumentFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto parent = GetSafeNode<uint32_t>(node, "parent"); + auto sampleBankId = GetSafeNode<uint32_t>(node, "sampleBankId"); + + auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(parent); + + auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset); + + auto instrument = std::make_shared<InstrumentData>(); + instrument->isRelocated = reader.ReadUByte(); + instrument->normalRangeLo = reader.ReadUByte(); + instrument->normalRangeHi = reader.ReadUByte(); + instrument->adsrDecayIndex = reader.ReadUByte(); + + auto envAddr = entry.addr + reader.ReadUInt32(); + YAML::Node envelope; + envelope["type"] = "NAUDIO:V1:ENVELOPE"; + envelope["offset"] = envAddr; + instrument->envelope = envAddr; + Companion::Instance->AddAsset(envelope); + + instrument->lowPitchTunedSample = AudioContext::LoadTunedSample(reader, parent, sampleBankId); + instrument->normalPitchTunedSample = AudioContext::LoadTunedSample(reader, parent, sampleBankId); + instrument->highPitchTunedSample = AudioContext::LoadTunedSample(reader, parent, sampleBankId); + + return instrument; +} diff --git a/src/factories/naudio/v1/InstrumentFactory.h b/src/factories/naudio/v1/InstrumentFactory.h new file mode 100644 index 0000000..9d6ccf0 --- /dev/null +++ b/src/factories/naudio/v1/InstrumentFactory.h @@ -0,0 +1,40 @@ +#pragma once + +#include <factories/BaseFactory.h> +#include "AudioContext.h" + +class InstrumentData : public IParsedData { +public: + uint8_t isRelocated; + uint8_t normalRangeLo; + uint8_t normalRangeHi; + uint8_t adsrDecayIndex; + uint32_t envelope; + TunedSample lowPitchTunedSample; + TunedSample normalPitchTunedSample; + TunedSample highPitchTunedSample; +}; + +class InstrumentHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class InstrumentBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class InstrumentCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class InstrumentFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, InstrumentHeaderExporter) + REGISTER(Binary, InstrumentBinaryExporter) + REGISTER(Code, InstrumentCodeExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/LoopFactory.cpp b/src/factories/naudio/v1/LoopFactory.cpp new file mode 100644 index 0000000..522192e --- /dev/null +++ b/src/factories/naudio/v1/LoopFactory.cpp @@ -0,0 +1,56 @@ +#include "LoopFactory.h" +#include "utils/Decompressor.h" +#include "Companion.h" + +ExportResult ADPCMLoopHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern AdpcmLoop " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult ADPCMLoopCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + return std::nullopt; +} + +ExportResult ADPCMLoopBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast<ADPCMLoopData>(raw); + + WriteHeader(writer, Torch::ResourceType::AdpcmLoop, 0); + writer.Write(data->start); + writer.Write(data->end); + writer.Write(data->count); + if(data->count != 0){ + for(size_t i = 0; i < 16; i++){ + writer.Write(data->predictorState[i]); + } + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> ADPCMLoopFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset); + auto loop = std::make_shared<ADPCMLoopData>(); + + loop->start = reader.ReadInt32(); + loop->end = reader.ReadUInt32(); + loop->count = reader.ReadUInt32(); + + if(loop->count != 0){ + for(size_t i = 0; i < 16; i++){ + loop->predictorState[i] = reader.ReadInt16(); + } + } + + return loop; +} diff --git a/src/factories/naudio/v1/LoopFactory.h b/src/factories/naudio/v1/LoopFactory.h new file mode 100644 index 0000000..e281946 --- /dev/null +++ b/src/factories/naudio/v1/LoopFactory.h @@ -0,0 +1,36 @@ +#pragma once + +#include <factories/BaseFactory.h> +#include "AudioContext.h" + +class ADPCMLoopData : public IParsedData { +public: + uint32_t start; + uint32_t end; + uint32_t count; + int16_t predictorState[16]; +}; + +class ADPCMLoopHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ADPCMLoopBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ADPCMLoopCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class ADPCMLoopFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, ADPCMLoopHeaderExporter) + REGISTER(Binary, ADPCMLoopBinaryExporter) + REGISTER(Code, ADPCMLoopCodeExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/SampleFactory.cpp b/src/factories/naudio/v1/SampleFactory.cpp new file mode 100644 index 0000000..cafbdd9 --- /dev/null +++ b/src/factories/naudio/v1/SampleFactory.cpp @@ -0,0 +1,81 @@ +#include "SampleFactory.h" +#include "utils/Decompressor.h" +#include "Companion.h" + +ExportResult NSampleHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern Sample " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult NSampleCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + return std::nullopt; +} + +ExportResult NSampleBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast<NSampleData>(raw); + + WriteHeader(writer, Torch::ResourceType::Sample, 1); + writer.Write(data->codec); + writer.Write(data->medium); + writer.Write(data->unk); + writer.Write(data->size); + + writer.Write(AudioContext::GetPathByAddr(data->loop)); + writer.Write(AudioContext::GetPathByAddr(data->book)); + + auto entry = AudioContext::tableData[AudioTableType::SAMPLE_TABLE]->entries[data->sampleBankId]; + auto buffer = AudioContext::data[AudioTableType::SAMPLE_TABLE]; + + writer.Write((uint32_t) data->size); + writer.Write((char*) buffer.data() + data->sampleAddr, data->size); + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> NSampleFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto parent = GetSafeNode<uint32_t>(node, "parent"); + auto sampleBankId = GetSafeNode<uint32_t>(node, "sampleBankId"); + + auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(parent); + auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset); + + auto sample = std::make_shared<NSampleData>(); + + uint32_t flags = reader.ReadUInt32(); + uint32_t addr = reader.ReadUInt32(); + + sample->codec = (flags >> 28) & 0x0F; + sample->medium = (flags >> 24) & 0x03; + sample->unk = (flags >> 22) & 0x01; + sample->size = flags; + + auto loopAddr = entry.addr + reader.ReadUInt32(); + YAML::Node loop; + loop["type"] = "NAUDIO:V1:ADPCM_LOOP"; + loop["offset"] = loopAddr; + sample->loop = loopAddr; + Companion::Instance->AddAsset(loop); + + auto bookAddr = entry.addr + reader.ReadUInt32(); + YAML::Node book; + book["type"] = "NAUDIO:V1:ADPCM_BOOK"; + book["offset"] = bookAddr; + sample->book = bookAddr; + Companion::Instance->AddAsset(book); + + sample->sampleAddr = addr; + sample->sampleBankId = sampleBankId; + + return sample; +} diff --git a/src/factories/naudio/v1/SampleFactory.h b/src/factories/naudio/v1/SampleFactory.h new file mode 100644 index 0000000..3507188 --- /dev/null +++ b/src/factories/naudio/v1/SampleFactory.h @@ -0,0 +1,41 @@ +#pragma once + +#include <factories/BaseFactory.h> +#include "AudioContext.h" + +class NSampleData : public IParsedData { +public: + uint32_t codec; + uint32_t medium; + uint32_t unk; + uint32_t isRelocated; + uint32_t size; + uint32_t sampleAddr; + uint32_t loop; + uint32_t book; + uint32_t sampleBankId; +}; + +class NSampleHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class NSampleBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class NSampleCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class NSampleFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, NSampleHeaderExporter) + REGISTER(Binary, NSampleBinaryExporter) + REGISTER(Code, NSampleCodeExporter) + }; + } +}; diff --git a/src/factories/naudio/v1/SoundFontFactory.cpp b/src/factories/naudio/v1/SoundFontFactory.cpp new file mode 100644 index 0000000..87870f8 --- /dev/null +++ b/src/factories/naudio/v1/SoundFontFactory.cpp @@ -0,0 +1,148 @@ +#include "SoundFontFactory.h" +#include "AudioContext.h" +#include "Companion.h" +#include "spdlog/spdlog.h" +#include "utils/Decompressor.h" + +ExportResult SoundFontHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { + const auto symbol = GetSafeNode(node, "symbol", entryName); + + if(Companion::Instance->IsOTRMode()){ + write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + return std::nullopt; + } + + write << "extern SoundFont " << symbol << ";\n"; + + return std::nullopt; +} + +ExportResult SoundFontCodeExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + // auto symbol = GetSafeNode(node, "symbol", entryName); + // auto offset = GetSafeNode<uint32_t>(node, "offset"); + // auto data = std::static_pointer_cast<RawBuffer>(raw)->mBuffer; + + // if(Companion::Instance->IsOTRMode()){ + // write << "static const ALIGN_ASSET(2) char " << symbol << "[] = \"__OTR__" << (*replacement) << "\";\n\n"; + // return std::nullopt; + // } + + // write << GetSafeNode<std::string>(node, "ctype", "u8") << " " << symbol << "[] = {\n" << tab_t; + + // for (int i = 0; i < data.size(); i++) { + // if ((i % 15 == 0) && i != 0) { + // write << "\n" << tab_t; + // } + + // write << "0x" << std::hex << std::setw(2) << std::setfill('0') << (int) data[i] << ", "; + // } + // write << "\n};\n"; + + // if (Companion::Instance->IsDebug()) { + // write << "// size: 0x" << std::hex << std::uppercase << data.size() << "\n"; + // } + + // return offset + data.size(); + return std::nullopt; +} + +ExportResult SoundFontBinaryExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto writer = LUS::BinaryWriter(); + auto data = std::static_pointer_cast<SoundFontData>(raw); + + WriteHeader(writer, Torch::ResourceType::SoundFont, 0); + writer.Write(data->numInstruments); + writer.Write(data->numDrums); + writer.Write(data->sampleBankId1); + writer.Write(data->sampleBankId2); + + for(auto& instrument : data->instruments){ + auto crc = AudioContext::GetPathByAddr(instrument); + writer.Write(crc); + } + + for(auto& drum : data->drums){ + auto crc = AudioContext::GetPathByAddr(drum); + writer.Write(crc); + } + + writer.Finish(write); + return std::nullopt; +} + +std::optional<std::shared_ptr<IParsedData>> SoundFontFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) { + auto offset = GetSafeNode<uint32_t>(node, "offset"); + auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(offset); + auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, entry.addr); + auto font = std::make_shared<SoundFontData>(); + + font->numInstruments = (entry.shortData2 >> 8) & 0xFFu; + font->numDrums = entry.shortData2 & 0xFFu; + font->sampleBankId1 = (entry.shortData1 >> 8) & 0xFFu; + font->sampleBankId2 = entry.shortData1 & 0xFFu; + + uint32_t drumBaseAddr = reader.ReadUInt32(); + uint32_t instBaseAddr = 4; + + if(drumBaseAddr != 0){ + reader.Seek(entry.addr + drumBaseAddr, LUS::SeekOffsetType::Start); + for(size_t i = 0; i < font->numDrums; i++){ + uint32_t addr = reader.ReadUInt32(); + + if(addr == 0){ + font->drums.push_back(0); + continue; + } + + // SPDLOG_INFO("Found Drum[{}] 0x{:X}", i, addr); + + YAML::Node drum; + drum["type"] = "NAUDIO:V1:DRUM"; + drum["parent"] = entry.addr; + drum["offset"] = entry.addr + addr; + drum["sampleBankId"] = (uint32_t) font->sampleBankId1; + + Companion::Instance->AddAsset(drum); + font->drums.push_back(entry.addr + addr); + } + +// YAML::Node table; +// table["type"] = "ASSET_ARRAY"; +// table["assetType"] = "Drum"; +// table["factoryType"] = "NAUDIO:V1:DRUM"; +// table["offset"] = entry.addr + drumBaseAddr; +// table["count"] = (uint32_t) font->numDrums; +// Companion::Instance->AddAsset(table); + } + + reader.Seek(entry.addr + instBaseAddr, LUS::SeekOffsetType::Start); + for(size_t i = 0; i < font->numInstruments; i++){ + uint32_t addr = reader.ReadUInt32(); + + if(addr == 0){ + font->instruments.push_back(0); + continue; + } + + // SPDLOG_INFO("Found Instrument[{}] 0x{:X}", i, addr); + + YAML::Node instrument; + instrument["type"] = "NAUDIO:V1:INSTRUMENT"; + instrument["parent"] = entry.addr; + instrument["offset"] = entry.addr + addr; + instrument["sampleBankId"] = (uint32_t) font->sampleBankId1; + font->instruments.push_back(entry.addr + addr); + + Companion::Instance->AddAsset(instrument); + } + +// YAML::Node table; +// table["type"] = "ASSET_ARRAY"; +// table["assetType"] = "Instrument"; +// table["factoryType"] = "NAUDIO:V1:INSTRUMENT"; +// table["offset"] = entry.addr + instBaseAddr; +// table["count"] = (uint32_t) font->numInstruments; +// Companion::Instance->AddAsset(table); + + return font; +} diff --git a/src/factories/naudio/v1/SoundFontFactory.h b/src/factories/naudio/v1/SoundFontFactory.h new file mode 100644 index 0000000..8bb73e4 --- /dev/null +++ b/src/factories/naudio/v1/SoundFontFactory.h @@ -0,0 +1,37 @@ +#pragma once + +#include <factories/BaseFactory.h> + +class SoundFontData : public IParsedData { +public: + uint8_t numInstruments; + uint8_t numDrums; + uint8_t sampleBankId1; + uint8_t sampleBankId2; + std::vector<uint32_t> instruments; + std::vector<uint32_t> drums; +}; + +class SoundFontHeaderExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SoundFontBinaryExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SoundFontCodeExporter : public BaseExporter { + ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; +}; + +class SoundFontFactory : public BaseFactory { +public: + std::optional<std::shared_ptr<IParsedData>> parse(std::vector<uint8_t>& buffer, YAML::Node& data) override; + inline std::unordered_map<ExportType, std::shared_ptr<BaseExporter>> GetExporters() override { + return { + REGISTER(Header, SoundFontHeaderExporter) + REGISTER(Binary, SoundFontBinaryExporter) + REGISTER(Code, SoundFontCodeExporter) + }; + } +}; |
