summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKiritoDv <kiritodev01@gmail.com>2025-01-31 11:45:43 -0600
committerKiritoDv <kiritodev01@gmail.com>2025-01-31 11:45:43 -0600
commit7ae083a3a16000afe435caacf9d3588f1de37873 (patch)
treee8b70fadb319a6b2ef7eb2ccdaadb58664e35a81 /src
parent7b83e15d8068c6fc18b52c90b0cbc425b5abd63f (diff)
Added sf64 compressed audio support, cleaned code and implemented audio drivers switch
Diffstat (limited to 'src')
-rw-r--r--src/factories/naudio/v0/AIFCDecode.cpp3
-rw-r--r--src/factories/naudio/v1/AudioContext.cpp30
-rw-r--r--src/factories/naudio/v1/AudioContext.h19
-rw-r--r--src/factories/naudio/v1/AudioConverter.cpp5
-rw-r--r--src/factories/naudio/v1/AudioTableFactory.cpp12
-rw-r--r--src/factories/naudio/v1/DrumFactory.cpp2
-rw-r--r--src/factories/naudio/v1/InstrumentFactory.cpp2
-rw-r--r--src/factories/naudio/v1/SampleFactory.cpp52
-rw-r--r--src/factories/naudio/v1/SequenceFactory.cpp6
-rw-r--r--src/factories/naudio/v1/SoundFontFactory.cpp2
-rw-r--r--src/factories/sf64/audio/AudioDecompressor.cpp500
-rw-r--r--src/factories/sf64/audio/AudioDecompressor.h8
12 files changed, 589 insertions, 52 deletions
diff --git a/src/factories/naudio/v0/AIFCDecode.cpp b/src/factories/naudio/v0/AIFCDecode.cpp
index cddf398..d487242 100644
--- a/src/factories/naudio/v0/AIFCDecode.cpp
+++ b/src/factories/naudio/v0/AIFCDecode.cpp
@@ -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");
}
diff --git a/src/factories/naudio/v1/AudioContext.cpp b/src/factories/naudio/v1/AudioContext.cpp
index 596ffeb..f2b0dd0 100644
--- a/src/factories/naudio/v1/AudioContext.cpp
+++ b/src/factories/naudio/v1/AudioContext.cpp
@@ -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);
diff --git a/src/factories/naudio/v1/AudioContext.h b/src/factories/naudio/v1/AudioContext.h
index a965f10..415d1f1 100644
--- a/src/factories/naudio/v1/AudioContext.h
+++ b/src/factories/naudio/v1/AudioContext.h
@@ -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; }
-};
+}; \ No newline at end of file
diff --git a/src/factories/naudio/v1/AudioConverter.cpp b/src/factories/naudio/v1/AudioConverter.cpp
index 62d1470..e3fbf5d 100644
--- a/src/factories/naudio/v1/AudioConverter.cpp
+++ b/src/factories/naudio/v1/AudioConverter.cpp
@@ -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);
diff --git a/src/factories/naudio/v1/AudioTableFactory.cpp b/src/factories/naudio/v1/AudioTableFactory.cpp
index 1a9b367..dc2c7d1 100644
--- a/src/factories/naudio/v1/AudioTableFactory.cpp
+++ b/src/factories/naudio/v1/AudioTableFactory.cpp
@@ -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;
}
diff --git a/src/factories/naudio/v1/DrumFactory.cpp b/src/factories/naudio/v1/DrumFactory.cpp
index bceaaae..38ec7cf 100644
--- a/src/factories/naudio/v1/DrumFactory.cpp
+++ b/src/factories/naudio/v1/DrumFactory.cpp
@@ -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);
diff --git a/src/factories/naudio/v1/InstrumentFactory.cpp b/src/factories/naudio/v1/InstrumentFactory.cpp
index 19989db..b0c8143 100644
--- a/src/factories/naudio/v1/InstrumentFactory.cpp
+++ b/src/factories/naudio/v1/InstrumentFactory.cpp
@@ -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);
diff --git a/src/factories/naudio/v1/SampleFactory.cpp b/src/factories/naudio/v1/SampleFactory.cpp
index a416e04..3a40883 100644
--- a/src/factories/naudio/v1/SampleFactory.cpp
+++ b/src/factories/naudio/v1/SampleFactory.cpp
@@ -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();
- if(!cnv.empty()){
- write_aiff(cnv, aiff);
- aiff.Finish(write);
+#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);
+ }
+#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;
diff --git a/src/factories/naudio/v1/SequenceFactory.cpp b/src/factories/naudio/v1/SequenceFactory.cpp
index 1d95cf4..ad89131 100644
--- a/src/factories/naudio/v1/SequenceFactory.cpp
+++ b/src/factories/naudio/v1/SequenceFactory.cpp
@@ -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);
}
diff --git a/src/factories/naudio/v1/SoundFontFactory.cpp b/src/factories/naudio/v1/SoundFontFactory.cpp
index 81419fa..e0ba51c 100644
--- a/src/factories/naudio/v1/SoundFontFactory.cpp
+++ b/src/factories/naudio/v1/SoundFontFactory.cpp
@@ -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>();
diff --git a/src/factories/sf64/audio/AudioDecompressor.cpp b/src/factories/sf64/audio/AudioDecompressor.cpp
new file mode 100644
index 0000000..04203f1
--- /dev/null
+++ b/src/factories/sf64/audio/AudioDecompressor.cpp
@@ -0,0 +1,500 @@
+#include <cstdint>
+#include <vector>
+#include <cmath>
+#include "endianness.h"
+#include "AudioDecompressor.h"
+
+struct StupidDMAStruct {
+ int16_t* unk_0;
+ int32_t unk_4;
+ int32_t unk_8;
+ int16_t* unk_C;
+ int16_t unk18;
+};
+
+int16_t D_8014C1B4 = 0x1000;
+float D_80145D48[256];
+float D_80146148[256];
+float D_80146548[515];
+float D_80146D54;
+float D_80146D58;
+float D_80146D5C;
+float D_80146D60;
+float D_80146D64;
+float D_80146D68;
+float D_80146D6C;
+float D_80146D70;
+
+void func_80009124(int16_t** arg0) {
+ int16_t* var_a1;
+ int32_t temp_a0;
+ uint8_t temp_s0;
+ uint8_t temp_s1;
+ uint8_t temp_u1;
+ int32_t temp_t5_4;
+ int32_t temp_v0;
+ uint8_t temp_v1;
+ int32_t var_s1;
+ int32_t var_t2;
+ int32_t var_v1;
+ uint16_t var_s0;
+ uint32_t var_t3;
+ int32_t i;
+ int32_t j;
+ int16_t new_var2;
+
+ var_a1 = *arg0;
+
+ for (i = 255; i >= 0; i--) {
+ D_80145D48[i] = 0.0f;
+ }
+ temp_v0 = *var_a1++;
+ var_t3 = temp_v0 << 0x10;
+ temp_v0 = *var_a1++;
+ var_t3 |= temp_v0;
+
+ for (var_t2 = 0; var_t2 < 4; var_t2++) {
+ var_v1 = var_t2 * 0x40;
+ temp_s0 = var_t3 >> 0x18;
+
+ var_t3 <<= 8;
+
+ temp_v1 = ((temp_s0 >> 4) & 0xF);
+ temp_a0 = temp_s0 & 0xF;
+ if (temp_v1 == 0) {
+ continue;
+ }
+ switch (temp_v1) {
+ case 1:
+ while (true) {
+ var_s0 = *var_a1++;
+ for (var_s1 = 0; var_s1 < 4; var_s1++) {
+ temp_u1 = (var_s0 >> 0xC) & 0xF;
+ var_s0 <<= 4;
+ D_80145D48[var_v1++] = ((temp_u1 & 7) - 4) << temp_a0;
+ if (temp_u1 >= 8) {
+ goto case_1_break;
+ }
+ }
+ }
+ case_1_break:
+ break;
+ case 2:
+ for (var_s1 = 0; var_s1 < 16; var_s1++) {
+ var_s0 = *var_a1++;
+ for (i = 0; i < 4; i++) {
+ temp_u1 = (var_s0 >> 0xC) & 0xF;
+ var_s0 <<= 4;
+ D_80145D48[var_v1++] = (temp_u1 - 8) << temp_a0;
+ }
+ }
+ break;
+ case 6:
+ while (true) {
+ var_s0 = *var_a1++;
+ temp_u1 = (var_s0 >> 8) & 0xFF;
+ temp_t5_4 = temp_u1 >> 6;
+ D_80145D48[var_v1] = ((temp_u1 & 0x3F) - 0x20) << temp_a0;
+ if (temp_t5_4 == 0) {
+ break;
+ }
+ var_v1 += temp_t5_4;
+ temp_u1 = var_s0 & 0xFF;
+ temp_t5_4 = temp_u1 >> 6;
+ D_80145D48[var_v1] = ((temp_u1 & 0x3F) - 0x20) << temp_a0;
+ if (temp_t5_4 == 0) {
+ break;
+ }
+ var_v1 += temp_t5_4;
+ }
+ break;
+ case 3:
+ while (true) {
+ var_s0 = *var_a1++;
+ temp_u1 = (var_s0 >> 8) & 0xFF;
+
+ D_80145D48[var_v1++] = ((temp_u1 & 0x7F) - 0x40) << temp_a0;
+
+ if (temp_u1 >= 0x80) {
+ break;
+ }
+ temp_u1 = var_s0 & 0xFF;
+ D_80145D48[var_v1++] = ((temp_u1 & 0x7F) - 0x40) << temp_a0;
+ if (temp_u1 >= 0x80) {
+ break;
+ }
+ }
+ break;
+ case 4:
+ while (true) {
+ var_s0 = *var_a1++;
+ temp_t5_4 = var_s0 >> 0xC;
+ D_80145D48[var_v1] = ((var_s0 & 0xFFF) - 0x800) << temp_a0;
+ if (temp_t5_4 == 0) {
+ break;
+ }
+ var_v1 += temp_t5_4;
+ }
+ break;
+ case 5:
+ while (true) {
+ var_s0 = *var_a1++;
+ temp_t5_4 = var_s0 >> 0xF;
+ D_80145D48[var_v1] = ((var_s0 & 0x7FFF) - 0x4000) << temp_a0;
+ if (temp_t5_4 == 1) {
+ break;
+ }
+ var_v1++;
+ }
+ break;
+ }
+ }
+ *arg0 = var_a1;
+}
+
+void AudioSynth_HartleyTransform(float* arg0, int32_t arg1, float* arg2) {
+ int32_t length;
+ int32_t spD0;
+ int32_t spCC;
+ int32_t spC8;
+ int32_t var_a0;
+ int32_t spC0;
+ int32_t spBC;
+ int32_t pad;
+ int32_t spB4;
+ int32_t sp58;
+ int32_t sp50;
+ int32_t spA8;
+ float var_fs0;
+ float temp_fa0;
+ float temp_fv1;
+ float* temp_a0;
+ float* temp_a1;
+ float* temp_a2;
+ float* temp_a3;
+ float* temp_b0;
+ float* temp_b1;
+ float* temp_b2;
+ float* temp_b3;
+ float* var_s0;
+ float* var_s1;
+ float* var_s2;
+ float* var_s3;
+
+ length = 1 << arg1;
+ spBC = length * 2;
+ sp58 = (length / 8) - 1;
+ switch (length) {
+ case 1:
+ break;
+ case 2:
+ temp_fa0 = arg0[1];
+ temp_fv1 = arg0[0];
+
+ arg0[0] = (temp_fa0 + temp_fv1) * 0.707107f;
+ arg0[1] = (temp_fv1 - temp_fa0) * 0.707107f;
+ break;
+ case 4:
+ temp_fv1 = arg0[0];
+ arg0[0] = (arg0[2] + temp_fv1) / 2.0f;
+ arg0[2] = (temp_fv1 - arg0[2]) / 2.0f;
+
+ temp_fa0 = arg0[1];
+ arg0[1] = (arg0[3] + temp_fa0) / 2.0f;
+ arg0[3] = (temp_fa0 - arg0[3]) / 2.0f;
+
+ temp_fv1 = arg0[0];
+ temp_fa0 = arg0[1];
+ arg0[0] = arg0[1] + temp_fv1;
+ arg0[1] = arg0[3] + arg0[2];
+ arg0[3] = arg0[2] - arg0[3];
+ arg0[2] = temp_fv1 - temp_fa0;
+ break;
+ default:
+ if (length != (int32_t) *arg2) {
+ *arg2 = length;
+
+ var_s0 = &arg2[1];
+ var_s1 = &var_s0[sp58];
+ var_s2 = &var_s1[sp58];
+ var_s3 = &var_s2[sp58];
+
+ var_fs0 = 6.283186f / length;
+ for (spCC = 0; spCC < sp58; spCC++) {
+ *var_s0++ = cosf(var_fs0);
+ *var_s1++ = sinf(var_fs0);
+ *var_s2++ = cosf(3.0f * var_fs0);
+ *var_s3++ = sinf(3.0f * var_fs0);
+ var_fs0 += 6.283186f / length;
+ }
+ }
+ spC0 = 1;
+ for (spD0 = 0; spD0 < arg1 - 1; spD0++) {
+ spA8 = spBC;
+ spBC >>= 1;
+ spB4 = spBC >> 3;
+ sp50 = spBC >> 2;
+ var_a0 = 1;
+ do {
+ for (spCC = var_a0 - 1; spCC < length; spCC += spA8) {
+ // if (0) { }
+ temp_a0 = arg0 + spCC;
+ temp_a1 = temp_a0 + sp50;
+ temp_a2 = temp_a1 + sp50;
+ temp_a3 = temp_a2 + sp50;
+
+ D_80146D54 = *temp_a0;
+ *temp_a0 = *temp_a2 + D_80146D54;
+ D_80146D58 = *temp_a1;
+ *temp_a1 = *temp_a1 + *temp_a3;
+ D_80146D5C = *temp_a2;
+ *temp_a2 = D_80146D54 - D_80146D5C + D_80146D58 - *temp_a3;
+ *temp_a3 = D_80146D54 - D_80146D5C - D_80146D58 + *temp_a3;
+ if (sp50 > 1) {
+ temp_a0 = arg0 + spCC + spB4;
+ temp_a1 = temp_a0 + sp50;
+ temp_a2 = temp_a1 + sp50;
+ temp_a3 = temp_a2 + sp50;
+
+ D_80146D54 = *temp_a0;
+ *temp_a0 = *temp_a2 + D_80146D54;
+ D_80146D58 = *temp_a1;
+ *temp_a1 = *temp_a3 + D_80146D58;
+ *temp_a2 = (D_80146D54 - *temp_a2) * 1.414214f;
+ *temp_a3 = (D_80146D58 - *temp_a3) * 1.414214f;
+
+ var_s0 = &arg2[spC0];
+ var_s1 = &var_s0[sp58];
+ var_s2 = &var_s1[sp58];
+ var_s3 = &var_s2[sp58];
+ for (spC8 = 1; spC8 < spB4; spC8++) {
+ temp_a0 = arg0 + spCC + spC8;
+ temp_a1 = temp_a0 + sp50;
+ temp_a2 = temp_a1 + sp50;
+ temp_a3 = temp_a2 + sp50;
+
+ temp_b0 = arg0 + spCC + sp50 - spC8;
+ temp_b1 = temp_b0 + sp50;
+ temp_b2 = temp_b1 + sp50;
+ temp_b3 = temp_b2 + sp50;
+
+ D_80146D54 = *temp_a0;
+ D_80146D58 = *temp_a1;
+ D_80146D5C = *temp_a2;
+ D_80146D60 = *temp_a3;
+
+ D_80146D64 = *temp_b0;
+ D_80146D68 = *temp_b1;
+ D_80146D6C = *temp_b2;
+ D_80146D70 = *temp_b3;
+
+ *temp_a0 = D_80146D54 + D_80146D5C;
+ *temp_a1 = D_80146D58 + D_80146D60;
+ *temp_a2 = ((D_80146D54 - D_80146D5C + D_80146D64 - D_80146D6C) * *var_s0) +
+ ((D_80146D60 - D_80146D58 + D_80146D68 - D_80146D70) * *var_s1);
+ *temp_a3 = ((D_80146D54 - D_80146D5C - D_80146D64 + D_80146D6C) * *var_s2) -
+ ((D_80146D60 - D_80146D58 - D_80146D68 + D_80146D70) * *var_s3);
+ *temp_b0 = D_80146D64 + D_80146D6C;
+ *temp_b1 = D_80146D68 + D_80146D70;
+ *temp_b2 = ((D_80146D54 - D_80146D5C + D_80146D64 - D_80146D6C) * *var_s1) -
+ ((D_80146D60 - D_80146D58 + D_80146D68 - D_80146D70) * *var_s0);
+ *temp_b3 = ((D_80146D54 - D_80146D5C - D_80146D64 + D_80146D6C) * *var_s3) +
+ ((D_80146D60 - D_80146D58 - D_80146D68 + D_80146D70) * *var_s2);
+ var_s0 += spC0;
+ var_s1 += spC0;
+ var_s2 += spC0;
+ var_s3 += spC0;
+ }
+ }
+ }
+ var_a0 = ((spA8 * 2) - spBC) + 1;
+ spA8 *= 4;
+ } while (var_a0 < length);
+ spC0 = spC0 * 2;
+ temp_a0 = arg0;
+ for (spC8 = 0; spC8 < length; spC8++, temp_a0++) {
+ *temp_a0 /= 1.414214f;
+ }
+ }
+ var_a0 = 1;
+ spA8 = 4;
+
+ do {
+ for (spCC = var_a0 - 1; spCC < length; spCC += spA8) {
+ D_80146D54 = arg0[spCC];
+ arg0[spCC] = arg0[spCC + 1] + D_80146D54;
+ arg0[spCC + 1] = D_80146D54 - arg0[spCC + 1];
+ }
+ var_a0 = (spA8 * 2) - 1;
+ spA8 *= 4;
+ } while (var_a0 < length);
+ temp_a0 = arg0;
+ for (spC8 = 0; spC8 < length; spC8++) {
+ *temp_a0++ /= 1.414214f;
+ }
+ spB4 = 1;
+ temp_a0 = arg0;
+
+ for (spC8 = 1; spC8 < length; spC8++) {
+ if (spC8 < spB4) {
+ D_80146D54 = arg0[spB4 - 1];
+ arg0[spB4 - 1] = *temp_a0;
+ *temp_a0 = D_80146D54;
+ }
+ temp_a0++;
+ spC0 = length >> 1;
+ while (spC0 < spB4) {
+ spB4 -= spC0;
+ spC0 >>= 1;
+ }
+ spB4 += spC0;
+ }
+ break;
+ }
+}
+
+void AudioSynth_InverseDiscreteCosineTransform(float* buffer0, float* buffer1, int32_t length, float* buffer2) {
+ float temp_ft0;
+ float var_fs0;
+ float* buff0fromStart;
+ float* buf2half2;
+ float* buf2half3;
+ float* buff1half1;
+ float* buff0FromEnd;
+ float* buff1half2;
+ int32_t half;
+ int32_t i;
+ int32_t size;
+
+ size = 1 << length;
+ half = size >> 1;
+
+ // Initialize buffer 2 if it is the wrong size for this calculation
+ if (size != (int32_t) buffer2[0]) {
+ buf2half2 = &buffer2[half];
+ buf2half3 = &buf2half2[half];
+ var_fs0 = 0.0f;
+ temp_ft0 = M_PI / (float) (2 * size);
+ for (i = 0; i < half; i++) {
+ *buf2half2++ = (cosf(var_fs0) - sinf(var_fs0)) * 0.707107f;
+ *buf2half3++ = (cosf(var_fs0) + sinf(var_fs0)) * 0.707107f;
+ var_fs0 += temp_ft0;
+ }
+ }
+
+ // reset the buffer pointers
+ buf2half2 = &buffer2[half];
+ buf2half3 = &buf2half2[half];
+ buff1half1 = buffer1;
+ buff0fromStart = buffer0;
+
+ // handle i = 0 case
+ buffer1[0] = buffer0[0];
+ buffer1[half] = buffer0[half];
+
+ // advance buffer pointers
+ buf2half2++;
+ buf2half3++;
+ buff0fromStart++;
+ buff0FromEnd = &buffer0[size - 1];
+ buff1half1++;
+ buff1half2 = &buffer1[size - 1];
+
+ // convert to real amplitudes
+ for (i = 1; i < half; i++) {
+ *buff1half1++ = (*buf2half2 * *buff0fromStart) + (*buf2half3 * *buff0FromEnd);
+ *buff1half2-- = (*buf2half3 * *buff0fromStart) - (*buf2half2 * *buff0FromEnd);
+ buff0fromStart++;
+ buf2half3++;
+ buf2half2++;
+ buff0FromEnd--;
+ }
+
+ // FFT buffer 1 using buffer 2
+ AudioSynth_HartleyTransform(buffer1, length, buffer2);
+
+ buff0fromStart = buffer0;
+ buff0FromEnd = &buffer0[size - 1];
+ buff1half1 = buffer1;
+ buff1half2 = &buffer1[half];
+
+ // Copy even entries of buffer 0 into the first half of buffer 1. Copy odd entries into the second half in reverse
+ // order
+ for (i = 0; i < half; i++) {
+ *buff0fromStart = *buff1half1++;
+ *buff0FromEnd = *buff1half2++;
+ buff0fromStart += 2;
+ buff0FromEnd -= 2;
+ }
+}
+
+void func_80009504(int16_t* arg0, StupidDMAStruct* arg1) {
+ int32_t i;
+
+ if (arg1->unk_0 != nullptr) {
+ arg1->unk_C = arg1->unk_0;
+ arg1->unk_0 = 0;
+ }
+
+ arg1->unk18 += D_8014C1B4;
+
+ while (arg1->unk18 > 0x1000) {
+ func_80009124(&arg1->unk_C);
+ arg1->unk18 -= 0x1000;
+ }
+
+ AudioSynth_InverseDiscreteCosineTransform(D_80145D48, D_80146148, 8, D_80146548);
+
+ for (i = 0; i < 256; i++) {
+ if (D_80145D48[i] > 32767.0f) {
+ D_80145D48[i] = 32767.0f;
+ }
+ if (D_80145D48[i] < -32767.0f) {
+ D_80145D48[i] = -32767.0f;
+ }
+ }
+
+ for (i = 0; i < 0x100; i++, arg0++) {
+ *arg0 = (int16_t) D_80145D48[i];
+ }
+}
+
+int32_t func_8000967C(int32_t length, int16_t* inputAddr, int16_t* ramAddr, StupidDMAStruct* arg2) {
+ int32_t pad;
+ int32_t temp_t0;
+ int32_t i;
+ int32_t var_s1;
+ int16_t* temp_t7 = inputAddr;
+
+ for (i = 0; i < arg2->unk_4; i++) {
+ ramAddr[i] = temp_t7[i];
+ }
+
+ var_s1 = arg2->unk_4;
+ temp_t0 = (length - arg2->unk_4 + 0xFF) / 256;
+ arg2->unk_4 = (temp_t0 * 256) + arg2->unk_4 - length;
+
+ for (i = 0; i < temp_t0; i++) {
+ func_80009504(&ramAddr[var_s1], arg2);
+ var_s1 += 0x100;
+ }
+
+ for (i = 0; i < arg2->unk_4; i++) {
+ temp_t7[i] = ramAddr[length + i];
+ }
+ return temp_t0;
+}
+
+void SF64::DecompressAudio(std::vector<uint8_t> data, int16_t* output) {
+ StupidDMAStruct arg3 = {};
+ arg3.unk_0 = (int16_t*) data.data();
+ arg3.unk_4 = 0;
+ arg3.unk_8 = 0;
+ arg3.unk18 = 0;
+
+ for(int i = 0; i < data.size() / 2; i++){
+ arg3.unk_0[i] = BSWAP16(arg3.unk_0[i]);
+ }
+
+ func_8000967C((int32_t) data.size(), arg3.unk_0, (int16_t*) output, &arg3);
+} \ No newline at end of file
diff --git a/src/factories/sf64/audio/AudioDecompressor.h b/src/factories/sf64/audio/AudioDecompressor.h
new file mode 100644
index 0000000..938703b
--- /dev/null
+++ b/src/factories/sf64/audio/AudioDecompressor.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+namespace SF64 {
+ void DecompressAudio(std::vector<uint8_t> data, int16_t* output);
+} \ No newline at end of file