mirror of
https://github.com/izzy2lost/Torch.git
synced 2026-07-06 00:18:35 -07:00
Added sf64 compressed audio support, cleaned code and implemented audio drivers switch
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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; }
|
||||
};
|
||||
};
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user