diff options
| author | KiritoDv <kiritodev01@gmail.com> | 2024-11-24 03:00:38 -0600 |
|---|---|---|
| committer | KiritoDv <kiritodev01@gmail.com> | 2024-11-24 03:00:38 -0600 |
| commit | 714b555d13ee1f2cfe107353dbfd76b81c993b62 (patch) | |
| tree | 872ad2ee9e096e5f55ef9279435ea958b7ee8be6 /src | |
| parent | de6b8fa447b6db093c95375e9b4ca82878f04c90 (diff) | |
Added XML Extraction
Diffstat (limited to 'src')
| -rw-r--r-- | src/Companion.cpp | 162 | ||||
| -rw-r--r-- | src/Companion.h | 2 | ||||
| -rw-r--r-- | src/factories/BaseFactory.h | 6 | ||||
| -rw-r--r-- | src/factories/naudio/v1/AudioContext.cpp | 57 | ||||
| -rw-r--r-- | src/factories/naudio/v1/AudioContext.h | 4 | ||||
| -rw-r--r-- | src/factories/naudio/v1/SampleFactory.cpp | 58 | ||||
| -rw-r--r-- | src/factories/naudio/v1/SampleFactory.h | 5 | ||||
| -rw-r--r-- | src/main.cpp | 9 |
8 files changed, 201 insertions, 102 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp index e16c670..6b813b5 100644 --- a/src/Companion.cpp +++ b/src/Companion.cpp @@ -454,6 +454,7 @@ std::string ExportTypeToString(ExportType type) { case ExportType::Header: return "Header"; case ExportType::Code: return "Code"; case ExportType::Modding: return "Modding"; + case ExportType::XML: return "XML"; default: throw std::runtime_error("Invalid ExportType"); } @@ -559,66 +560,31 @@ void Companion::ProcessFile(YAML::Node root) { auto node = asset->second; auto entryName = asset->first.as<std::string>(); - // Parse horizontal assets - if(node["files"]){ - auto segment = node["segment"] ? node["segment"].as<uint8_t>() : -1; - const auto files = node["files"]; - for (const auto& file : files) { - auto assetNode = file.as<YAML::Node>(); - auto childName = assetNode["name"].as<std::string>(); - auto output = (this->gCurrentDirectory / entryName / childName).string(); - std::replace(output.begin(), output.end(), '\\', '/'); - - if(assetNode["type"]){ - const auto type = GetSafeNode<std::string>(assetNode, "type"); - if(type == "SAMPLE"){ - AudioManager::Instance->bind_sample(assetNode, output); - } - } - - if(!assetNode["offset"]) { - continue; - } - - if(segment != -1 || gCurrentSegmentNumber) { - assetNode["offset"] = (segment << 24) | assetNode["offset"].as<uint32_t>(); - } - - if(!gCurrentVirtualPath.empty()) { - node["path"] = gCurrentVirtualPath; - } - - this->gAddrMap[this->gCurrentFile][assetNode["offset"].as<uint32_t>()] = std::make_tuple(output, assetNode); - } - } else { - - auto output = (this->gCurrentDirectory / entryName).string(); - std::replace(output.begin(), output.end(), '\\', '/'); + auto output = (this->gCurrentDirectory / entryName).string(); + std::replace(output.begin(), output.end(), '\\', '/'); - - if(node["type"]){ - const auto type = GetSafeNode<std::string>(node, "type"); - if(type == "SAMPLE"){ - AudioManager::Instance->bind_sample(node, output); - } - } - - if(!node["offset"]) { - continue; + if(node["type"]){ + const auto type = GetSafeNode<std::string>(node, "type"); + if(type == "SAMPLE"){ + AudioManager::Instance->bind_sample(node, output); } + } - if(gCurrentSegmentNumber) { - if (IS_SEGMENTED(node["offset"].as<uint32_t>()) == false) { - node["offset"] = (gCurrentSegmentNumber << 24) | node["offset"].as<uint32_t>(); - } - } + if(!node["offset"]) { + continue; + } - if(!gCurrentVirtualPath.empty()) { - node["path"] = gCurrentVirtualPath; + if(gCurrentSegmentNumber) { + if (IS_SEGMENTED(node["offset"].as<uint32_t>()) == false) { + node["offset"] = (gCurrentSegmentNumber << 24) | node["offset"].as<uint32_t>(); } + } - this->gAddrMap[this->gCurrentFile][node["offset"].as<uint32_t>()] = std::make_tuple(output, node); + if(!gCurrentVirtualPath.empty()) { + node["path"] = gCurrentVirtualPath; } + + this->gAddrMap[this->gCurrentFile][node["offset"].as<uint32_t>()] = std::make_tuple(output, node); } // Stupid hack because the iteration broke the assets @@ -656,53 +622,23 @@ void Companion::ProcessFile(YAML::Node root) { continue; } - // Parse horizontal assets - if(assetNode["files"]){ - auto segment = assetNode["segment"] ? assetNode["segment"].as<uint8_t>() : -1; - auto files = assetNode["files"]; - for (const auto& file : files) { - auto node = file.as<YAML::Node>(); - auto childName = node["name"].as<std::string>(); - - if(!node["offset"]) { - continue; - } - - if(segment != -1 || gCurrentFileOffset) { - node["offset"] = (segment << 24) | node["offset"].as<uint32_t>(); - } - - if(!gCurrentVirtualPath.empty()) { - node["path"] = gCurrentVirtualPath; - } - - auto output = (this->gCurrentDirectory / entryName / childName).string(); - std::replace(output.begin(), output.end(), '\\', '/'); - this->gConfig.segment.temporal.clear(); - auto result = this->ParseNode(node, output); - if(result.has_value()) { - this->gParseResults[this->gCurrentFile].push_back(result.value()); - } - } - } else { - if(gCurrentFileOffset && assetNode["offset"]) { - const auto offset = assetNode["offset"].as<uint32_t>(); - if (!IS_SEGMENTED(offset)) { - assetNode["offset"] = (gCurrentSegmentNumber << 24) | offset; - } + if(gCurrentFileOffset && assetNode["offset"]) { + const auto offset = assetNode["offset"].as<uint32_t>(); + if (!IS_SEGMENTED(offset)) { + assetNode["offset"] = (gCurrentSegmentNumber << 24) | offset; } + } - if(!gCurrentVirtualPath.empty()) { - assetNode["path"] = gCurrentVirtualPath; - } + if(!gCurrentVirtualPath.empty()) { + assetNode["path"] = gCurrentVirtualPath; + } - std::string output = (this->gCurrentDirectory / entryName).string(); - std::replace(output.begin(), output.end(), '\\', '/'); - this->gConfig.segment.temporal.clear(); - auto result = this->ParseNode(assetNode, output); - if(result.has_value()) { - this->gParseResults[this->gCurrentFile].push_back(result.value()); - } + std::string output = (this->gCurrentDirectory / entryName).string(); + std::replace(output.begin(), output.end(), '\\', '/'); + this->gConfig.segment.temporal.clear(); + auto result = this->ParseNode(assetNode, output); + if(result.has_value()) { + this->gParseResults[this->gCurrentFile].push_back(result.value()); } spdlog::set_pattern(regular); @@ -730,8 +666,16 @@ void Companion::ProcessFile(YAML::Node root) { exporter->get()->Export(stream, data, result.name, result.node, &result.name); auto data = stream.str(); this->gCurrentWrapper->CreateFile(result.name, std::vector(data.begin(), data.end())); + + for(auto& entry : this->gCompanionFiles){ + auto output = (this->gCurrentDirectory / entry.first).string(); + std::replace(output.begin(), output.end(), '\\', '/'); + this->gCurrentWrapper->CreateFile(output, entry.second); + } + break; } + case ExportType::XML: case ExportType::Modding: { stream.str(""); stream.clear(); @@ -748,12 +692,24 @@ void Companion::ProcessFile(YAML::Node root) { create_directories(fs::path(dpath).parent_path()); } - SPDLOG_INFO(ogname); this->gModdedAssetPaths[ogname] = result.name; std::ofstream file(dpath, std::ios::binary); file.write(data.c_str(), data.size()); file.close(); + + for(auto& entry : this->gCompanionFiles){ + auto cpath = (Instance->GetOutputPath() / this->gCurrentDirectory / entry.first).string(); + std::replace(cpath.begin(), cpath.end(), '\\', '/'); + if(!exists(fs::path(cpath).parent_path())){ + create_directories(fs::path(cpath).parent_path()); + } + + std::ofstream cfile(cpath, std::ios::binary); + cfile.write(entry.second.data(), entry.second.size()); + cfile.close(); + } + break; } default: { @@ -762,6 +718,8 @@ void Companion::ProcessFile(YAML::Node root) { } } + this->gCompanionFiles.clear(); + if(result.node["offset"]) { auto alignment = GetSafeNode<uint32_t>(result.node, "alignment", impl->GetAlignment()); if(!endptr.has_value()) { @@ -807,7 +765,7 @@ void Companion::ProcessFile(YAML::Node root) { auto fsout = fs::path(this->gConfig.outputPath); - if(this->gConfig.exporterType == ExportType::Modding) { + if(this->gConfig.exporterType == ExportType::Modding || this->gConfig.exporterType == ExportType::XML) { fsout /= "modding.yml"; YAML::Node modding; @@ -1048,6 +1006,7 @@ void Companion::Process() { this->gConfig.outputPath = opath && opath["code"] ? opath["code"].as<std::string>() : "code"; break; } + case ExportType::XML: case ExportType::Modding: { this->gConfig.outputPath = modding_path; break; @@ -1420,6 +1379,11 @@ std::optional<std::vector<std::tuple<std::string, YAML::Node>>> Companion::GetNo } +void Companion::RegisterCompanionFile(const std::string path, std::vector<char> data) { + this->gCompanionFiles[path] = data; + SPDLOG_INFO("Registered companion file {}", path); +} + std::string Companion::NormalizeAsset(const std::string& name) const { auto path = fs::path(this->gCurrentFile).stem().string() + "_" + name; return path; diff --git a/src/Companion.h b/src/Companion.h index eb51783..6f14708 100644 --- a/src/Companion.h +++ b/src/Companion.h @@ -154,6 +154,7 @@ public: static void Pack(const std::string& folder, const std::string& output); std::string NormalizeAsset(const std::string& name) const; std::string RelativePath(const std::string& path) const; + void RegisterCompanionFile(const std::string path, std::vector<char> data); TorchConfig& GetConfig() { return this->gConfig; } SWrapper* GetCurrentWrapper() { return this->gCurrentWrapper; } @@ -190,6 +191,7 @@ private: std::vector<std::string> gCurrentExternalFiles; std::unordered_set<std::string> gProcessedFiles; + std::unordered_map<std::string, std::vector<char>> gCompanionFiles; std::unordered_map<std::string, std::vector<ParseResultData>> gParseResults; std::unordered_map<std::string, std::string> gModdedAssetPaths; diff --git a/src/factories/BaseFactory.h b/src/factories/BaseFactory.h index 0320605..f3f30aa 100644 --- a/src/factories/BaseFactory.h +++ b/src/factories/BaseFactory.h @@ -11,10 +11,13 @@ #include <variant> #include <optional> #include <yaml-cpp/yaml.h> +#include <filesystem> #include <strhash64/StrHash64.h> #include "lib/binarytools/BinaryWriter.h" #include "lib/binarytools/BinaryReader.h" +namespace fs = std::filesystem; + #define REGISTER(type, c) { ExportType::type, std::make_shared<c>() }, #define SEGMENT_OFFSET(a) ((uint32_t)(a) & 0x00FFFFFF) @@ -37,7 +40,8 @@ enum class ExportType { Header, Code, Binary, - Modding + Modding, + XML }; template<typename T> diff --git a/src/factories/naudio/v1/AudioContext.cpp b/src/factories/naudio/v1/AudioContext.cpp index 7954aef..ce434ac 100644 --- a/src/factories/naudio/v1/AudioContext.cpp +++ b/src/factories/naudio/v1/AudioContext.cpp @@ -63,7 +63,7 @@ TunedSample AudioContext::LoadTunedSample(LUS::BinaryReader& reader, uint32_t pa node["offset"] = parent + sampleAddr; node["tuning"] = tuning; node["sampleBankId"] = sampleBankId; - node["symbol"] = StringHelper::Sprintf("Sample_P_%X_O_%X_B_%d", parent, parent + sampleAddr, sampleBankId); + node["symbol"] = StringHelper::Sprintf("%d_Sample_P_%X_B_%d", parent + sampleAddr, parent, sampleBankId); Companion::Instance->AddAsset(node); return { parent + sampleAddr, sampleBankId, tuning }; @@ -84,4 +84,59 @@ uint64_t AudioContext::GetPathByAddr(uint32_t addr) { SPDLOG_INFO("Failed to find path for 0x{:X}", addr); throw std::runtime_error("Failed to find node by addr"); } +} + +const char* AudioContext::GetMediumStr(uint8_t medium) { + switch (medium) { + case 0: + return "Ram"; + case 1: + return "Unk"; + case 2: + return "Cart"; + case 3: + return "Disk"; + case 5: + return "RamUnloaded"; + default: + return "ERROR"; + } +} + +const char* AudioContext::GetCachePolicyStr(uint8_t policy) { + switch (policy) { + case 0: + return "Temporary"; + case 1: + return "Persistent"; + case 2: + return "Either"; + case 3: + return "Permanent"; + default: + return "ERROR"; + } +} + +const char* AudioContext::GetCodecStr(uint8_t codec) { + switch (codec) { + case 0: + return "ADPCM"; + case 1: + return "S8"; + case 2: + return "S16MEM"; + case 3: + return "ADPCMSMALL"; + case 4: + return "REVERB"; + case 5: + return "S16"; + case 6: + return "UNK6"; + case 7: + return "UNK7"; + default: + return "ERROR"; + } }
\ No newline at end of file diff --git a/src/factories/naudio/v1/AudioContext.h b/src/factories/naudio/v1/AudioContext.h index 84e5337..a965f10 100644 --- a/src/factories/naudio/v1/AudioContext.h +++ b/src/factories/naudio/v1/AudioContext.h @@ -20,6 +20,10 @@ public: 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); + + static const char* GetMediumStr(uint8_t medium); + static const char* GetCachePolicyStr(uint8_t policy); + static const char* GetCodecStr(uint8_t codec); }; class AudioContextFactory : public BaseFactory { diff --git a/src/factories/naudio/v1/SampleFactory.cpp b/src/factories/naudio/v1/SampleFactory.cpp index b35467e..58e9afb 100644 --- a/src/factories/naudio/v1/SampleFactory.cpp +++ b/src/factories/naudio/v1/SampleFactory.cpp @@ -1,6 +1,9 @@ #include "SampleFactory.h" #include "AudioConverter.h" #include "Companion.h" +#include <tinyxml2.h> +#include "LoopFactory.h" +#include "BookFactory.h" #include <factories/naudio/v0/AIFCDecode.h> ExportResult NSampleHeaderExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement) { @@ -58,6 +61,61 @@ ExportResult NSampleModdingExporter::Export(std::ostream &write, std::shared_ptr return std::nullopt; } +ExportResult NSampleXMLExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) { + auto aiff = LUS::BinaryWriter(); + auto entry = std::static_pointer_cast<NSampleData>(raw); + auto loop = std::static_pointer_cast<ADPCMLoopData>(Companion::Instance->GetParseDataByAddr(entry->loop)->data.value()); + auto book = std::static_pointer_cast<ADPCMBookData>(Companion::Instance->GetParseDataByAddr(entry->book)->data.value()); + + auto path = fs::path(*replacement); + + *replacement += ".meta"; + + tinyxml2::XMLDocument sample; + tinyxml2::XMLElement* root = sample.NewElement("Sample"); + root->SetAttribute("Codec", AudioContext::GetCodecStr(entry->codec)); + root->SetAttribute("Medium", AudioContext::GetMediumStr(entry->medium)); + root->SetAttribute("Unk", entry->unk); + // root->SetAttribute("Relocated", entry->isRelocated); + + tinyxml2::XMLElement* adpcmLoop = sample.NewElement("ADPCMLoop"); + adpcmLoop->SetAttribute("Start", loop->start); + adpcmLoop->SetAttribute("End", loop->end); + adpcmLoop->SetAttribute("Count", loop->count); + if (loop->count != 0) { + for (size_t i = 0; i < 16; i++) { + tinyxml2::XMLElement* loopEntry = adpcmLoop->InsertNewChildElement("Predictor"); + loopEntry->SetAttribute("State", loop->predictorState[i]); + adpcmLoop->InsertEndChild(loopEntry); + } + } + root->InsertEndChild(adpcmLoop); + + tinyxml2::XMLElement* adpcmBook = sample.NewElement("ADPCMBook"); + adpcmBook->SetAttribute("Order", book->order); + adpcmBook->SetAttribute("Npredictors", book->numPredictors); + + for (size_t i = 0; i < book->book.size(); i++) { + tinyxml2::XMLElement* bookEntry = adpcmBook->InsertNewChildElement("Book"); + bookEntry->SetAttribute("Page", book->book[i]); + adpcmBook->InsertEndChild(bookEntry); + } + root->InsertEndChild(adpcmBook); + sample.InsertEndChild(root); + + tinyxml2::XMLPrinter printer; + sample.Accept(&printer); + write.write(printer.CStr(), printer.CStrSize() - 1); + + auto tableEntry = AudioContext::tableData[AudioTableType::SAMPLE_TABLE]->entries[entry->sampleBankId]; + auto buffer = AudioContext::data[AudioTableType::SAMPLE_TABLE]; + auto sampleData = buffer.data() + tableEntry.addr + entry->sampleAddr; + std::vector<char> data(sampleData, sampleData + entry->size); + Companion::Instance->RegisterCompanionFile(path.filename(), data); + + 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"); diff --git a/src/factories/naudio/v1/SampleFactory.h b/src/factories/naudio/v1/SampleFactory.h index d447cc2..eb7cff5 100644 --- a/src/factories/naudio/v1/SampleFactory.h +++ b/src/factories/naudio/v1/SampleFactory.h @@ -36,6 +36,10 @@ class NSampleModdingExporter : public BaseExporter { ExportResult Export(std::ostream& write, std::shared_ptr<IParsedData> data, std::string& entryName, YAML::Node& node, std::string* replacement) override; }; +class NSampleXMLExporter : 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; @@ -45,6 +49,7 @@ public: REGISTER(Binary, NSampleBinaryExporter) REGISTER(Code, NSampleCodeExporter) REGISTER(Modding, NSampleModdingExporter) + REGISTER(XML, NSampleXMLExporter) }; } bool SupportModdedAssets() override { return true; } diff --git a/src/main.cpp b/src/main.cpp index ee1d92a..33ca27a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -98,11 +98,18 @@ int main(int argc, char *argv[]) { } }); + modding_export->add_option("mode", mode, "xml or binary")->required(); modding_export->add_option("<baserom.z64>", filename, "")->required()->check(CLI::ExistingFile); modding_export->parse_complete_callback([&] { const auto instance = Companion::Instance = new Companion(filename, false, debug); - instance->Init(ExportType::Modding); + if (mode == "binary") { + instance->Init(ExportType::Modding); + } else if (mode == "xml") { + instance->Init(ExportType::XML); + } else { + std::cout << "Invalid mode" << std::endl; + } }); try { |
