diff options
| author | KiritoDv <kiritodev01@gmail.com> | 2025-01-31 11:45:43 -0600 |
|---|---|---|
| committer | KiritoDv <kiritodev01@gmail.com> | 2025-01-31 11:45:43 -0600 |
| commit | 7ae083a3a16000afe435caacf9d3588f1de37873 (patch) | |
| tree | e8b70fadb319a6b2ef7eb2ccdaadb58664e35a81 /src | |
| parent | 7b83e15d8068c6fc18b52c90b0cbc425b5abd63f (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.cpp | 3 | ||||
| -rw-r--r-- | src/factories/naudio/v1/AudioContext.cpp | 30 | ||||
| -rw-r--r-- | src/factories/naudio/v1/AudioContext.h | 19 | ||||
| -rw-r--r-- | src/factories/naudio/v1/AudioConverter.cpp | 5 | ||||
| -rw-r--r-- | src/factories/naudio/v1/AudioTableFactory.cpp | 12 | ||||
| -rw-r--r-- | src/factories/naudio/v1/DrumFactory.cpp | 2 | ||||
| -rw-r--r-- | src/factories/naudio/v1/InstrumentFactory.cpp | 2 | ||||
| -rw-r--r-- | src/factories/naudio/v1/SampleFactory.cpp | 52 | ||||
| -rw-r--r-- | src/factories/naudio/v1/SequenceFactory.cpp | 6 | ||||
| -rw-r--r-- | src/factories/naudio/v1/SoundFontFactory.cpp | 2 | ||||
| -rw-r--r-- | src/factories/sf64/audio/AudioDecompressor.cpp | 500 | ||||
| -rw-r--r-- | src/factories/sf64/audio/AudioDecompressor.h | 8 |
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 |
