summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKiritoDv <kiritodev01@gmail.com>2023-09-17 23:55:59 -0600
committerKiritoDv <kiritodev01@gmail.com>2023-09-17 23:55:59 -0600
commit396f732bc58080430562ea60fd345bf2e51cfc0b (patch)
tree69a90e2d4e255074bc5c476c991deb7b30f847e3 /src
parent87ba0d258759a03b2397d63ba5d203cf5fe26c0f (diff)
Refactored to use a better file format
Diffstat (limited to 'src')
-rw-r--r--src/Companion.cpp131
-rw-r--r--src/Companion.h12
-rw-r--r--src/audio/AudioManager.cpp20
-rw-r--r--src/audio/AudioManager.h3
-rw-r--r--src/factories/AnimFactory.cpp39
-rw-r--r--src/factories/AnimFactory.h2
-rw-r--r--src/factories/AudioFactory.cpp191
-rw-r--r--src/factories/AudioFactory.h9
-rw-r--r--src/factories/AudioHeaderFactory.cpp10
-rw-r--r--src/factories/AudioHeaderFactory.h9
-rw-r--r--src/factories/BankFactory.cpp94
-rw-r--r--src/factories/BankFactory.h9
-rw-r--r--src/factories/BlobFactory.cpp25
-rw-r--r--src/factories/BlobFactory.h8
-rw-r--r--src/factories/RawFactory.h4
-rw-r--r--src/factories/SampleFactory.cpp46
-rw-r--r--src/factories/SampleFactory.h9
-rw-r--r--src/factories/SequenceFactory.cpp21
-rw-r--r--src/factories/SequenceFactory.h9
-rw-r--r--src/factories/TextureFactory.cpp77
-rw-r--r--src/factories/TextureFactory.h15
-rw-r--r--src/main.cpp2
-rw-r--r--src/n64/Cartridge.cpp59
-rw-r--r--src/n64/Cartridge.h30
24 files changed, 467 insertions, 367 deletions
diff --git a/src/Companion.cpp b/src/Companion.cpp
index df793be..d234ee7 100644
--- a/src/Companion.cpp
+++ b/src/Companion.cpp
@@ -5,92 +5,105 @@
#include "audio/AudioManager.h"
#include "factories/RawFactory.h"
#include "factories/BlobFactory.h"
-#include "factories/AudioFactory.h"
+#include "factories/AudioHeaderFactory.h"
+#include "factories/SequenceFactory.h"
+#include "factories/SampleFactory.h"
+#include "factories/BankFactory.h"
#include "factories/TextureFactory.h"
#include "factories/AnimFactory.h"
+#include "n64/Cartridge.h"
#include <fstream>
#include <iostream>
#include <filesystem>
-#include <nlohmann/json.hpp>
-using json = nlohmann::json;
namespace fs = std::filesystem;
-static const std::unordered_map<std::string, RawFactory*> gFactories = {
- { ".png", new TextureFactory() },
- { ".anim", new AnimFactory() },
- { ".aiff", new AudioFactory() },
- { ".bnk", new AudioFactory() },
- { ".bset", new AudioFactory() },
- { ".m64", new AudioFactory() },
- { ".bin", new BlobFactory(LUS::ResourceType::Blob) },
- { ".sbox", new BlobFactory(LUS::ResourceType::Blob, true) },
-};
+void Companion::Init() {
-void Companion::Start() {
- std::cout << "Super Mario 64 Rom Path: " << this->gRomPath << '\n';
+ this->RegisterFactory("AUDIO:HEADER", new AudioHeaderFactory());
+ this->RegisterFactory("SEQUENCE", new SequenceFactory());
+ this->RegisterFactory("SAMPLE", new SampleFactory());
+ this->RegisterFactory("BANK", new BankFactory());
+
+ this->RegisterFactory("TEXTURE", new TextureFactory());
+ this->RegisterFactory("BLOB", new BlobFactory());
+
+ // SM64 Specific
+
+ this->RegisterFactory("SM64:ANIM", new AnimFactory());
+ this->Process();
+}
+
+void Companion::Process() {
std::ifstream input( this->gRomPath, std::ios::binary );
this->gRomData = std::vector<uint8_t>( std::istreambuf_iterator<char>( input ), {} );
input.close();
- // TODO: Validate hash
+ N64::Cartridge cartridge = N64::Cartridge(this->gRomData);
+ cartridge.Initialize();
- std::cout << "Detected Rom Size: " << this->gRomData.size() << '\n';
+ YAML::Node config = YAML::LoadFile("config.yml");
- AudioManager::Instance = new AudioManager();
- AudioManager::Instance->initialize(this->gRomData);
-
- this->ProcessAssets();
-}
+ if(!config[cartridge.GetHash()]){
+ std::cout << "No config found for " << cartridge.GetHash() << '\n';
+ return;
+ }
-void Companion::ProcessAssets() {
- json assets = json::parse( std::ifstream( "assets.json" ) );
+ auto cfg = config[cartridge.GetHash()];
+ auto path = cfg["path"].as<std::string>();
+ auto otr = cfg["output"].as<std::string>();
- SWrapper wrapper = SWrapper("smcube.otr");
+ auto wrapper = SWrapper(otr);
- for( auto& [asset, data] : assets.items() ) {
- std::string extension = fs::path(asset).extension().string();
- if( gFactories.find(extension) == gFactories.end() ) {
- std::cout << "No factory found for " << asset << '\n';
- continue;
- }
- LUS::BinaryWriter write = LUS::BinaryWriter();
- std::string path = asset.substr(0, asset.find_last_of('.'));
- json entry = {
- { "path", path },
- { "offsets", data }
- };
- RawFactory* factory = gFactories.at(extension);
-
- if(!factory->process(&write, entry, this->gRomData)){
- std::cout << "Failed to process " << asset << '\n';
- continue;
- }
+ for (const auto & entry : fs::directory_iterator(path)){
+ std::cout << "Processing " << entry.path() << '\n';
+ YAML::Node root = YAML::LoadFile(entry.path());
+ for(auto asset = root.begin(); asset != root.end(); ++asset){
+ auto type = asset->second["type"].as<std::string>();
- bool isTexture = typeid(*factory) == typeid(TextureFactory);
+ LUS::BinaryWriter write = LUS::BinaryWriter();
+ RawFactory* factory = this->GetFactory(type);
- auto buffer = write.ToVector();
- // TODO: Change this that we all know its going to crash with other assets
- wrapper.CreateFile(isTexture ? path.substr(0, path.find_last_of('.')) : path, buffer);
+ if(!factory->process(&write, asset->second, this->gRomData)){
+ std::cout << "Failed to process " << asset->first.as<std::string>() << '\n';
+ continue;
+ }
- if(!isTexture) {
- // Write to file too
- std::string dpath = "debug/" + path;
- if(!fs::exists(fs::path(dpath).parent_path())){
- fs::create_directories(fs::path(dpath).parent_path());
+ auto buffer = write.ToVector();
+ auto output = entry.path().stem() / asset->first.as<std::string>();
+ std::cout << "Writing " << output << '\n';
+ wrapper.CreateFile(output, buffer);
+
+ if(type != "TEXTURE") {
+ std::string dpath = "debug/" + path;
+ if(!fs::exists(fs::path(dpath).parent_path())){
+ fs::create_directories(fs::path(dpath).parent_path());
+ }
+ std::ofstream stream(dpath, std::ios::binary);
+ stream.write((char*)buffer.data(), buffer.size());
+ stream.close();
}
- std::ofstream output(dpath, std::ios::binary);
- output.write((char*)buffer.data(), buffer.size());
- output.close();
- }
- std::cout << "Processed " << path << std::endl;
+ std::cout << "Processed " << path << std::endl;
- write.Close();
+ write.Close();
+ }
}
MIO0Decoder::ClearCache();
wrapper.Close();
-} \ No newline at end of file
+}
+
+void Companion::RegisterFactory(const std::string &extension, RawFactory *factory) {
+ this->gFactories[extension] = factory;
+}
+
+RawFactory *Companion::GetFactory(const std::string &extension) {
+ if(!this->gFactories.contains(extension)){
+ throw std::runtime_error("No factory found for " + extension);
+ }
+
+ return this->gFactories[extension];
+}
diff --git a/src/Companion.h b/src/Companion.h
index 28a12eb..6bf6130 100644
--- a/src/Companion.h
+++ b/src/Companion.h
@@ -1,17 +1,23 @@
#pragma once
#include <string>
+#include <utility>
#include <vector>
#include <unordered_map>
#include <filesystem>
+#include "factories/RawFactory.h"
class Companion {
public:
static Companion* Instance;
- Companion(const std::filesystem::path& rom) : gRomPath(rom) {}
- void Start();
- void ProcessAssets();
+ explicit Companion(std::filesystem::path rom) : gRomPath(std::move(rom)) {}
+ void Init();
+ void Process();
private:
std::filesystem::path gRomPath;
std::vector<uint8_t> gRomData;
+ std::unordered_map<std::string, RawFactory*> gFactories;
+
+ void RegisterFactory(const std::string& type, RawFactory* factory);
+ RawFactory* GetFactory(const std::string& type);
}; \ No newline at end of file
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
index 2316141..2bd1960 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 <nlohmann/json.hpp>
std::unordered_map<std::string, uint32_t> name_table;
AudioManager* AudioManager::Instance;
@@ -429,21 +428,22 @@ TBLFile AudioManager::parse_tbl(std::vector<uint8_t>& data, std::vector<Entry>&
return tbl;
}
-void AudioManager::initialize(std::vector<uint8_t>& buffer) {
- auto assets = nlohmann::json::parse(std::ifstream( "assets.json" ));
- auto sound_data = assets["@sound_data"]["us"];
+void AudioManager::initialize(std::vector<uint8_t>& buffer, YAML::Node& data) {
- auto sound_tbl = sound_data["sound_tbl"];
- auto sound_ctl = sound_data["sound_ctl"];
+ auto ctlOffset = data["ctl"]["offset"].as<size_t>();
+ auto ctlSize = data["ctl"]["size"].as<size_t>();
- std::vector<Entry> tbl = parse_seq_file(buffer, sound_tbl[0], false);
- std::vector<Entry> ctl = parse_seq_file(buffer, sound_ctl[0], true);
+ auto tblOffset = data["tbl"]["offset"].as<size_t>();
+ auto tblSize = data["tbl"]["size"].as<size_t>();
+
+ std::vector<Entry> tbl = parse_seq_file(buffer, tblOffset, false);
+ std::vector<Entry> ctl = parse_seq_file(buffer, ctlOffset, true);
std::cout << "Table entries: " << tbl.size() << std::endl;
std::cout << "Control entries: " << ctl.size() << std::endl;
- std::vector<uint8_t> tbl_data = PyUtils::slice(buffer, sound_tbl[0], (size_t) sound_tbl[0] + (size_t) sound_tbl[1]);
- std::vector<uint8_t> ctl_data = PyUtils::slice(buffer, sound_ctl[0], (size_t) sound_ctl[0] + (size_t) sound_ctl[1]);
+ std::vector<uint8_t> tbl_data = PyUtils::slice(buffer, tblOffset, tblOffset + tblSize);
+ std::vector<uint8_t> ctl_data = PyUtils::slice(buffer, ctlOffset, ctlOffset + ctlSize);
this->loaded_tbl = parse_tbl(tbl_data, tbl);
std::cout << "TBLs: " << this->loaded_tbl.tbls.size() << std::endl;
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
index 4b5d9ce..23aa875 100644
--- a/src/audio/AudioManager.h
+++ b/src/audio/AudioManager.h
@@ -4,6 +4,7 @@
#include <vector>
#include <string>
#include <iostream>
+#include <yaml-cpp/yaml.h>
#include "binarytools/BinaryWriter.h"
#define NONE 0xFFFF
@@ -134,7 +135,7 @@ struct Bank {
class AudioManager {
public:
static AudioManager* Instance;
- void initialize(std::vector<uint8_t>& buffer);
+ void initialize(std::vector<uint8_t>& buffer, YAML::Node& data);
void create_aifc(int32_t index, LUS::BinaryWriter& writer);
AudioBankSample get_aifc(int32_t index);
std::map<uint32_t, Bank> get_banks();
diff --git a/src/factories/AnimFactory.cpp b/src/factories/AnimFactory.cpp
index 7727220..5acd0ab 100644
--- a/src/factories/AnimFactory.cpp
+++ b/src/factories/AnimFactory.cpp
@@ -8,8 +8,11 @@
namespace fs = std::filesystem;
-void WriteAnimationHeader(LUS::BinaryWriter* writer, nlohmann::json& offsets, std::vector<uint8_t>& buffer) {
- LUS::BinaryReader reader((char*) buffer.data() + (size_t)offsets[0], offsets[1]);
+void WriteAnimationHeader(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ auto offset = data["offset"].as<uint32_t>();
+ auto size = data["size"].as<uint32_t>();
+
+ LUS::BinaryReader reader((char*) buffer.data() + offset, size);
reader.SetEndianness(LUS::Endianness::Big);
auto flags = reader.ReadInt16();
@@ -32,10 +35,13 @@ void WriteAnimationHeader(LUS::BinaryWriter* writer, nlohmann::json& offsets, st
reader.Close();
}
-void WriteAnimationIndex(LUS::BinaryWriter* writer, nlohmann::json& offsets, std::vector<uint8_t>& buffer) {
- LUS::BinaryReader reader((char*) buffer.data() + (size_t)offsets[0], offsets[1]);
+void WriteAnimationIndex(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ auto offset = data["offset"].as<uint32_t>();
+ auto size = data["size"].as<uint32_t>();
+
+ LUS::BinaryReader reader((char*) buffer.data() + offset, size);
reader.SetEndianness(LUS::Endianness::Big);
- size_t entries = ((size_t) offsets[1]);
+ size_t entries = size / sizeof(uint16_t);
WRITE_U32(entries);
for(size_t id = 0; id < entries; id++) {
WRITE_I16(reader.ReadInt16());
@@ -43,10 +49,13 @@ void WriteAnimationIndex(LUS::BinaryWriter* writer, nlohmann::json& offsets, std
reader.Close();
}
-void WriteAnimationValues(LUS::BinaryWriter* writer, nlohmann::json& offsets, std::vector<uint8_t>& buffer) {
- LUS::BinaryReader reader((char*) buffer.data() + (size_t)offsets[0], offsets[1]);
+void WriteAnimationValues(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ auto offset = data["offset"].as<uint32_t>();
+ auto size = data["size"].as<uint32_t>();
+
+ LUS::BinaryReader reader((char*) buffer.data() + offset, size);
reader.SetEndianness(LUS::Endianness::Big);
- size_t entries = ((size_t) offsets[1]);
+ size_t entries = size / sizeof(uint16_t);
WRITE_U32(entries);
for(size_t id = 0; id < entries; id++) {
WRITE_U16(reader.ReadUInt16());
@@ -54,14 +63,16 @@ void WriteAnimationValues(LUS::BinaryWriter* writer, nlohmann::json& offsets, st
reader.Close();
}
-bool AnimFactory::process(LUS::BinaryWriter* writer, nlohmann::json& data, std::vector<uint8_t>& buffer) {
- auto metadata = data["offsets"];
-
+bool AnimFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
WRITE_HEADER(LUS::ResourceType::Anim, 0);
- WriteAnimationHeader(writer, metadata["header"], buffer);
- WriteAnimationIndex( writer, metadata["indices"], buffer);
- WriteAnimationValues(writer, metadata["values"], buffer);
+ auto header = data["header"];
+ auto values = data["values"];
+ auto index = data["indices"];
+
+ WriteAnimationHeader(writer, header, buffer);
+ WriteAnimationIndex(writer, values, buffer);
+ WriteAnimationValues(writer, index, buffer);
return true;
}
diff --git a/src/factories/AnimFactory.h b/src/factories/AnimFactory.h
index 7641099..c1ca50d 100644
--- a/src/factories/AnimFactory.h
+++ b/src/factories/AnimFactory.h
@@ -5,5 +5,5 @@
class AnimFactory : public RawFactory {
public:
AnimFactory() = default;
- bool process(LUS::BinaryWriter* write, nlohmann::json& data, std::vector<uint8_t>& buffer) override;
+ bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
}; \ No newline at end of file
diff --git a/src/factories/AudioFactory.cpp b/src/factories/AudioFactory.cpp
deleted file mode 100644
index bd91a20..0000000
--- a/src/factories/AudioFactory.cpp
+++ /dev/null
@@ -1,191 +0,0 @@
-#include "AudioFactory.h"
-
-#include <vector>
-#include "audio/AudioManager.h"
-#include "audio/samples_table.h"
-#include "binarytools/BinaryReader.h"
-
-bool AudioFactory::process(LUS::BinaryWriter* writer, nlohmann::json& data, std::vector<uint8_t>& buffer) {
- auto metadata = data["offsets"];
- std::string path = data["path"];
-
- if(path.find("bank_sets") != std::string::npos){
- WRITE_HEADER(LUS::ResourceType::Blob, 0);
- char* raw = (char*) (buffer.data() + metadata[1]["us"][0]);
- WRITE_U32(metadata[0]);
- for(int i = 0; i < 0x23; i++){
- int16_t value;
- memcpy(&value, raw + (i * 2), 2);
- WRITE_I16(BSWAP16(value));
- }
- writer->Write(raw + 0x46, 0x5A);
- return true;
- }
-
- if(path.find("sound/banks") != std::string::npos){
- auto banks = AudioManager::Instance->get_banks();
- auto bankId = metadata["us"][0];
- auto bank = banks[bankId];
-
- if(bankId == 10){
- int bp = 1;
- }
-
- WRITE_HEADER(LUS::ResourceType::Bank, 0);
-
- WRITE_U32(bank.insts.size());
- for(auto &instrument : bank.insts){
- WRITE_U8(instrument.valid);
- if(!instrument.valid){
- continue;
- }
- WRITE_U8(instrument.releaseRate);
- WRITE_U8(instrument.normalRangeLo);
- WRITE_U8(instrument.normalRangeHi);
-
- auto envelope = bank.envelopes[instrument.envelope];
- if(!envelope.entries.empty()){
- WRITE_U32(envelope.entries.size());
- for(auto &entry : envelope.entries){
- writer->Write(entry.delay);
- writer->Write(entry.arg);
- }
- } else {
- WRITE_U32(0);
- }
-
- uint32_t soundFlags = 0;
- bool hasLo = instrument.soundLo.has_value();
- bool hasMed = instrument.soundMed.has_value();
- bool hasHi = instrument.soundHi.has_value();
- if(hasLo){
- soundFlags |= (1 << 0);
- }
- if(hasMed){
- soundFlags |= (1 << 1);
- }
- if(hasHi){
- soundFlags |= (1 << 2);
- }
-
- WRITE_U32(soundFlags);
- if(hasLo){
- auto value = instrument.soundLo.value();
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
- writer->Write(std::string(gSampleTable[idx]));
- writer->Write(value.tuning);
- }
- if(hasMed){
- auto value = instrument.soundMed.value();
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
- writer->Write(std::string(gSampleTable[idx]));
- writer->Write(value.tuning);
- }
- if(hasHi){
- auto value = instrument.soundHi.value();
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
- writer->Write(std::string(gSampleTable[idx]));
- writer->Write(value.tuning);
- }
-
- }
-
- WRITE_U32(bank.drums.size());
- for(auto &drum : bank.drums){
- WRITE_U8(drum.releaseRate);
- WRITE_U8(drum.pan);
- auto envelope = bank.envelopes[drum.envelope];
- if(!envelope.entries.empty()){
- std::cout << "Envelope entries: " << envelope.entries.size() << std::endl;
- WRITE_U32(envelope.entries.size());
- for(auto &entry : envelope.entries){
- writer->Write(entry.delay);
- writer->Write(entry.arg);
- }
- } else {
- WRITE_U32(0);
- }
-
- uint32_t idx = AudioManager::Instance->get_index(bank.samples[drum.sound.offset]);
- std::string out = std::string(gSampleTable[idx]);
- writer->Write(out);
- writer->Write(drum.sound.tuning);
- }
-
- return true;
- }
-
- if(path.find("sound/sequences") != std::string::npos){
-
- if(!metadata[1].contains("us")){
- return false;
- }
-
- WRITE_HEADER(LUS::ResourceType::Sequence, 0);
-
- size_t size = metadata[0];
- auto offsets = metadata[1]["us"];
-
- std::vector<uint8_t> bank = metadata[1]["banks"];
-
- WRITE_U32(bank.size());
- WRITE_ARRAY(bank.data(), bank.size());
-
- WRITE_U32(size);
- WRITE_ARRAY(buffer.data() + (size_t)offsets[0], size);
-
- return true;
- }
-
- if(path.find("sound/samples") == std::string::npos || metadata.size() < 2 || !metadata[1].contains("us")){
- return false;
- }
-
- /*
- * HINT: Uncomment this to write the aiff to a file
- LUS::BinaryWriter aifcWriter;
- AudioManager::Instance->create_aifc(metadata[1]["us"][1], aifcWriter);
- std::vector<char> aifcData = aifcWriter.ToVector();
- aifcWriter.Close();
- write_aiff(aifcData, *writer);
- */
-
- WRITE_HEADER(LUS::ResourceType::Sample, 0);
-
- AudioBankSample entry = AudioManager::Instance->get_aifc(metadata[1]["us"][1]);
-
- // Write AdpcmLoop
- WRITE_U32(entry.loop.start);
- WRITE_U32(entry.loop.end);
- WRITE_I32(entry.loop.count);
- WRITE_U32(entry.loop.pad);
-
- if(entry.loop.state.has_value()){
- std::vector<int16_t> state = entry.loop.state.value();
- WRITE_U32(state.size());
- for(auto &value : state){
- writer->Write(value);
- }
- } else {
- WRITE_U32(0);
- }
-
- // Write AdpcmBook
- WRITE_I32(entry.book.order);
- WRITE_I32(entry.book.npredictors);
-
- WRITE_U32(entry.book.table.size());
- for(auto &value : entry.book.table){
- writer->Write(value);
- }
-
- // Write sample
- WRITE_I32(entry.data.size());
- for(auto &value : entry.data){
- WRITE_U8(value);
- }
-
- writer->Write(entry.name);
-
- return true;
-} \ No newline at end of file
diff --git a/src/factories/AudioFactory.h b/src/factories/AudioFactory.h
deleted file mode 100644
index fdfdb9c..0000000
--- a/src/factories/AudioFactory.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "RawFactory.h"
-
-class AudioFactory : public RawFactory {
-public:
- AudioFactory() = default;
- bool process(LUS::BinaryWriter* write, nlohmann::json& data, std::vector<uint8_t>& buffer) override;
-}; \ No newline at end of file
diff --git a/src/factories/AudioHeaderFactory.cpp b/src/factories/AudioHeaderFactory.cpp
new file mode 100644
index 0000000..b493458
--- /dev/null
+++ b/src/factories/AudioHeaderFactory.cpp
@@ -0,0 +1,10 @@
+#include "AudioHeaderFactory.h"
+
+#include <vector>
+#include "audio/AudioManager.h"
+
+bool AudioHeaderFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ AudioManager::Instance = new AudioManager();
+ AudioManager::Instance->initialize(buffer, data);
+ return false;
+} \ No newline at end of file
diff --git a/src/factories/AudioHeaderFactory.h b/src/factories/AudioHeaderFactory.h
new file mode 100644
index 0000000..bd7336e
--- /dev/null
+++ b/src/factories/AudioHeaderFactory.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "RawFactory.h"
+
+class AudioHeaderFactory : public RawFactory {
+public:
+ AudioHeaderFactory() = default;
+ bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+}; \ No newline at end of file
diff --git a/src/factories/BankFactory.cpp b/src/factories/BankFactory.cpp
new file mode 100644
index 0000000..252fd48
--- /dev/null
+++ b/src/factories/BankFactory.cpp
@@ -0,0 +1,94 @@
+#include "BankFactory.h"
+
+#include <vector>
+#include "audio/AudioManager.h"
+#include "audio/samples_table.h"
+#include "binarytools/BinaryReader.h"
+
+bool BankFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ auto banks = AudioManager::Instance->get_banks();
+ auto bankId = data["id"].as<uint32_t>();
+ auto bank = banks[bankId];
+
+ WRITE_HEADER(LUS::ResourceType::Bank, 0);
+
+ WRITE_U32(bank.insts.size());
+ for(auto &instrument : bank.insts){
+ WRITE_U8(instrument.valid);
+ if(!instrument.valid){
+ continue;
+ }
+ WRITE_U8(instrument.releaseRate);
+ WRITE_U8(instrument.normalRangeLo);
+ WRITE_U8(instrument.normalRangeHi);
+
+ auto envelope = bank.envelopes[instrument.envelope];
+ if(!envelope.entries.empty()){
+ WRITE_U32(envelope.entries.size());
+ for(auto &entry : envelope.entries){
+ writer->Write(entry.delay);
+ writer->Write(entry.arg);
+ }
+ } else {
+ WRITE_U32(0);
+ }
+
+ uint32_t soundFlags = 0;
+ bool hasLo = instrument.soundLo.has_value();
+ bool hasMed = instrument.soundMed.has_value();
+ bool hasHi = instrument.soundHi.has_value();
+ if(hasLo){
+ soundFlags |= (1 << 0);
+ }
+ if(hasMed){
+ soundFlags |= (1 << 1);
+ }
+ if(hasHi){
+ soundFlags |= (1 << 2);
+ }
+
+ WRITE_U32(soundFlags);
+ if(hasLo){
+ auto value = instrument.soundLo.value();
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
+ writer->Write(std::string(gSampleTable[idx]));
+ writer->Write(value.tuning);
+ }
+ if(hasMed){
+ auto value = instrument.soundMed.value();
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
+ writer->Write(std::string(gSampleTable[idx]));
+ writer->Write(value.tuning);
+ }
+ if(hasHi){
+ auto value = instrument.soundHi.value();
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
+ writer->Write(std::string(gSampleTable[idx]));
+ writer->Write(value.tuning);
+ }
+
+ }
+
+ WRITE_U32(bank.drums.size());
+ for(auto &drum : bank.drums){
+ WRITE_U8(drum.releaseRate);
+ WRITE_U8(drum.pan);
+ auto envelope = bank.envelopes[drum.envelope];
+ if(!envelope.entries.empty()){
+ WRITE_U32(envelope.entries.size());
+ for(auto &entry : envelope.entries){
+ writer->Write(entry.delay);
+ writer->Write(entry.arg);
+ }
+ } else {
+ WRITE_U32(0);
+ }
+
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[drum.sound.offset]);
+ std::string out = std::string(gSampleTable[idx]);
+ writer->Write(out);
+ writer->Write(drum.sound.tuning);
+ }
+
+ return true;
+} \ No newline at end of file
diff --git a/src/factories/BankFactory.h b/src/factories/BankFactory.h
new file mode 100644
index 0000000..c19f137
--- /dev/null
+++ b/src/factories/BankFactory.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "RawFactory.h"
+
+class BankFactory : public RawFactory {
+public:
+ BankFactory() = default;
+ bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+}; \ No newline at end of file
diff --git a/src/factories/BlobFactory.cpp b/src/factories/BlobFactory.cpp
index 30714b1..e020079 100644
--- a/src/factories/BlobFactory.cpp
+++ b/src/factories/BlobFactory.cpp
@@ -1,29 +1,22 @@
#include "BlobFactory.h"
-
-#include <iostream>
-#include <filesystem>
-#include "Companion.h"
#include "utils/MIODecoder.h"
namespace fs = std::filesystem;
-bool BlobFactory::process(LUS::BinaryWriter* writer, nlohmann::json& data, std::vector<uint8_t>& buffer) {
- auto metadata = data["offsets"];
- if(!metadata[1].contains("us")){
- return false;
- }
+bool BlobFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- WRITE_HEADER(this->type, 0);
+ WRITE_HEADER(LUS::ResourceType::Blob, 0);
- size_t size = metadata[0];
- auto offsets = metadata[1]["us"];
+ auto size = data["size"].as<size_t>();
+ auto offset = data["offset"].as<size_t>();
auto* blob = new uint8_t[size];
- if(this->isMIOChunk){
- auto mio0 = MIO0Decoder::Decode(buffer, offsets[0]);
- memcpy(blob, mio0.data() + (size_t)offsets[1], size);
+ if(data["mio0"]){
+ auto decoded = MIO0Decoder::Decode(buffer, offset);
+ auto cursor = data["mio0"].as<size_t>();
+ memcpy(blob, decoded.data() + cursor, size);
} else {
- memcpy(blob, buffer.data() + (size_t)offsets[0], size);
+ memcpy(blob, buffer.data() + offset, size);
}
WRITE_U32(size); // Blob Data Size
diff --git a/src/factories/BlobFactory.h b/src/factories/BlobFactory.h
index 73cb80b..302fb01 100644
--- a/src/factories/BlobFactory.h
+++ b/src/factories/BlobFactory.h
@@ -4,10 +4,6 @@
class BlobFactory : public RawFactory {
public:
- BlobFactory(LUS::ResourceType type, bool isMIOChunk = false, bool bigEndian = false) : type(type), isMIOChunk(isMIOChunk), bigEndian(bigEndian) {}
- bool process(LUS::BinaryWriter* write, nlohmann::json& data, std::vector<uint8_t>& buffer) override;
-private:
- bool isMIOChunk = false;
- bool bigEndian = false;
- LUS::ResourceType type = LUS::ResourceType::Blob;
+ BlobFactory() = default;
+ bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
}; \ No newline at end of file
diff --git a/src/factories/RawFactory.h b/src/factories/RawFactory.h
index 8918b8b..fba32e0 100644
--- a/src/factories/RawFactory.h
+++ b/src/factories/RawFactory.h
@@ -4,7 +4,7 @@
#include <string>
#include <vector>
#include <binarytools/BinaryWriter.h>
-#include <nlohmann/json.hpp>
+#include <yaml-cpp/yaml.h>
#define WRITE_HEADER(type, version) this->WriteHeader(writer, type, version)
#define WRITE_BHEADER(type, version) this->WriteHeader(writer, type, version, true)
@@ -21,6 +21,6 @@
class RawFactory {
public:
RawFactory() = default;
- virtual bool process(LUS::BinaryWriter* write, nlohmann::json& data, std::vector<uint8_t>& buffer) = 0;
+ virtual bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) = 0;
void WriteHeader(LUS::BinaryWriter* write, LUS::ResourceType resType, int32_t version, bool bigEndian = false);
}; \ No newline at end of file
diff --git a/src/factories/SampleFactory.cpp b/src/factories/SampleFactory.cpp
new file mode 100644
index 0000000..7e2d1a1
--- /dev/null
+++ b/src/factories/SampleFactory.cpp
@@ -0,0 +1,46 @@
+#include "SampleFactory.h"
+
+#include <vector>
+#include "audio/AudioManager.h"
+
+bool SampleFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ WRITE_HEADER(LUS::ResourceType::Sample, 0);
+
+ auto id = data["id"].as<int32_t>();
+ AudioBankSample entry = AudioManager::Instance->get_aifc(id);
+
+ // Write AdpcmLoop
+ WRITE_U32(entry.loop.start);
+ WRITE_U32(entry.loop.end);
+ WRITE_I32(entry.loop.count);
+ WRITE_U32(entry.loop.pad);
+
+ if(entry.loop.state.has_value()){
+ std::vector<int16_t> state = entry.loop.state.value();
+ WRITE_U32(state.size());
+ for(auto &value : state){
+ writer->Write(value);
+ }
+ } else {
+ WRITE_U32(0);
+ }
+
+ // Write AdpcmBook
+ WRITE_I32(entry.book.order);
+ WRITE_I32(entry.book.npredictors);
+
+ WRITE_U32(entry.book.table.size());
+ for(auto &value : entry.book.table){
+ writer->Write(value);
+ }
+
+ // Write sample
+ WRITE_I32(entry.data.size());
+ for(auto &value : entry.data){
+ WRITE_U8(value);
+ }
+
+ writer->Write(entry.name);
+
+ return true;
+} \ No newline at end of file
diff --git a/src/factories/SampleFactory.h b/src/factories/SampleFactory.h
new file mode 100644
index 0000000..c0ad4ef
--- /dev/null
+++ b/src/factories/SampleFactory.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "RawFactory.h"
+
+class SampleFactory : public RawFactory {
+public:
+ SampleFactory() = default;
+ bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+}; \ No newline at end of file
diff --git a/src/factories/SequenceFactory.cpp b/src/factories/SequenceFactory.cpp
new file mode 100644
index 0000000..5e3151b
--- /dev/null
+++ b/src/factories/SequenceFactory.cpp
@@ -0,0 +1,21 @@
+#include "SequenceFactory.h"
+
+#include "audio/AudioManager.h"
+#include <vector>
+
+bool SequenceFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
+ WRITE_HEADER(LUS::ResourceType::Sequence, 0);
+
+ auto size = data["size"].as<size_t>();
+ auto offset = data["offset"].as<size_t>();
+
+ auto bank = data["banks"].as<std::vector<uint8_t>>();
+
+ WRITE_U32(bank.size());
+ WRITE_ARRAY(bank.data(), bank.size());
+
+ WRITE_U32(size);
+ WRITE_ARRAY(buffer.data() + offset, size);
+
+ return true;
+} \ No newline at end of file
diff --git a/src/factories/SequenceFactory.h b/src/factories/SequenceFactory.h
new file mode 100644
index 0000000..93e9b3e
--- /dev/null
+++ b/src/factories/SequenceFactory.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "RawFactory.h"
+
+class SequenceFactory : public RawFactory {
+public:
+ SequenceFactory() = default;
+ bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
+}; \ No newline at end of file
diff --git a/src/factories/TextureFactory.cpp b/src/factories/TextureFactory.cpp
index 4c37fd5..12d8540 100644
--- a/src/factories/TextureFactory.cpp
+++ b/src/factories/TextureFactory.cpp
@@ -1,77 +1,48 @@
#include "TextureFactory.h"
-#include <iostream>
-#include <filesystem>
#include "Companion.h"
#include "utils/MIODecoder.h"
namespace fs = std::filesystem;
-enum class TextureType {
- Error,
- RGBA32bpp,
- RGBA16bpp,
- Palette4bpp,
- Palette8bpp,
- Grayscale4bpp,
- Grayscale8bpp,
- GrayscaleAlpha4bpp,
- GrayscaleAlpha8bpp,
- GrayscaleAlpha16bpp,
-};
-
static const std::unordered_map <std::string, TextureType> gTextureTypes = {
- { ".rgba16", TextureType::RGBA16bpp },
- { ".rgba32", TextureType::RGBA32bpp },
- { ".ia1", TextureType::GrayscaleAlpha4bpp },
- { ".ia4", TextureType::GrayscaleAlpha4bpp },
- { ".ia8", TextureType::GrayscaleAlpha8bpp },
- { ".ia16", TextureType::GrayscaleAlpha16bpp },
+ { "RGBA16", TextureType::RGBA16bpp },
+ { "RGBA32", TextureType::RGBA32bpp },
+ { "IA1", TextureType::GrayscaleAlpha4bpp },
+ { "IA4", TextureType::GrayscaleAlpha4bpp },
+ { "IA8", TextureType::GrayscaleAlpha8bpp },
+ { "IA16", TextureType::GrayscaleAlpha16bpp },
};
-bool TextureFactory::process(LUS::BinaryWriter* writer, nlohmann::json& data, std::vector<uint8_t>& buffer) {
- std::string path = data["path"];
- std::string ext = fs::path(path).extension().string();
+bool TextureFactory::process(LUS::BinaryWriter* writer, YAML::Node& data, std::vector<uint8_t>& buffer) {
- bool isTileTexture = path.find("cake") != std::string::npos || path.find("skyboxes") != std::string::npos;
+ auto format = data["format"].as<std::string>();
+ auto width = data["width"].as<uint32_t>();
+ auto height = data["height"].as<uint32_t>();
+ auto size = data["size"].as<size_t>();
+ auto offset = data["offset"].as<size_t>();
- if(isTileTexture) {
+ if(!gTextureTypes.contains(format)) {
return false;
}
- if(!gTextureTypes.contains(ext)) {
- return false;
- }
-
- auto metadata = data["offsets"];
- if(!metadata[3].contains("us")){
- return false;
- }
-
- // Path: [Width, Height, Size, { Country : [Rom Offset, MIO0 Size] }],
-
- TextureType type = isTileTexture ? TextureType::RGBA32bpp : gTextureTypes.at(ext);
+ TextureType type = gTextureTypes.at(format);
WRITE_HEADER(LUS::ResourceType::Texture, 0);
- WRITE_U32(type); // Texture Type
- WRITE_U32(metadata[0]); // Width
- WRITE_U32(metadata[1]); // Height
- size_t size = metadata[2];
- auto offsets = metadata[3]["us"];
+ WRITE_U32(type);
+ WRITE_U32(width);
+ WRITE_U32(height);
- auto* texture = new uint8_t[size];
-
- if(offsets.size() > 1){
- auto mio0 = MIO0Decoder::Decode(buffer, offsets[0]);
- memcpy(texture, mio0.data() + (size_t)offsets[1], size);
+ if(data["mio0"]){
+ auto mio0 = data["mio0"].as<size_t>();
+ auto decoded = MIO0Decoder::Decode(buffer, offset);
+ WRITE_U32(size);
+ WRITE_ARRAY(decoded.data() + mio0, size);
} else {
- memcpy(texture, buffer.data() + (size_t)offsets[0], size);
+ WRITE_U32(size);
+ WRITE_ARRAY(buffer.data() + offset, size);
}
- WRITE_U32(size); // Texture Data Size
- WRITE_ARRAY(texture, size); // Texture Data
-
- delete[] texture;
return true;
}
diff --git a/src/factories/TextureFactory.h b/src/factories/TextureFactory.h
index 88ebbdf..c0349d6 100644
--- a/src/factories/TextureFactory.h
+++ b/src/factories/TextureFactory.h
@@ -2,8 +2,21 @@
#include "RawFactory.h"
+enum class TextureType {
+ Error,
+ RGBA32bpp,
+ RGBA16bpp,
+ Palette4bpp,
+ Palette8bpp,
+ Grayscale4bpp,
+ Grayscale8bpp,
+ GrayscaleAlpha4bpp,
+ GrayscaleAlpha8bpp,
+ GrayscaleAlpha16bpp,
+};
+
class TextureFactory : public RawFactory {
public:
TextureFactory() = default;
- bool process(LUS::BinaryWriter* write, nlohmann::json& data, std::vector<uint8_t>& buffer) override;
+ bool process(LUS::BinaryWriter* write, YAML::Node& data, std::vector<uint8_t>& buffer) override;
}; \ No newline at end of file
diff --git a/src/main.cpp b/src/main.cpp
index ad50334..ab1f8d3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -17,6 +17,6 @@ int main(int argc, char *argv[]) {
}
Companion::Instance = new Companion(filename);
- Companion::Instance->Start();
+ Companion::Instance->Init();
return 0;
} \ No newline at end of file
diff --git a/src/n64/Cartridge.cpp b/src/n64/Cartridge.cpp
new file mode 100644
index 0000000..96e150c
--- /dev/null
+++ b/src/n64/Cartridge.cpp
@@ -0,0 +1,59 @@
+#include "Cartridge.h"
+
+#include "hj/sha1.h"
+#include "binarytools/BinaryReader.h"
+
+void N64::Cartridge::Initialize() {
+ LUS::BinaryReader reader((char*) this->gRomData.data(), this->gRomData.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+ reader.Seek(0x20, LUS::SeekOffsetType::Start);
+ this->gGameTitle = std::string(reader.ReadCString());
+ reader.Seek(0x3E, LUS::SeekOffsetType::Start);
+ uint8_t country = reader.ReadUByte();
+ this->gVersion = reader.ReadUByte();
+ this->gHash = Chocobo1::SHA1().addData(this->gRomData).finalize().toString();
+ switch (country) {
+ case 'J':
+ this->gCountryCode = CountryCode::Japan;
+ break;
+ case 'E':
+ this->gCountryCode = CountryCode::NorthAmerica;
+ break;
+ case 'P':
+ this->gCountryCode = CountryCode::Europe;
+ break;
+ default:
+ this->gCountryCode = CountryCode::Unknown;
+ break;
+ }
+ reader.Close();
+}
+
+const std::string &N64::Cartridge::GetGameTitle() {
+ return this->gGameTitle;
+}
+
+N64::CountryCode N64::Cartridge::GetCountry() {
+ return this->gCountryCode;
+}
+
+uint8_t N64::Cartridge::GetVersion() const {
+ return this->gVersion;
+}
+
+std::string N64::Cartridge::GetHash() {
+ return this->gHash;
+}
+
+std::string N64::Cartridge::GetCountryCode() {
+ switch (this->gCountryCode) {
+ case CountryCode::Japan:
+ return "jp";
+ case CountryCode::NorthAmerica:
+ return "us";
+ case CountryCode::Europe:
+ return "eu";
+ default:
+ return "unk";
+ }
+}
diff --git a/src/n64/Cartridge.h b/src/n64/Cartridge.h
new file mode 100644
index 0000000..e53b8ef
--- /dev/null
+++ b/src/n64/Cartridge.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <vector>
+#include <string>
+
+namespace N64 {
+enum class CountryCode {
+ Japan,
+ NorthAmerica,
+ Europe,
+ Unknown
+};
+
+class Cartridge {
+public:
+ explicit Cartridge(const std::vector<uint8_t>& romData) : gRomData(romData), gCountryCode(CountryCode::Unknown), gVersion(0), gGameTitle("Unknown") {}
+ void Initialize();
+ const std::string& GetGameTitle();
+ std::string GetCountryCode();
+ CountryCode GetCountry();
+ uint8_t GetVersion() const;
+ std::string GetHash();
+private:
+ std::vector<uint8_t> gRomData;
+ CountryCode gCountryCode;
+ uint8_t gVersion;
+ std::string gGameTitle;
+ std::string gHash;
+};
+} \ No newline at end of file