summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKiritoDv <kiritodev01@gmail.com>2026-05-11 15:16:08 -0600
committerKiritoDv <kiritodev01@gmail.com>2026-05-11 15:16:08 -0600
commit9b3eef94e58065273d17a802ac26e13ffa49a19f (patch)
treec1666df292519c2146bcca9a5ae7298ea5105af8 /src
parent86a69ba5547df01550616f22d599d20b00bea17c (diff)
Trying to get rid of duplicated audio on sf64
Diffstat (limited to 'src')
-rw-r--r--src/factories/naudio/v1/AudioContext.cpp10
-rw-r--r--src/factories/naudio/v1/AudioContext.h9
-rw-r--r--src/factories/naudio/v1/SampleFactory.cpp24
3 files changed, 41 insertions, 2 deletions
diff --git a/src/factories/naudio/v1/AudioContext.cpp b/src/factories/naudio/v1/AudioContext.cpp
index 82d034a..45beef5 100644
--- a/src/factories/naudio/v1/AudioContext.cpp
+++ b/src/factories/naudio/v1/AudioContext.cpp
@@ -4,6 +4,8 @@
std::unordered_map<AudioTableType, TableEntry> AudioContext::tables;
NAudioDrivers AudioContext::driver = NAudioDrivers::UNKNOWN;
+std::unordered_map<uint64_t, std::string> AudioContext::sampleDedup;
+std::unordered_map<uint32_t, std::string> AudioContext::sampleAddrRemap;
std::optional<std::shared_ptr<IParsedData>> AudioContextFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
auto driver = GetSafeNode<std::string>(node, "driver");
@@ -83,6 +85,14 @@ uint64_t AudioContext::GetPathByAddr(uint32_t addr) {
return 0;
}
+ // If this ROM address belongs to a duplicate SampleData struct, return the
+ // canonical's hash so instruments/drums reference the canonical entry directly.
+ auto remapIt = sampleAddrRemap.find(addr);
+ if (remapIt != sampleAddrRemap.end()) {
+ SPDLOG_INFO("Remapping duplicate 0x{:X} to canonical {}", addr, remapIt->second);
+ return CRC64(remapIt->second.c_str());
+ }
+
auto dec = Companion::Instance->GetNodeByAddr(addr);
if (dec.has_value()) {
std::string path = std::get<0>(dec.value());
diff --git a/src/factories/naudio/v1/AudioContext.h b/src/factories/naudio/v1/AudioContext.h
index 415d1f1..05e5516 100644
--- a/src/factories/naudio/v1/AudioContext.h
+++ b/src/factories/naudio/v1/AudioContext.h
@@ -3,6 +3,8 @@
#include "AudioTableFactory.h"
#include "factories/naudio/v0/AudioHeaderFactory.h"
#include "factories/BaseFactory.h"
+#include <unordered_map>
+#include <string>
struct TunedSample {
uint32_t sample;
@@ -25,6 +27,13 @@ class AudioContext {
public:
static std::unordered_map<AudioTableType, TableEntry> tables;
static NAudioDrivers driver;
+ // Key: (sampleBankId << 32) | sampleAddr → canonical archive path.
+ // Populated during parse so all dedup decisions are made before any export runs.
+ static std::unordered_map<uint64_t, std::string> sampleDedup;
+ // Key: ROM offset of a duplicate SampleData struct → canonical archive path.
+ // Used by GetPathByAddr() so instrument/drum export writes the canonical hash
+ // instead of the duplicate's hash, making redirect entries permanently unreferenced.
+ static std::unordered_map<uint32_t, std::string> sampleAddrRemap;
static LUS::BinaryReader MakeReader(AudioTableType type, uint32_t offset);
static TunedSample LoadTunedSample(LUS::BinaryReader& reader, uint32_t parent, uint32_t sampleBankId);
diff --git a/src/factories/naudio/v1/SampleFactory.cpp b/src/factories/naudio/v1/SampleFactory.cpp
index 2faafe2..4616d3f 100644
--- a/src/factories/naudio/v1/SampleFactory.cpp
+++ b/src/factories/naudio/v1/SampleFactory.cpp
@@ -28,9 +28,10 @@ ExportResult NSampleCodeExporter::Export(std::ostream& write, std::shared_ptr<IP
ExportResult NSampleBinaryExporter::Export(std::ostream& write, std::shared_ptr<IParsedData> raw,
std::string& entryName, YAML::Node& node, std::string* replacement) {
- auto writer = LUS::BinaryWriter();
+ // parse() returns nullopt for duplicates, so Export() is only reached for
+ // canonical samples — no redirect check needed here.
auto data = std::static_pointer_cast<NSampleData>(raw);
-
+ auto writer = LUS::BinaryWriter();
WriteHeader(writer, Torch::ResourceType::Sample, 1);
writer.Write((uint8_t)data->codec);
writer.Write((uint8_t)data->medium);
@@ -190,5 +191,24 @@ std::optional<std::shared_ptr<IParsedData>> NSampleFactory::parse(std::vector<ui
sample->sampleBankId = sampleBankId;
sample->sampleRate = sampleRate;
+ // Build dedup maps at parse time so GetPathByAddr() has full information
+ // before any instrument/drum export runs.
+ if (addr != 0) {
+ uint64_t key = ((uint64_t)sampleBankId << 32) | (uint64_t)addr;
+ auto it = AudioContext::sampleDedup.find(key);
+ if (it == AudioContext::sampleDedup.end()) {
+ // First time we see this audio data: this struct is the canonical.
+ auto pathDec = Companion::Instance->GetNodeByAddr(offset);
+ if (pathDec.has_value()) {
+ AudioContext::sampleDedup[key] = std::get<0>(pathDec.value());
+ }
+ } else {
+ // Duplicate: map this ROM offset → canonical path for GetPathByAddr(),
+ // then return nullopt so the Companion produces no archive entry for it.
+ AudioContext::sampleAddrRemap[offset] = it->second;
+ return std::nullopt;
+ }
+ }
+
return sample;
}