Added sf64 compressed audio support, cleaned code and implemented audio drivers switch

This commit is contained in:
KiritoDv
2025-01-31 11:45:43 -06:00
parent 7b83e15d80
commit 7ae083a3a1
12 changed files with 588 additions and 51 deletions
+1 -2
View File
@@ -216,8 +216,8 @@ s32 readaifccodebook(LUS::BinaryReader& fhandle, s32 ****table, s16 *order, s16
}
ALADPCMloop *readlooppoints(LUS::BinaryReader& reader, s16 *nloops) {
BSWAP16(*nloops);
checked_fread(nloops, sizeof(s16), 1, reader);
BSWAP16(*nloops);
auto *al = static_cast<ALADPCMloop *>(malloc(*nloops * sizeof(ALADPCMloop)));
for (s32 i = 0; i < *nloops; i++) {
checked_fread(&al[i], sizeof(ALADPCMloop), 1, reader);
@@ -505,7 +505,6 @@ void write_aiff(std::vector<char> data, LUS::BinaryWriter& writer) {
fail_parse("Unknown loop chunk version");
}
aloops = readlooppoints(reader, &nloops);
BSWAP16(nloops);
if (nloops != 1) {
fail_parse("Only a single loop supported");
}
+19 -11
View File
@@ -3,12 +3,20 @@
#include "Companion.h"
#include "utils/StringHelper.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, std::shared_ptr<AudioTableData>> AudioContext::tableData;
std::unordered_map<AudioTableType, uint32_t> AudioContext::tableOffsets;
std::unordered_map<AudioTableType, TableEntry> AudioContext::tables;
NAudioDrivers AudioContext::driver = NAudioDrivers::UNKNOWN;
std::optional<std::shared_ptr<IParsedData>> AudioContextFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
auto driver = GetSafeNode<std::string>(node, "driver");
if(driver == "SF64") {
AudioContext::driver = NAudioDrivers::SF64;
} else if(driver == "FZEROX"){
AudioContext::driver = NAudioDrivers::FZEROX;
} else {
throw std::runtime_error("Unknown NAudio driver");
}
auto seq = GetSafeNode<YAML::Node>(node, "audio_seq");
auto seqSize = GetSafeNode<uint32_t>(seq, "size");
auto seqOffset = GetSafeNode<uint32_t>(seq, "offset");
@@ -21,13 +29,13 @@ std::optional<std::shared_ptr<IParsedData>> AudioContextFactory::parse(std::vect
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);
AudioContext::tables[AudioTableType::SEQ_TABLE].buffer = std::vector<uint8_t>(buffer.begin() + seqOffset, buffer.begin() + seqOffset + seqSize);
AudioContext::tables[AudioTableType::FONT_TABLE].buffer = std::vector<uint8_t>(buffer.begin() + bankOffset, buffer.begin() + bankOffset + bankSize);
AudioContext::tables[AudioTableType::SAMPLE_TABLE].buffer = std::vector<uint8_t>(buffer.begin() + tableOffset, buffer.begin() + tableOffset + tableSize);
AudioContext::tableOffsets[AudioTableType::SEQ_TABLE] = seqOffset;
AudioContext::tableOffsets[AudioTableType::FONT_TABLE] = bankOffset;
AudioContext::tableOffsets[AudioTableType::SAMPLE_TABLE] = tableOffset;
AudioContext::tables[AudioTableType::SEQ_TABLE].offset = seqOffset;
AudioContext::tables[AudioTableType::FONT_TABLE].offset = bankOffset;
AudioContext::tables[AudioTableType::SAMPLE_TABLE].offset = tableOffset;
SPDLOG_INFO("Sequence Table 0x{:X}", seqOffset);
SPDLOG_INFO("Sound Font Table 0x{:X}", bankOffset);
@@ -37,7 +45,7 @@ std::optional<std::shared_ptr<IParsedData>> AudioContextFactory::parse(std::vect
}
LUS::BinaryReader AudioContext::MakeReader(AudioTableType type, uint32_t offset) {
auto entry = AudioContext::data[type];
auto entry = AudioContext::tables[type].buffer;
LUS::BinaryReader reader(entry.data(), entry.size());
reader.SetEndianness(Torch::Endianness::Big);
+14 -5
View File
@@ -10,12 +10,21 @@ struct TunedSample {
float tuning;
};
struct TableEntry {
std::shared_ptr<AudioTableData> info;
std::unordered_map<uint32_t, AudioTableEntry> entries;
std::vector<uint8_t> buffer;
uint32_t offset;
};
enum class NAudioDrivers {
SF64, FZEROX, UNKNOWN
};
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 std::unordered_map<AudioTableType, uint32_t> tableOffsets;
static std::unordered_map<AudioTableType, TableEntry> tables;
static NAudioDrivers driver;
static LUS::BinaryReader MakeReader(AudioTableType type, uint32_t offset);
static TunedSample LoadTunedSample(LUS::BinaryReader& reader, uint32_t parent, uint32_t sampleBankId);
@@ -39,4 +48,4 @@ public:
}
bool HasModdedDependencies() override { return true; }
};
};
+2 -3
View File
@@ -168,9 +168,8 @@ void AudioConverter::SampleV0ToAIFC(AudioBankSample* sample, LUS::BinaryWriter &
void AudioConverter::SampleV1ToAIFC(NSampleData* sample, LUS::BinaryWriter &out) {
auto loop = std::static_pointer_cast<ADPCMLoopData>(Companion::Instance->GetParseDataByAddr(sample->loop)->data.value());
auto book = std::static_pointer_cast<ADPCMBookData>(Companion::Instance->GetParseDataByAddr(sample->book)->data.value());
auto entry = AudioContext::tableData[AudioTableType::SAMPLE_TABLE]->entries[sample->sampleBankId];
auto buffer = AudioContext::data[AudioTableType::SAMPLE_TABLE];
auto sampleData = buffer.data() + entry.addr + sample->sampleAddr;
auto entry = AudioContext::tables[AudioTableType::SAMPLE_TABLE];
auto sampleData = entry.buffer.data() + entry.info->entries[sample->sampleBankId].addr + sample->sampleAddr;
auto aifc = AIFCWriter();
std::vector<uint8_t> data(sampleData, sampleData + sample->size);
@@ -82,7 +82,7 @@ ExportResult AudioTableBinaryExporter::Export(std::ostream &write, std::shared_p
throw std::runtime_error("Fuck this thing");
}
if(entry.size == 0){
auto item = AudioContext::tableData[AudioTableType::SEQ_TABLE]->entries[entry.addr];
auto item = AudioContext::tables[AudioTableType::SEQ_TABLE].entries[entry.addr];
writer.Write(item.crc);
} else {
writer.Write(entry.crc);
@@ -136,7 +136,7 @@ std::optional<std::shared_ptr<IParsedData>> AudioTableFactory::parse(std::vector
uint64_t crc = 0;
auto entry = AudioTableEntry { addr, size, medium, policy, sd1, sd2, sd3, crc };
AudioContext::tables[type][addr] = entry;
AudioContext::tables[type].entries[addr] = entry;
switch (type) {
case AudioTableType::FONT_TABLE: {
@@ -156,14 +156,14 @@ std::optional<std::shared_ptr<IParsedData>> AudioTableFactory::parse(std::vector
break;
}
case AudioTableType::SEQ_TABLE: {
auto parent = AudioContext::tableOffsets[AudioTableType::SEQ_TABLE];
auto parent = AudioContext::tables[AudioTableType::SEQ_TABLE].offset;
if(size != 0){
YAML::Node seq;
seq["type"] = "BLOB";
seq["offset"] = parent + addr;
seq["size"] = size;
Companion::Instance->AddAsset(seq);
std::string path = seq["vpath"].as<std::string>();
auto path = seq["vpath"].as<std::string>();
crc = CRC64(path.c_str());
break;
}
@@ -171,11 +171,11 @@ std::optional<std::shared_ptr<IParsedData>> AudioTableFactory::parse(std::vector
}
entry.crc = crc;
AudioContext::tables[type][addr].crc = crc;
AudioContext::tables[type].entries[addr].crc = crc;
entries.push_back(entry);
}
auto table = std::make_shared<AudioTableData>(bmedium, offset, type, entries);
AudioContext::tableData[type] = table;
AudioContext::tables[type].info = table;
return table;
}
+1 -1
View File
@@ -40,7 +40,7 @@ std::optional<std::shared_ptr<IParsedData>> DrumFactory::parse(std::vector<uint8
auto parent = GetSafeNode<uint32_t>(node, "parent");
auto sampleBankId = GetSafeNode<uint32_t>(node, "sampleBankId");
auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(parent);
auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].entries[parent];
auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset);
@@ -47,7 +47,7 @@ std::optional<std::shared_ptr<IParsedData>> InstrumentFactory::parse(std::vector
auto parent = GetSafeNode<uint32_t>(node, "parent");
auto sampleBankId = GetSafeNode<uint32_t>(node, "sampleBankId");
auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(parent);
auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].entries[parent];
auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset);
+33 -17
View File
@@ -4,6 +4,7 @@
#include <tinyxml2.h>
#include "LoopFactory.h"
#include "BookFactory.h"
#include <factories/sf64/audio/AudioDecompressor.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) {
@@ -36,10 +37,8 @@ ExportResult NSampleBinaryExporter::Export(std::ostream &write, std::shared_ptr<
writer.Write(AudioContext::GetPathByAddr(data->loop));
writer.Write(AudioContext::GetPathByAddr(data->book));
auto entry = AudioContext::tableData[AudioTableType::SAMPLE_TABLE]->entries[data->sampleBankId];
auto buffer = AudioContext::data[AudioTableType::SAMPLE_TABLE];
writer.Write((char*) buffer.data() + entry.addr + data->sampleAddr, data->size);
auto table = AudioContext::tables[AudioTableType::SAMPLE_TABLE];
writer.Write((char*) table.buffer.data() + table.info->entries[data->sampleBankId].addr + data->sampleAddr, data->size);
writer.Finish(write);
return std::nullopt;
@@ -48,16 +47,34 @@ ExportResult NSampleBinaryExporter::Export(std::ostream &write, std::shared_ptr<
ExportResult NSampleModdingExporter::Export(std::ostream &write, std::shared_ptr<IParsedData> raw, std::string& entryName, YAML::Node &node, std::string* replacement ) {
auto aiff = LUS::BinaryWriter();
auto data = std::static_pointer_cast<NSampleData>(raw);
*replacement += ".aiff";
auto aifc = LUS::BinaryWriter();
AudioConverter::SampleV1ToAIFC(data.get(), aifc);
auto cnv = aifc.ToVector();
#ifdef SF64_SUPPORT
if(AudioContext::driver == NAudioDrivers::SF64 && data->codec == 2) {
*replacement += ".pcm";
auto table = AudioContext::tables[AudioTableType::SAMPLE_TABLE];
auto ptr = table.buffer.data() + table.info->entries[data->sampleBankId].addr + data->sampleAddr;
auto vec = std::vector<uint8_t>(ptr, ptr + data->size);
auto output = new int16_t[data->size * 2];
SF64::DecompressAudio(vec, output);
auto writer = LUS::BinaryWriter();
writer.Write((char*) output, data->size);
writer.Finish(write);
} else {
#endif
*replacement += ".aiff";
auto aifc = LUS::BinaryWriter();
AudioConverter::SampleV1ToAIFC(data.get(), aifc);
auto cnv = aifc.ToVector();
if(!cnv.empty()){
write_aiff(cnv, aiff);
aiff.Finish(write);
if(!cnv.empty()){
write_aiff(cnv, aiff);
aiff.Finish(write);
}
#ifdef SF64_SUPPORT
}
#endif
return std::nullopt;
}
@@ -114,9 +131,8 @@ ExportResult NSampleXMLExporter::Export(std::ostream &write, std::shared_ptr<IPa
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;
auto table = AudioContext::tables[AudioTableType::SAMPLE_TABLE];
auto sampleData = table.buffer.data() + table.info->entries[entry->sampleBankId].addr + entry->sampleAddr;
std::vector<char> data(sampleData, sampleData + entry->size);
Companion::Instance->RegisterCompanionFile(path.filename().string(), data);
@@ -130,7 +146,7 @@ std::optional<std::shared_ptr<IParsedData>> NSampleFactory::parse(std::vector<ui
auto sampleRate = GetSafeNode<uint32_t>(node, "sampleRate", 0);
auto sampleBankId = GetSafeNode<uint32_t>(node, "sampleBankId");
auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(parent);
auto table = AudioContext::tables[AudioTableType::FONT_TABLE].entries[parent];
auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, offset);
auto sample = std::make_shared<NSampleData>();
@@ -147,7 +163,7 @@ std::optional<std::shared_ptr<IParsedData>> NSampleFactory::parse(std::vector<ui
auto bookAddr = reader.ReadUInt32();
if(loopAddr != 0){
loopAddr += entry.addr;
loopAddr += table.addr;
YAML::Node loop;
loop["type"] = "NAUDIO:V1:ADPCM_LOOP";
loop["offset"] = loopAddr;
@@ -155,7 +171,7 @@ std::optional<std::shared_ptr<IParsedData>> NSampleFactory::parse(std::vector<ui
}
if(bookAddr != 0){
bookAddr += entry.addr;
bookAddr += table.addr;
YAML::Node book;
book["type"] = "NAUDIO:V1:ADPCM_BOOK";
book["offset"] = bookAddr;
+2 -4
View File
@@ -58,8 +58,6 @@ ExportResult NSequenceBinaryExporter::Export(std::ostream &write, std::shared_pt
std::optional<std::shared_ptr<IParsedData>> NSequenceFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
auto offset = GetSafeNode<uint32_t>(node, "offset");
auto entry = AudioContext::tables[AudioTableType::SEQ_TABLE].at(offset);
auto data = AudioContext::data[AudioTableType::SEQ_TABLE];
return std::make_shared<RawBuffer>((uint8_t*) data.data() + entry.addr, entry.size);
auto entry = AudioContext::tables[AudioTableType::SEQ_TABLE];
return std::make_shared<RawBuffer>((uint8_t*) entry.buffer.data() + entry.entries[offset].addr, entry.entries[offset].size);
}
+1 -1
View File
@@ -182,7 +182,7 @@ ExportResult SoundFontXMLExporter::Export(std::ostream &write, std::shared_ptr<I
std::optional<std::shared_ptr<IParsedData>> SoundFontFactory::parse(std::vector<uint8_t>& buffer, YAML::Node& node) {
auto offset = GetSafeNode<uint32_t>(node, "offset");
auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].at(offset);
auto entry = AudioContext::tables[AudioTableType::FONT_TABLE].entries[offset];
auto reader = AudioContext::MakeReader(AudioTableType::FONT_TABLE, entry.addr);
auto font = std::make_shared<SoundFontData>();
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
#pragma once
#include <cstdint>
#include <vector>
namespace SF64 {
void DecompressAudio(std::vector<uint8_t> data, int16_t* output);
}