Skip to content

Commit

Permalink
Recreated audio export system to something more generic
Browse files Browse the repository at this point in the history
  • Loading branch information
KiritoDv committed Nov 19, 2024
1 parent 4451ae2 commit b253276
Show file tree
Hide file tree
Showing 33 changed files with 1,144 additions and 12 deletions.
42 changes: 34 additions & 8 deletions src/Companion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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>());
Expand Down Expand Up @@ -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();
}

Expand Down Expand Up @@ -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;

Expand Down
4 changes: 3 additions & 1 deletion src/factories/BaseFactory.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,7 @@ class BaseFactory {
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 {};
}
};
16 changes: 13 additions & 3 deletions src/factories/ResourceType.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
78 changes: 78 additions & 0 deletions src/factories/naudio/v1/AudioContext.cpp
Original file line number Diff line number Diff line change
@@ -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");
}
}
35 changes: 35 additions & 0 deletions src/factories/naudio/v1/AudioContext.h
Original file line number Diff line number Diff line change
@@ -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)
};
}
};
131 changes: 131 additions & 0 deletions src/factories/naudio/v1/AudioTableFactory.cpp
Original file line number Diff line number Diff line change
@@ -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;
}
Loading

0 comments on commit b253276

Please sign in to comment.