summaryrefslogtreecommitdiff
path: root/ZAPDTR
diff options
context:
space:
mode:
authorNicholas Estelami <NEstelami@users.noreply.github.com>2022-06-01 13:06:32 -0400
committerNicholas Estelami <NEstelami@users.noreply.github.com>2022-06-16 20:35:52 -0400
commit941c19f2c33a0d1af75a10a64fe0905387d1e440 (patch)
tree137060be3f45645965726f1e14fd58d066ce7e08 /ZAPDTR
parent5fcddaa066cad80ff9c3f9946b3e3df101afd3f3 (diff)
Audio decompiled and WIP custom sample support
Diffstat (limited to 'ZAPDTR')
-rw-r--r--ZAPDTR/ZAPD/Main.cpp2
-rw-r--r--ZAPDTR/ZAPD/ZAPD.vcxproj3
-rw-r--r--ZAPDTR/ZAPD/ZAPD.vcxproj.filters9
-rw-r--r--ZAPDTR/ZAPD/ZAudio.cpp325
-rw-r--r--ZAPDTR/ZAPD/ZAudio.h122
-rw-r--r--ZAPDTR/ZAPD/ZAudioDecode.cpp669
-rw-r--r--ZAPDTR/ZAPD/ZResource.h3
-rw-r--r--ZAPDTR/ZAPD/ZRom.cpp2
8 files changed, 1133 insertions, 2 deletions
diff --git a/ZAPDTR/ZAPD/Main.cpp b/ZAPDTR/ZAPD/Main.cpp
index 65a65fea6..a9f70eed5 100644
--- a/ZAPDTR/ZAPD/Main.cpp
+++ b/ZAPDTR/ZAPD/Main.cpp
@@ -39,7 +39,7 @@ extern "C" void Audio_SetGameVolume(int player_id, float volume)
extern "C" int ResourceMgr_OTRSigCheck(char* imgData)
{
-
+ return 0;
}
void DebugConsole_SaveCVars()
diff --git a/ZAPDTR/ZAPD/ZAPD.vcxproj b/ZAPDTR/ZAPD/ZAPD.vcxproj
index 91ff515a2..940d3b2ed 100644
--- a/ZAPDTR/ZAPD/ZAPD.vcxproj
+++ b/ZAPDTR/ZAPD/ZAPD.vcxproj
@@ -195,6 +195,8 @@
<ClCompile Include="WarningHandler.cpp" />
<ClCompile Include="yaz0\yaz0.cpp" />
<ClCompile Include="ZArray.cpp" />
+ <ClCompile Include="ZAudio.cpp" />
+ <ClCompile Include="ZAudioDecode.cpp" />
<ClCompile Include="ZBackground.cpp" />
<ClCompile Include="ZCutsceneMM.cpp" />
<ClCompile Include="ZLimb.cpp" />
@@ -288,6 +290,7 @@
<ClInclude Include="yaz0\yaz0.h" />
<ClInclude Include="ZAnimation.h" />
<ClInclude Include="ZArray.h" />
+ <ClInclude Include="ZAudio.h" />
<ClInclude Include="ZBackground.h" />
<ClInclude Include="ZBlob.h" />
<ClInclude Include="ZCollision.h" />
diff --git a/ZAPDTR/ZAPD/ZAPD.vcxproj.filters b/ZAPDTR/ZAPD/ZAPD.vcxproj.filters
index c122b7e56..82fa8acb2 100644
--- a/ZAPDTR/ZAPD/ZAPD.vcxproj.filters
+++ b/ZAPDTR/ZAPD/ZAPD.vcxproj.filters
@@ -297,6 +297,12 @@
<ClCompile Include="FileWorker.cpp">
<Filter>Source Files</Filter>
</ClCompile>
+ <ClCompile Include="ZAudio.cpp">
+ <Filter>Source Files\Z64</Filter>
+ </ClCompile>
+ <ClCompile Include="ZAudioDecode.cpp">
+ <Filter>Source Files\Z64</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ZRoom\ZRoom.h">
@@ -569,6 +575,9 @@
<ClInclude Include="ctpl_stl.h">
<Filter>Header Files\Libraries</Filter>
</ClInclude>
+ <ClInclude Include="ZAudio.h">
+ <Filter>Header Files\Z64</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<Text Include="..\SymbolMap_OoTMqDbg.txt">
diff --git a/ZAPDTR/ZAPD/ZAudio.cpp b/ZAPDTR/ZAPD/ZAudio.cpp
new file mode 100644
index 000000000..1c24c824a
--- /dev/null
+++ b/ZAPDTR/ZAPD/ZAudio.cpp
@@ -0,0 +1,325 @@
+#include "ZAudio.h"
+
+#include "Globals.h"
+#include "Utils/BitConverter.h"
+#include "Utils/File.h"
+#include "Utils/Path.h"
+#include "Utils/StringHelper.h"
+#include "ZFile.h"
+
+REGISTER_ZFILENODE(Audio, ZAudio);
+
+ZAudio::ZAudio(ZFile* nParent) : ZResource(nParent)
+{
+ //RegisterRequiredAttribute("CodeOffset");
+ //RegisterOptionalAttribute("LangOffset", "0");
+}
+
+void ZAudio::DecodeADPCMSample(SampleEntry* sample)
+{
+ int16_t buffer[1024 * 128];
+
+ int16_t* out = &buffer[0];
+}
+
+std::vector<AdsrEnvelope*> ZAudio::ParseEnvelopeData(std::vector<uint8_t> audioBank, std::vector<uint8_t> audioTable, int envelopeOffset, int baseOffset)
+{
+ std::vector<AdsrEnvelope*> result;
+
+ //bool process = true;
+
+ //for (int i = 0; i < 4; i++)
+ while (true)
+ {
+ AdsrEnvelope* env = new AdsrEnvelope();
+
+ env->delay = BitConverter::ToInt16BE(audioBank, envelopeOffset + 0);
+ env->arg = BitConverter::ToInt16BE(audioBank, envelopeOffset + 2);
+
+ envelopeOffset += 4;
+
+ result.push_back(env);
+
+ if (env->delay < 0)
+ break;
+ }
+
+ return result;
+}
+
+SoundFontEntry* ZAudio::ParseSoundFontEntry(std::vector<uint8_t> audioBank,
+ std::vector<uint8_t> audioTable,
+ AudioTableEntry audioSampleBankEntry,
+ int soundFontOffset,
+ int baseOffset)
+{
+ SoundFontEntry* soundFont = new SoundFontEntry();
+ soundFont->sampleEntry = ParseSampleEntry(
+ audioBank, audioTable, audioSampleBankEntry,
+ BitConverter::ToInt32BE(audioBank, soundFontOffset + 0) + baseOffset, baseOffset);
+ soundFont->tuning = BitConverter::ToFloatBE(audioBank, soundFontOffset + 4);
+
+ return soundFont;
+}
+
+SampleEntry* ZAudio::ParseSampleEntry(std::vector<uint8_t> audioBank,
+ std::vector<uint8_t> audioTable,
+ AudioTableEntry audioSampleBankEntry,
+ int sampleOffset,
+ int baseOffset)
+{
+ int sampleDataOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 4) + audioSampleBankEntry.ptr;
+
+ if (samples.find(sampleOffset) == samples.end())
+ {
+ SampleEntry* sample = new SampleEntry();
+
+ int sampleSize = BitConverter::ToInt32BE(audioBank, sampleOffset + 0) & 0x00FFFFFF;
+ int loopOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 8) + baseOffset;
+ int bookOffset = BitConverter::ToInt32BE(audioBank, sampleOffset + 12) + baseOffset;
+
+ char* sampleData = (char*)malloc(sampleSize);
+ memcpy(sampleData, audioTable.data() + sampleDataOffset, sampleSize);
+ sample->data = std::vector<uint8_t>(sampleSize);
+ memcpy(sample->data.data(), sampleData, sampleSize);
+
+ uint32_t origField = (BitConverter::ToUInt32BE(audioBank, sampleOffset + 0));
+ sample->codec = (origField >> 28) & 0x0F;
+ sample->medium = (origField >> 24) & 0x03;
+ sample->unk_bit26 = (origField >> 22) & 0x01;
+ sample->unk_bit25 = (origField >> 21) & 0x01;
+
+ sample->loop.start = BitConverter::ToInt32BE(audioBank, loopOffset + 0);
+ sample->loop.end = BitConverter::ToInt32BE(audioBank, loopOffset + 4);
+ sample->loop.count = BitConverter::ToInt32BE(audioBank, loopOffset + 8);
+
+ if (sample->loop.count != 0xFFFFFFFF)
+ {
+ for (int i = 0; i < sample->loop.count; i++)
+ {
+ int16_t state = BitConverter::ToInt16BE(sample->data, loopOffset + 16 + (i * 2));
+ sample->loop.states.push_back(state);
+ }
+ }
+
+ sample->book.order = BitConverter::ToInt32BE(audioBank, bookOffset + 0);
+ sample->book.npredictors = BitConverter::ToInt32BE(audioBank, bookOffset + 4);
+
+ for (int i = 0; i < sample->book.npredictors * sample->book.order * 8; i++)
+ {
+ sample->book.books.push_back(
+ BitConverter::ToInt16BE(audioBank, bookOffset + 8 + (i * 2)));
+ }
+
+ samples[sampleOffset] = sample;
+
+ return sample;
+ }
+ else
+ {
+ return samples[sampleOffset];
+ }
+}
+
+std::vector<AudioTableEntry> ZAudio::ParseAudioTable(std::vector<uint8_t> codeData, int baseOffset)
+{
+ std::vector<AudioTableEntry> entries;
+
+ int numEntries = BitConverter::ToInt16BE(codeData, baseOffset + 0);
+ int romAddr = BitConverter::ToInt16BE(codeData, baseOffset + 4);
+
+ int currentOffset = baseOffset + 16;
+
+ for (int i = 0; i < numEntries; i++)
+ {
+ AudioTableEntry entry;
+
+ entry.ptr = BitConverter::ToInt32BE(codeData, currentOffset + 0);
+ entry.size = BitConverter::ToInt32BE(codeData, currentOffset + 4);
+ entry.medium = codeData[currentOffset + 8];
+ entry.cachePolicy = codeData[currentOffset + 9];
+ entry.data1 = BitConverter::ToInt16BE(codeData, currentOffset + 10);
+ entry.data2 = BitConverter::ToInt16BE(codeData, currentOffset + 12);
+ entry.data3 = BitConverter::ToInt16BE(codeData, currentOffset + 14);
+
+ entries.push_back(entry);
+
+ currentOffset += 16;
+ }
+
+ return entries;
+}
+
+void ZAudio::ParseSoundFont(std::vector<uint8_t> codeData, std::vector<uint8_t> audioTable,
+ std::vector<AudioTableEntry> audioSampleBank,
+ AudioTableEntry& entry)
+{
+ int ptr = entry.ptr;
+ int size = entry.size;
+ int sampleBankId1 = (entry.data1 >> 8) & 0xFF;
+ int sampleBankId2 = (entry.data1) & 0xFF;
+ int numInstruments = (entry.data2 >> 8) & 0xFF;
+ int numDrums = entry.data2 & 0xFF;
+ int numSfx = entry.data3;
+
+ int currentOffset = BitConverter::ToInt32BE(codeData, ptr) + ptr;
+ for (int i = 0; i < numDrums; i++)
+ {
+ DrumEntry drum;
+
+ int samplePtr = BitConverter::ToInt32BE(codeData, currentOffset);
+
+ if (samplePtr != 0)
+ {
+ samplePtr += ptr;
+
+ drum.sample = ParseSampleEntry(codeData, audioTable, audioSampleBank[sampleBankId1],
+ BitConverter::ToInt32BE(codeData, samplePtr + 4) + ptr, ptr);
+
+ drum.releaseRate = codeData[samplePtr + 0];
+ drum.pan = codeData[samplePtr + 1];
+ drum.loaded = codeData[samplePtr + 2];
+ drum.tuning = BitConverter::ToFloatBE(codeData, samplePtr + 8);
+
+ //int sampleDefOffset = BitConverter::ToInt32BE(codeData, samplePtr + 4);
+ drum.env = ParseEnvelopeData(codeData, audioTable, BitConverter::ToInt32BE(codeData, samplePtr + 12) + ptr, ptr);
+ }
+
+ entry.drums.push_back(drum);
+
+ currentOffset += 4;
+ }
+
+ currentOffset = BitConverter::ToInt32BE(codeData, ptr + 4) + ptr;
+ for (int i = 0; i < numSfx; i++)
+ {
+ SoundFontEntry* sfx;
+ sfx = ParseSoundFontEntry(codeData, audioTable, audioSampleBank[sampleBankId1],
+ currentOffset, ptr);
+ entry.soundEffects.push_back(sfx);
+
+ currentOffset += 8;
+ }
+
+ for (int i = 0; i < numInstruments; i++)
+ {
+ InstrumentEntry instrument;
+
+ currentOffset = BitConverter::ToInt32BE(codeData, ptr + 8 + (i * 4));
+
+ instrument.isValidInstrument = currentOffset != 0;
+
+ if (currentOffset != 0)
+ {
+ currentOffset += ptr;
+
+ instrument.loaded = codeData[currentOffset + 0];
+ instrument.normalRangeLo = codeData[currentOffset + 1];
+ instrument.normalRangeHi = codeData[currentOffset + 2];
+ instrument.releaseRate = codeData[currentOffset + 3];
+ instrument.env = ParseEnvelopeData(codeData, audioTable, BitConverter::ToInt32BE(codeData, currentOffset + 4) + ptr, ptr);
+
+ if (BitConverter::ToInt32BE(codeData, currentOffset + 8) != 0)
+ instrument.lowNotesSound = ParseSoundFontEntry(
+ codeData, audioTable, audioSampleBank[sampleBankId1], currentOffset + 8, ptr);
+
+ if (BitConverter::ToInt32BE(codeData, currentOffset + 16) != 0)
+ instrument.normalNotesSound = ParseSoundFontEntry(
+ codeData, audioTable, audioSampleBank[sampleBankId1], currentOffset + 16, ptr);
+
+ if (BitConverter::ToInt32BE(codeData, currentOffset + 24) != 0 &&
+ instrument.normalRangeHi != 0x7F)
+ instrument.highNotesSound = ParseSoundFontEntry(
+ codeData, audioTable, audioSampleBank[sampleBankId1], currentOffset + 24, ptr);
+ }
+
+ entry.instruments.push_back(instrument);
+ }
+}
+
+void ZAudio::ParseRawData()
+{
+ ZResource::ParseRawData();
+
+ std::vector<uint8_t> codeData;
+ std::vector<uint8_t> audioTableData;
+ std::vector<uint8_t> audioBankData;
+ std::vector<uint8_t> audioSeqData;
+
+ if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
+ codeData = Globals::Instance->GetBaseromFile("code");
+ else
+ codeData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "code");
+
+ if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
+ audioTableData = Globals::Instance->GetBaseromFile("Audiotable");
+ else
+ audioTableData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "Audiotable");
+
+ if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
+ audioBankData = Globals::Instance->GetBaseromFile("Audiobank");
+ else
+ audioBankData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() + "Audiobank");
+
+ if (Globals::Instance->fileMode == ZFileMode::ExtractDirectory)
+ audioSeqData = Globals::Instance->GetBaseromFile("Audioseq");
+ else
+ audioSeqData = Globals::Instance->GetBaseromFile(Globals::Instance->baseRomPath.string() +
+ "Audioseq");
+
+ // TABLE PARSING
+ //int gSoundFontTableOffset = 0x138270; // OTRTODO: Make this an XML Param
+ //int gSequenceTableOffset = 0x1386A0; // OTRTODO: Make this an XML Param
+ //int gSampleBankTableOffset = 0x138D90; // OTRTODO: Make this an XML Param
+ int gSoundFontTableOffset = 0x138290; // OTRTODO: Make this an XML Param
+ int gSequenceTableOffset = 0x1386C0; // OTRTODO: Make this an XML Param
+ int gSampleBankTableOffset = 0x138DB0; // OTRTODO: Make this an XML Param
+ soundFontTable = ParseAudioTable(codeData, gSoundFontTableOffset);
+ sequenceTable = ParseAudioTable(codeData, gSequenceTableOffset);
+ sampleBankTable = ParseAudioTable(codeData, gSampleBankTableOffset);
+ // int gSequenceFontTableOffset = 0x1384E0; // OTRTODO: Make this an XML Param
+
+
+ // SAMPLE/FONT PARSING
+ for (int i = 0; i < soundFontTable.size(); i++)
+ {
+ ParseSoundFont(audioBankData, audioTableData, sampleBankTable, soundFontTable[i]);
+ }
+
+
+ // SOUNDBANK PARSING
+ /*for (int i = 0; i < sampleBankTable.size(); i++)
+ {
+
+ }*/
+
+ // SEQUENCE PARSING
+ for (int i = 0; i < sequenceTable.size(); i++)
+ {
+ int seqDestIdx = i;
+
+ if (sequenceTable[i].size == 0)
+ seqDestIdx = sequenceTable[i].ptr;
+
+ std::vector<char> seqVec = std::vector<char>(sequenceTable[seqDestIdx].size);
+ memcpy(seqVec.data(), audioSeqData.data() + sequenceTable[seqDestIdx].ptr,
+ sequenceTable[seqDestIdx].size);
+
+ sequences.push_back(seqVec);
+ }
+}
+
+std::string ZAudio::GetSourceTypeName() const
+{
+ return "u8";
+}
+
+size_t ZAudio::GetRawDataSize() const
+{
+ return 1;
+}
+
+ZResourceType ZAudio::GetResourceType() const
+{
+ return ZResourceType::Audio;
+}
diff --git a/ZAPDTR/ZAPD/ZAudio.h b/ZAPDTR/ZAPD/ZAudio.h
new file mode 100644
index 000000000..a7c88410f
--- /dev/null
+++ b/ZAPDTR/ZAPD/ZAudio.h
@@ -0,0 +1,122 @@
+#pragma once
+
+#include "ZResource.h"
+#include "tinyxml2.h"
+
+struct AdsrEnvelope
+{
+ int16_t delay;
+ int16_t arg;
+};
+
+struct AdpcmBook
+{
+ /* 0x00 */ int32_t order;
+ /* 0x04 */ int32_t npredictors;
+ /* 0x08 */ std::vector<int16_t> books; // size 8 * order * npredictors. 8-byte aligned
+};
+
+struct AdpcmLoop
+{
+ /* 0x00 */ uint32_t start;
+ /* 0x04 */ uint32_t end;
+ /* 0x08 */ uint32_t count;
+ ///* 0x10 */ int16_t state[16]; // only exists if count != 0. 8-byte aligned
+ /* 0x10 */ std::vector<int16_t> states;
+};
+
+struct SampleEntry
+{
+ uint8_t codec;
+ uint8_t medium;
+ uint8_t unk_bit26;
+ uint8_t unk_bit25;
+
+ std::vector<uint8_t> data;
+ AdpcmLoop loop;
+ AdpcmBook book;
+};
+
+struct SoundFontEntry
+{
+ SampleEntry* sampleEntry = nullptr;
+ float tuning;
+};
+
+struct DrumEntry
+{
+ uint8_t releaseRate;
+ uint8_t pan;
+ uint8_t loaded;
+ uint32_t offset;
+ float tuning;
+ std::vector<AdsrEnvelope*> env;
+ //AdsrEnvelope* env = nullptr;
+ SampleEntry* sample = nullptr;
+};
+
+struct InstrumentEntry
+{
+ bool isValidInstrument;
+ uint8_t loaded;
+ uint8_t normalRangeLo;
+ uint8_t normalRangeHi;
+ uint8_t releaseRate;
+ std::vector<AdsrEnvelope*> env;
+ //AdsrEnvelope* env = nullptr;
+ SoundFontEntry* lowNotesSound = nullptr;
+ SoundFontEntry* normalNotesSound = nullptr;
+ SoundFontEntry* highNotesSound = nullptr;
+};
+
+struct AudioTableEntry
+{
+ uint32_t ptr;
+ uint32_t size;
+ uint8_t medium;
+ uint8_t cachePolicy;
+ uint16_t data1;
+ uint16_t data2;
+ uint16_t data3;
+
+ std::vector<DrumEntry> drums;
+ std::vector<SoundFontEntry*> soundEffects;
+ std::vector<InstrumentEntry> instruments;
+};
+
+class ZAudio : public ZResource
+{
+public:
+ std::vector<AudioTableEntry> soundFontTable;
+ std::vector<AudioTableEntry> sequenceTable;
+ std::vector<AudioTableEntry> sampleBankTable;
+ std::vector<std::vector<char>> sequences;
+ std::map<uint32_t, SampleEntry*> samples;
+
+ ZAudio(ZFile* nParent);
+
+ void DecodeADPCMSample(SampleEntry* sample);
+ std::vector<AdsrEnvelope*> ParseEnvelopeData(std::vector<uint8_t> audioBank, std::vector<uint8_t> audioTable,
+ int envelopeOffset, int baseOffset);
+
+ SoundFontEntry* ParseSoundFontEntry(std::vector<uint8_t> audioBank,
+ std::vector<uint8_t> audioTable,
+ AudioTableEntry audioSampleBankEntry,
+ int soundFontOffset,
+ int baseOffset);
+
+ SampleEntry* ParseSampleEntry(std::vector<uint8_t> audioBank, std::vector<uint8_t> audioTable,
+ AudioTableEntry audioSampleBankEntry,
+ int sampleOffset, int baseOffset);
+
+ std::vector<AudioTableEntry> ParseAudioTable(std::vector<uint8_t> codeData, int baseOffset);
+ void ParseSoundFont(std::vector<uint8_t> codeData, std::vector<uint8_t> audioTable,
+ std::vector<AudioTableEntry> audioSampleBank, AudioTableEntry& entry);
+
+ void ParseRawData() override;
+
+ std::string GetSourceTypeName() const override;
+ ZResourceType GetResourceType() const override;
+
+ size_t GetRawDataSize() const override;
+};
diff --git a/ZAPDTR/ZAPD/ZAudioDecode.cpp b/ZAPDTR/ZAPD/ZAudioDecode.cpp
new file mode 100644
index 000000000..b8b066474
--- /dev/null
+++ b/ZAPDTR/ZAPD/ZAudioDecode.cpp
@@ -0,0 +1,669 @@
+/**
+ * Bruteforcing decoder for converting ADPCM-encoded AIFC into AIFF, in a way
+ * that roundtrips with vadpcm_enc.
+ */
+#include <assert.h>
+#include <math.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+//#include <unistd.h>
+
+typedef signed char s8;
+typedef short s16;
+typedef int s32;
+typedef long long s64;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+typedef float f32;
+typedef double f64;
+
+#ifdef _MSC_VER
+#define __builtin_bswap16 _byteswap_ushort
+#define __builtin_bswap32 _byteswap_ulong
+#endif
+
+#define bswap16(x) __builtin_bswap16(x)
+#define bswap32(x) __builtin_bswap32(x)
+#define BSWAP16(x) x = __builtin_bswap16(x)
+#define BSWAP32(x) x = __builtin_bswap32(x)
+#define BSWAP16_MANY(x, n) \
+ for (s32 _i = 0; _i < n; _i++) \
+ BSWAP16((x)[_i])
+
+#define NORETURN __attribute__((noreturn))
+#define UNUSED __attribute__((unused))
+
+typedef struct
+{
+ u32 ckID;
+ u32 ckSize;
+} ChunkHeader;
+
+typedef struct
+{
+ u32 ckID;
+ u32 ckSize;
+ u32 formType;
+} Chunk;
+
+typedef struct
+{
+ s16 numChannels;
+ u16 numFramesH;
+ u16 numFramesL;
+ s16 sampleSize;
+ s16 sampleRate[5]; // 80-bit float
+ u16 compressionTypeH;
+ u16 compressionTypeL;
+} CommonChunk;
+
+typedef struct
+{
+ s16 MarkerID;
+ u16 positionH;
+ u16 positionL;
+} Marker;
+
+typedef struct
+{
+ s16 playMode;
+ s16 beginLoop;
+ s16 endLoop;
+} Loop;
+
+typedef struct
+{
+ s8 baseNote;
+ s8 detune;
+ s8 lowNote;
+ s8 highNote;
+ s8 lowVelocity;
+ s8 highVelocity;
+ s16 gain;
+ Loop sustainLoop;
+ Loop releaseLoop;
+} InstrumentChunk;
+
+typedef struct
+{
+ s32 offset;
+ s32 blockSize;
+} SoundDataChunk;
+
+typedef struct
+{
+ s16 version;
+ s16 order;
+ s16 nEntries;
+} CodeChunk;
+
+typedef struct
+{
+ u32 start;
+ u32 end;
+ u32 count;
+ s16 state[16];
+} ALADPCMloop;
+
+static char usage[] = "input.aifc output.aiff";
+static const char *progname, *infilename;
+static int framesize = 9;
+
+void fail_parse(const char* fmt, ...)
+{
+ char* formatted = NULL;
+ va_list ap;
+ va_start(ap, fmt);
+ int size = vsnprintf(NULL, 0, fmt, ap);
+ va_end(ap);
+ if (size >= 0)
+ {
+ size++;
+ formatted = (char*)malloc(size);
+ if (formatted != NULL)
+ {
+ va_start(ap, fmt);
+ size = vsnprintf(formatted, size, fmt, ap);
+ va_end(ap);
+ if (size < 0)
+ {
+ free(formatted);
+ formatted = NULL;
+ }
+ }
+ }
+
+ if (formatted != NULL)
+ {
+ fprintf(stderr, "%s: %s [%s]\n", progname, formatted, infilename);
+ free(formatted);
+ }
+ exit(1);
+}
+
+
+s32 myrand()
+{
+ static u64 state = 1619236481962341ULL;
+ state *= 3123692312237ULL;
+ state += 1;
+ return state >> 33;
+}
+
+s16 qsample(f32 x, s32 scale)
+{
+ if (x > 0.0f)
+ {
+ return (s16)((x / scale) + 0.4999999);
+ }
+ else
+ {
+ return (s16)((x / scale) - 0.4999999);
+ }
+}
+
+void clamp_to_s16(f32* in, s32* out)
+{
+ f32 llevel = -0x8000;
+ f32 ulevel = 0x7fff;
+
+ for (s32 i = 0; i < 16; i++)
+ {
+ if (in[i] > ulevel)
+ in[i] = ulevel;
+ if (in[i] < llevel)
+ in[i] = llevel;
+
+ if (in[i] > 0.0f)
+ {
+ out[i] = (s32)(in[i] + 0.5);
+ }
+ else
+ {
+ out[i] = (s32)(in[i] - 0.5);
+ }
+ }
+}
+
+s16 clamp_bits(s32 x, s32 bits)
+{
+ s32 lim = 1 << (bits - 1);
+ if (x < -lim)
+ return -lim;
+ if (x > lim - 1)
+ return lim - 1;
+ return x;
+}
+
+s32 readaifccodebook(FILE* fhandle, s32**** table, s16* order, s16* npredictors)
+{
+ BSWAP16(*order);
+ BSWAP16(*npredictors);
+ *table = (s32***)malloc(*npredictors * sizeof(s32**));
+ for (s32 i = 0; i < *npredictors; i++)
+ {
+ (*table)[i] = (s32**)malloc(8 * sizeof(s32*));
+ for (s32 j = 0; j < 8; j++)
+ {
+ (*table)[i][j] = (s32*)malloc((*order + 8) * sizeof(s32));
+ }
+ }
+
+ for (s32 i = 0; i < *npredictors; i++)
+ {
+ s32** table_entry = (*table)[i];
+ for (s32 j = 0; j < *order; j++)
+ {
+ for (s32 k = 0; k < 8; k++)
+ {
+ s16 ts = 0;
+ BSWAP16(ts);
+ table_entry[k][j] = ts;
+ }
+ }
+
+ for (s32 k = 1; k < 8; k++)
+ {
+ table_entry[k][*order] = table_entry[k - 1][*order - 1];
+ }
+
+ table_entry[0][*order] = 1 << 11;
+
+ for (s32 k = 1; k < 8; k++)
+ {
+ s32 j = 0;
+ for (; j < k; j++)
+ {
+ table_entry[j][k + *order] = 0;
+ }
+
+ for (; j < 8; j++)
+ {
+ table_entry[j][k + *order] = table_entry[j - k][*order];
+ }
+ }
+ }
+ return 0;
+}
+
+ALADPCMloop* readlooppoints(FILE* ifile, s16* nloops)
+{
+ BSWAP16(*nloops);
+ ALADPCMloop* al = (ALADPCMloop*)malloc(*nloops * sizeof(ALADPCMloop));
+ for (s32 i = 0; i < *nloops; i++)
+ {
+ BSWAP32(al[i].start);
+ BSWAP32(al[i].end);
+ BSWAP32(al[i].count);
+ BSWAP16_MANY(al[i].state, 16);
+ }
+ return al;
+}
+
+s32 inner_product(s32 length, s32* v1, s32* v2)
+{
+ s32 out = 0;
+ for (s32 i = 0; i < length; i++)
+ {
+ out += v1[i] * v2[i];
+ }
+
+ // Compute "out / 2^11", rounded down.
+ s32 dout = out / (1 << 11);
+ s32 fiout = dout * (1 << 11);
+ return dout - (out - fiout < 0);
+}
+
+void my_decodeframe(u8* frame, s32* decompressed, s32* state, s32 order, s32*** coefTable)
+{
+ s32 ix[16];
+
+ u8 header = frame[0];
+ s32 scale = 1 << (header >> 4);
+ s32 optimalp = header & 0xf;
+
+ if (framesize == 5)
+ {
+ for (s32 i = 0; i < 16; i += 4)
+ {
+ u8 c = frame[1 + i / 4];
+ ix[i] = c >> 6;
+ ix[i + 1] = (c >> 4) & 0x3;
+ ix[i + 2] = (c >> 2) & 0x3;
+ ix[i + 3] = c & 0x3;
+ }
+ }
+ else
+ {
+ for (s32 i = 0; i < 16; i += 2)
+ {
+ u8 c = frame[1 + i / 2];
+ ix[i] = c >> 4;
+ ix[i + 1] = c & 0xf;
+ }
+ }
+
+ for (s32 i = 0; i < 16; i++)
+ {
+ if (framesize == 5)
+ {
+ if (ix[i] >= 2)
+ ix[i] -= 4;
+ }
+ else
+ {
+ if (ix[i] >= 8)
+ ix[i] -= 16;
+ }
+ decompressed[i] = ix[i];
+ ix[i] *= scale;
+ }
+
+ for (s32 j = 0; j < 2; j++)
+ {
+ s32 in_vec[16];
+ if (j == 0)
+ {
+ for (s32 i = 0; i < order; i++)
+ {
+ in_vec[i] = state[16 - order + i];
+ }
+ }
+ else
+ {
+ for (s32 i = 0; i < order; i++)
+ {
+ in_vec[i] = state[8 - order + i];
+ }
+ }
+
+ for (s32 i = 0; i < 8; i++)
+ {
+ s32 ind = j * 8 + i;
+ in_vec[order + i] = ix[ind];
+ state[ind] = inner_product(order + i, coefTable[optimalp][i], in_vec) + ix[ind];
+ }
+ }
+}
+
+void get_bounds(s32* in, s32* decompressed, s32 scale, s32* minVals, s32* maxVals)
+{
+ s32 minv, maxv;
+ if (framesize == 9)
+ {
+ minv = -8;
+ maxv = 7;
+ }
+ else
+ {
+ minv = -2;
+ maxv = 1;
+ }
+ for (s32 i = 0; i < 16; i++)
+ {
+ s32 lo = in[i] - scale / 2;
+ s32 hi = in[i] + scale / 2;
+ lo -= scale;
+ hi += scale;
+ if (decompressed[i] == minv)
+ lo -= scale;
+ else if (decompressed[i] == maxv)
+ hi += scale;
+ minVals[i] = lo;
+ maxVals[i] = hi;
+ }
+}
+
+void write_header(FILE* ofile, const char* id, s32 size)
+{
+ fwrite(id, 4, 1, ofile);
+ BSWAP32(size);
+ fwrite(&size, sizeof(s32), 1, ofile);
+}
+
+char* OldMain(char* infilename)
+{
+ s16 order = -1;
+ s16 nloops = 0;
+ ALADPCMloop* aloops = NULL;
+ s16 npredictors = -1;
+ s32*** coefTable = NULL;
+ s32 state[16];
+ s32 decompressed[16];
+ s32 soundPointer = -1;
+ s32 currPos = 0;
+ s32 nSamples = 0;
+ Chunk FormChunk = Chunk();
+ ChunkHeader Header = ChunkHeader();
+ CommonChunk CommChunk = CommonChunk();
+ InstrumentChunk InstChunk;
+ SoundDataChunk SndDChunk = SoundDataChunk();
+ FILE* ifile = NULL;
+ FILE* ofile = NULL;
+
+ if ((ifile = fopen(infilename, "rb")) == NULL)
+ {
+ fail_parse("AIFF-C file could not be opened");
+ exit(1);
+ }
+
+ memset(&InstChunk, 0, sizeof(InstChunk));
+
+ BSWAP32(FormChunk.ckID);
+ BSWAP32(FormChunk.formType);
+ if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643))
+ { // FORM, AIFC
+ fail_parse("not an AIFF-C file");
+ }
+
+ for (;;)
+ {
+ s32 num = fread(&Header, sizeof(Header), 1, ifile);
+ u32 ts = 0;
+
+ if (num <= 0)
+ break;
+
+ BSWAP32(Header.ckID);
+ BSWAP32(Header.ckSize);
+
+ Header.ckSize++;
+ Header.ckSize &= ~1;
+ s32 offset = ftell(ifile);
+
+ switch (Header.ckID)
+ {
+ case 0x434f4d4d: // COMM
+ {
+ BSWAP16(CommChunk.numChannels);
+ BSWAP16(CommChunk.numFramesH);
+ BSWAP16(CommChunk.numFramesL);
+ BSWAP16(CommChunk.sampleSize);
+ BSWAP16(CommChunk.compressionTypeH);
+ BSWAP16(CommChunk.compressionTypeL);
+ s32 cType = (CommChunk.compressionTypeH << 16) + CommChunk.compressionTypeL;
+ if (cType == 0x56415043 || cType == 0x41445039)
+ { // VAPC or ADP9
+ framesize = 9;
+ }
+ else if (cType == 0x41445035)
+ { // ADP5
+ framesize = 5;
+ }
+ else if (cType == 0x4850434d)
+ { // HPCM
+ framesize = 16;
+ }
+ else
+ {
+ char comprType[5] = {
+ CommChunk.compressionTypeH >> 8, CommChunk.compressionTypeH & 0xFF,
+ CommChunk.compressionTypeL >> 8, CommChunk.compressionTypeL & 0xFF, 0};
+ fail_parse("file is of the wrong compression type [got %s (%08x)]", &comprType,
+ cType);
+ }
+ if (CommChunk.numChannels != 1)
+ {
+ fail_parse("file contains %d channels, only 1 channel supported",
+ CommChunk.numChannels);
+ }
+ if (CommChunk.sampleSize != 16)
+ {
+ fail_parse("file contains %d bit samples, only 16 bit samples supported",
+ CommChunk.sampleSize);
+ }
+
+ nSamples = (CommChunk.numFramesH << 16) + CommChunk.numFramesL;
+
+ // Allow broken input lengths
+ if (nSamples % 16)
+ {
+ nSamples -= (nSamples % 16);
+ }
+
+ if (nSamples % 16 != 0)
+ {
+ fail_parse("number of chunks must be a multiple of 16, found %d with remainder %d",
+ nSamples, nSamples % 16);
+ }
+ }
+ break;
+
+ case 0x53534e44: // SSND
+ BSWAP32(SndDChunk.offset);
+ BSWAP32(SndDChunk.blockSize);
+ assert(SndDChunk.offset == 0);
+ assert(SndDChunk.blockSize == 0);
+ soundPointer = ftell(ifile);
+ break;
+
+ case 0x4150504c: // APPL
+ BSWAP32(ts);
+ if (ts == 0x73746f63)
+ { // stoc
+ u8 len = 0;
+ if (len == 11)
+ {
+ char ChunkName[12];
+ s16 version;
+ ChunkName[11] = '\0';
+ if (strcmp("VADPCMCODES", ChunkName) == 0)
+ {
+ BSWAP16(version);
+ if (version != 1)
+ {
+ fail_parse("Unknown codebook chunk version");
+ }
+ readaifccodebook(ifile, &coefTable, &order, &npredictors);
+ }
+ else if (strcmp("VADPCMLOOPS", ChunkName) == 0)
+ {
+ BSWAP16(version);
+ if (version != 1)
+ {
+ fail_parse("Unknown loop chunk version");
+ }
+ aloops = readlooppoints(ifile, &nloops);
+ if (nloops != 1)
+ {
+ fail_parse("Only a single loop supported");
+ }
+ }
+ }
+ }
+ break;
+ }
+
+ fseek(ifile, offset + Header.ckSize, SEEK_SET);
+ }
+
+ if (coefTable == NULL)
+ {
+ fail_parse("Codebook missing from bitstream");
+ }
+
+ for (s32 i = 0; i < order; i++)
+ {
+ state[15 - i] = 0;
+ }
+
+ u32 outputBytes = nSamples * sizeof(s16);
+ u8* outputBuf = (u8*)malloc(outputBytes);
+
+ fseek(ifile, soundPointer, SEEK_SET);
+ s32 fails = 0;
+ while (currPos < nSamples)
+ {
+ u8 input[9];
+ u8 encoded[9];
+ s32 lastState[16];
+ s32 decoded[16];
+ s16 guess[16];
+ s16 origGuess[16];
+
+ memcpy(lastState, state, sizeof(state));
+
+ // Decode for real
+ my_decodeframe(input, decompressed, state, order, coefTable);
+ memcpy(decoded, state, sizeof(state));
+
+ // Create a guess from that, by clamping to 16 bits
+ for (s32 i = 0; i < 16; i++)
+ {
+ origGuess[i] = clamp_bits(state[i], 16);
+ }
+
+ memcpy(state, decoded, sizeof(state));
+ memcpy(outputBuf + currPos * 2, decoded, sizeof(decoded));
+ currPos += 16;
+ }
+ if (fails)
+ {
+ fprintf(stderr, "%s %d\n", infilename, fails);
+ }
+
+ // Write an incomplete file header. We'll fill in the size later.
+ fwrite("FORM\0\0\0\0AIFF", 12, 1, ofile);
+
+ // Subtract 4 from the COMM size to skip the compression field.
+ write_header(ofile, "COMM", sizeof(CommonChunk) - 4);
+ CommChunk.numFramesH = nSamples >> 16;
+ CommChunk.numFramesL = nSamples & 0xffff;
+ BSWAP16(CommChunk.numChannels);
+ BSWAP16(CommChunk.numFramesH);
+ BSWAP16(CommChunk.numFramesL);
+ BSWAP16(CommChunk.sampleSize);
+ fwrite(&CommChunk, sizeof(CommonChunk) - 4, 1, ofile);
+
+ if (nloops > 0)
+ {
+ s32 startPos = aloops[0].start, endPos = aloops[0].end;
+ const char* markerNames[2] = {"start", "end"};
+ Marker markers[2] = {{1, startPos >> 16, startPos & 0xffff},
+ {2, endPos >> 16, endPos & 0xffff}};
+ write_header(ofile, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3);
+ s16 numMarkers = bswap16(2);
+ fwrite(&numMarkers, sizeof(s16), 1, ofile);
+ for (s32 i = 0; i < 2; i++)
+ {
+ u8 len = (u8)strlen(markerNames[i]);
+ BSWAP16(markers[i].MarkerID);
+ BSWAP16(markers[i].positionH);
+ BSWAP16(markers[i].positionL);
+ fwrite(&markers[i], sizeof(Marker), 1, ofile);
+ fwrite(&len, 1, 1, ofile);
+ fwrite(markerNames[i], len, 1, ofile);
+ }
+
+ write_header(ofile, "INST", sizeof(InstrumentChunk));
+ InstChunk.sustainLoop.playMode = bswap16(1);
+ InstChunk.sustainLoop.beginLoop = bswap16(1);
+ InstChunk.sustainLoop.endLoop = bswap16(2);
+ InstChunk.releaseLoop.playMode = 0;
+ InstChunk.releaseLoop.beginLoop = 0;
+ InstChunk.releaseLoop.endLoop = 0;
+ fwrite(&InstChunk, sizeof(InstrumentChunk), 1, ofile);
+ }
+
+ // Save the coefficient table for use when encoding. Ideally this wouldn't
+ // be needed and "tabledesign -s 1" would generate the right table, but in
+ // practice it's difficult to adjust samples to make that happen.
+ write_header(ofile, "APPL", 4 + 12 + sizeof(CodeChunk) + npredictors * order * 8 * 2);
+ fwrite("stoc", 4, 1, ofile);
+ CodeChunk cChunk;
+ cChunk.version = bswap16(1);
+ cChunk.order = bswap16(order);
+ cChunk.nEntries = bswap16(npredictors);
+ fwrite("\x0bVADPCMCODES", 12, 1, ofile);
+ fwrite(&cChunk, sizeof(CodeChunk), 1, ofile);
+ for (s32 i = 0; i < npredictors; i++)
+ {
+ for (s32 j = 0; j < order; j++)
+ {
+ for (s32 k = 0; k < 8; k++)
+ {
+ s16 ts = bswap16(coefTable[i][k][j]);
+ fwrite(&ts, sizeof(s16), 1, ofile);
+ }
+ }
+ }
+
+ write_header(ofile, "SSND", outputBytes + 8);
+ SndDChunk.offset = 0;
+ SndDChunk.blockSize = 0;
+ fwrite(&SndDChunk, sizeof(SoundDataChunk), 1, ofile);
+ fwrite(outputBuf, outputBytes, 1, ofile);
+
+ // Fix the size in the header
+ s32 fileSize = bswap32(ftell(ofile) - 8);
+ fseek(ofile, 4, SEEK_SET);
+ fwrite(&fileSize, 4, 1, ofile);
+
+ fclose(ifile);
+ fclose(ofile);
+ return 0;
+} \ No newline at end of file
diff --git a/ZAPDTR/ZAPD/ZResource.h b/ZAPDTR/ZAPD/ZResource.h
index 82709aec0..8b1055a4b 100644
--- a/ZAPDTR/ZAPD/ZResource.h
+++ b/ZAPDTR/ZAPD/ZResource.h
@@ -50,7 +50,8 @@ enum class ZResourceType
TextureAnimationParams,
Vector,
Vertex,
- Text
+ Text,
+ Audio
};
class ResourceAttribute
diff --git a/ZAPDTR/ZAPD/ZRom.cpp b/ZAPDTR/ZAPD/ZRom.cpp
index 2a1d3c8a1..a311714dd 100644
--- a/ZAPDTR/ZAPD/ZRom.cpp
+++ b/ZAPDTR/ZAPD/ZRom.cpp
@@ -191,6 +191,8 @@ ZRom::ZRom(std::string romPath)
}
else
files[lines[i]] = outData;
+
+ //File::WriteAllBytes(StringHelper::Sprintf("baserom/%s", lines[i]), files[lines[i]]);
}
int bp = 0;