#include "midi.h" #include "main.h" #include "reader.h" #include "util.h" #include #include #include std::filesystem::path MidiAsset::generateAssetPath() { std::filesystem::path path = this->path; return path.replace_extension(".mid"); } std::filesystem::path MidiAsset::generateBuildPath() { std::filesystem::path path = this->path; return path.replace_extension(".s"); } void MidiAsset::extractBinary(const std::vector& baserom) { // Custom extraction as we need a label in the middle. std::string label = this->path.stem(); std::filesystem::path tracksPath = this->path; tracksPath.replace_filename(label + "_tracks.bin"); std::filesystem::path headerPath = this->path; headerPath.replace_filename(label + "_header.bin"); int headerOffset = this->asset["options"]["headerOffset"]; // Extract tracks { auto first = baserom.begin() + this->start; auto last = baserom.begin() + this->start + headerOffset; std::vector data(first, last); std::fstream file(tracksPath, std::ios::out | std::ios::binary); file.write(&data[0], data.size()); file.close(); } // Extract header { auto first = baserom.begin() + this->start + headerOffset; auto last = baserom.begin() + this->start + this->size; std::vector data(first, last); std::fstream file(headerPath, std::ios::out | std::ios::binary); file.write(&data[0], data.size()); file.close(); } // Create dummy .s file. std::ofstream out(this->buildPath); out << "\t.incbin " << tracksPath << "\n"; out << label << "::\n"; out << "\t.incbin " << headerPath << "\n"; out.close(); } void MidiAsset::parseOptions(std::vector& commonParams, std::vector& agb2midParams) { bool exactGateTime = true; for (const auto& it : this->asset["options"].items()) { const std::string& key = it.key(); if (key == "group" || key == "G") { commonParams.push_back("-G"); commonParams.push_back(to_string(it.value())); } else if (key == "priority" || key == "P") { commonParams.push_back("-P"); commonParams.push_back(to_string(it.value())); } else if (key == "reverb" || key == "R") { commonParams.push_back("-R"); commonParams.push_back(to_string(it.value())); } else if (key == "nominator") { agb2midParams.push_back("-n"); agb2midParams.push_back(to_string(it.value())); } else if (key == "denominator") { agb2midParams.push_back("-d"); agb2midParams.push_back(to_string(it.value())); } else if (key == "timeChanges") { const nlohmann::json& value = it.value(); if (value.is_array()) { // Multiple time changes for (const auto& change : value) { agb2midParams.push_back("-t"); agb2midParams.push_back(to_string(change["nominator"])); agb2midParams.push_back(to_string(change["denominator"])); agb2midParams.push_back(to_string(change["time"])); } } else { agb2midParams.push_back("-t"); agb2midParams.push_back(to_string(value["nominator"])); agb2midParams.push_back(to_string(value["denominator"])); agb2midParams.push_back(to_string(value["time"])); } } else if (key == "exactGateTime") { if (it.value().get() == 1) { exactGateTime = true; } else { exactGateTime = false; } } else if (key == "headerOffset") { // ignore here } else { commonParams.push_back("-" + key); commonParams.push_back(to_string(it.value())); } } if (exactGateTime) { commonParams.push_back("-E"); } } void MidiAsset::convertToHumanReadable(const std::vector& baserom) { (void)baserom; // Convert the options std::vector commonParams; std::vector agb2midParams; this->parseOptions(commonParams, agb2midParams); int headerOffset = this->asset["options"]["headerOffset"]; std::filesystem::path toolPath = "tools"; std::vector cmd; cmd.push_back(toolPath / "agb2mid" / "agb2mid"); cmd.push_back(gBaseromPath); cmd.push_back(string_format("0x%x", this->start + headerOffset)); cmd.push_back(gBaseromPath); // TODO deduplicate? cmd.push_back(this->assetPath); cmd.insert(cmd.end(), commonParams.begin(), commonParams.end()); cmd.insert(cmd.end(), agb2midParams.begin(), agb2midParams.end()); check_call(cmd); // We also need to build the mid to an s file here, so we get shiftability after converting. cmd.clear(); cmd.push_back(toolPath / "mid2agb" / "mid2agb"); cmd.push_back(this->assetPath); cmd.push_back(this->buildPath); cmd.insert(cmd.end(), commonParams.begin(), commonParams.end()); check_call(cmd); } void MidiAsset::buildToBinary() { // Convert the options std::vector commonParams; std::vector agb2midParams; this->parseOptions(commonParams, agb2midParams); std::filesystem::path toolPath = "tools"; std::vector cmd; cmd.push_back(toolPath / "mid2agb" / "mid2agb"); cmd.push_back(this->assetPath); cmd.push_back(this->buildPath); cmd.insert(cmd.end(), commonParams.begin(), commonParams.end()); check_call(cmd); }