summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLywx <kiritodev01@gmail.com>2023-09-16 04:01:24 -0600
committerGitHub <noreply@github.com>2023-09-16 04:01:24 -0600
commitae8487a4adc5d6d33c47d41e3a40d3c67ddb1e45 (patch)
treee03627371fc7423c684631ed7eee68d697709e0f
parentf5cbd0056d601e4adaf5ed9006192dd510226ee3 (diff)
parent98b6d598324fdcb499a2cc4d37a7a6fcd19e8ead (diff)
Merge pull request #1 from KiritoDv/feature/audio
Implemented full audio extraction
-rw-r--r--assets.json116
-rw-r--r--banks_table.h129
-rw-r--r--lib/binarytools/BinaryReader.cpp31
-rw-r--r--lib/binarytools/BinaryReader.h3
-rw-r--r--lib/binarytools/BinaryWriter.cpp13
-rw-r--r--lib/binarytools/BinaryWriter.h3
-rw-r--r--lib/hj/pyutils.h65
-rw-r--r--lib/hj/zip.h60
-rw-r--r--samples_table.h717
-rw-r--r--sequences.json37
-rw-r--r--sequences_table.h141
-rw-r--r--src/Companion.cpp20
-rw-r--r--src/audio/AIFCDecode.cpp656
-rw-r--r--src/audio/AIFCDecode.h6
-rw-r--r--src/audio/AudioManager.cpp664
-rw-r--r--src/audio/AudioManager.h161
-rw-r--r--src/audio/samples_table.h722
-rw-r--r--src/factories/AudioFactory.cpp191
-rw-r--r--src/factories/AudioFactory.h9
-rw-r--r--src/factories/BlobFactory.cpp6
-rw-r--r--src/factories/RawFactory.h3
-rw-r--r--src/factories/ResourceType.h3
-rw-r--r--tools/gen_banks.js37
-rw-r--r--tools/gen_bankset.js23
-rw-r--r--tools/gen_samples.js37
-rw-r--r--tools/m64test.js32
26 files changed, 3832 insertions, 53 deletions
diff --git a/assets.json b/assets.json
index 2db3c3b..eb6a14e 100644
--- a/assets.json
+++ b/assets.json
@@ -525,8 +525,6 @@
"actors/yoshi_egg/yoshi_egg_5_unused.rgba16.png": [32,32,2048,{"jp":[1215456,32696],"us":[1222624,32696],"eu":[1094592,32696],"sh":[1071104,32696]}],
"actors/yoshi_egg/yoshi_egg_6_unused.rgba16.png": [32,32,2048,{"jp":[1215456,34744],"us":[1222624,34744],"eu":[1094592,34744],"sh":[1071104,34744]}],
"actors/yoshi_egg/yoshi_egg_7_unused.rgba16.png": [32,32,2048,{"jp":[1215456,36792],"us":[1222624,36792],"eu":[1094592,36792],"sh":[1071104,36792]}],
-"sound/sequences.aud": [114432, { "us": [8063072] }],
-"sound/bank_sets.aud": [159, { "us": [8177185] }],
"assets/demos/bbh.bin": [988,{"jp":[5733368],"us":[5741664],"eu":[5620584],"sh":[5589632]}],
"assets/demos/bitdw.bin": [1412,{"us":[5747100],"sh":[5595068]}],
"assets/demos/ccm.bin": [1320,{"jp":[5734356],"us":[5742652],"eu":[5621572],"sh":[5590620]}],
@@ -1088,40 +1086,86 @@
"sound/sequences/sh/20_cutscene_ending.m64": [1887,{"sh":[7981824]}],
"sound/sequences/sh/21_menu_file_select.m64": [786,{"sh":[7983712]}],
"sound/sequences/sh/22_cutscene_lakitu.m64": [317,{"sh":[7984512]}],
-"sound/sequences/us/01_cutscene_collect_star.m64": [619,{"us":[8076816]}],
-"sound/sequences/us/02_menu_title_screen.m64": [8254,{"us":[8077440]}],
-"sound/sequences/us/03_level_grass.m64": [5122,{"us":[8085696]}],
-"sound/sequences/us/04_level_inside_castle.m64": [2494,{"us":[8090832]}],
-"sound/sequences/us/05_level_water.m64": [4780,{"us":[8093328]}],
-"sound/sequences/us/06_level_hot.m64": [2451,{"us":[8098112]}],
-"sound/sequences/us/07_level_boss_koopa.m64": [3418,{"us":[8100576]}],
-"sound/sequences/us/08_level_snow.m64": [8143,{"us":[8104000]}],
-"sound/sequences/us/09_level_slide.m64": [7432,{"us":[8112144]}],
-"sound/sequences/us/0A_level_spooky.m64": [5674,{"us":[8119584]}],
-"sound/sequences/us/0B_event_piranha_plant.m64": [1395,{"us":[8125264]}],
-"sound/sequences/us/0C_level_underground.m64": [4887,{"us":[8126672]}],
-"sound/sequences/us/0D_menu_star_select.m64": [134,{"us":[8131568]}],
-"sound/sequences/us/0E_event_powerup.m64": [3129,{"us":[8131712]}],
-"sound/sequences/us/0F_event_metal_cap.m64": [2770,{"us":[8134848]}],
-"sound/sequences/us/10_event_koopa_message.m64": [552,{"us":[8137632]}],
-"sound/sequences/us/11_level_koopa_road.m64": [4741,{"us":[8138192]}],
-"sound/sequences/us/12_event_high_score.m64": [271,{"us":[8142944]}],
-"sound/sequences/us/13_event_merry_go_round.m64": [1657,{"us":[8143216]}],
-"sound/sequences/us/14_event_race.m64": [197,{"us":[8144880]}],
-"sound/sequences/us/15_cutscene_star_spawn.m64": [644,{"us":[8145088]}],
-"sound/sequences/us/16_event_boss.m64": [3435,{"us":[8145744]}],
-"sound/sequences/us/17_cutscene_collect_key.m64": [671,{"us":[8149184]}],
-"sound/sequences/us/18_event_endless_stairs.m64": [1777,{"us":[8149856]}],
-"sound/sequences/us/19_level_boss_koopa_final.m64": [3515,{"us":[8151648]}],
-"sound/sequences/us/1A_cutscene_credits.m64": [14313,{"us":[8155168]}],
-"sound/sequences/us/1B_event_solve_puzzle.m64": [216,{"us":[8169488]}],
-"sound/sequences/us/1C_event_toad_message.m64": [208,{"us":[8169712]}],
-"sound/sequences/us/1D_event_peach_message.m64": [432,{"us":[8169920]}],
-"sound/sequences/us/1E_cutscene_intro.m64": [1764,{"us":[8170352]}],
-"sound/sequences/us/1F_cutscene_victory.m64": [2058,{"us":[8172128]}],
-"sound/sequences/us/20_cutscene_ending.m64": [1882,{"us":[8174192]}],
-"sound/sequences/us/21_menu_file_select.m64": [781,{"us":[8176080]}],
-"sound/sequences/us/22_cutscene_lakitu.m64": [313,{"us":[8176864]}],
+"sound/sequences/us/00_sound_player.m64": [13452,{"us":[8063360], "banks": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}],
+"sound/sequences/us/01_cutscene_collect_star.m64": [619,{"us":[8076816], "banks": [34]}],
+"sound/sequences/us/02_menu_title_screen.m64": [8254,{"us":[8077440], "banks": [17]}],
+"sound/sequences/us/03_level_grass.m64": [5122,{"us":[8085696], "banks": [34]}],
+"sound/sequences/us/04_level_inside_castle.m64": [2494,{"us":[8090832], "banks": [14]}],
+"sound/sequences/us/05_level_water.m64": [4780,{"us":[8093328], "banks": [19]}],
+"sound/sequences/us/06_level_hot.m64": [2451,{"us":[8098112], "banks": [15]}],
+"sound/sequences/us/07_level_boss_koopa.m64": [3418,{"us":[8100576], "banks": [18]}],
+"sound/sequences/us/08_level_snow.m64": [8143,{"us":[8104000], "banks": [11]}],
+"sound/sequences/us/09_level_slide.m64": [7432,{"us":[8112144], "banks": [13]}],
+"sound/sequences/us/0A_level_spooky.m64": [5674,{"us":[8119584], "banks": [33, 16]}],
+"sound/sequences/us/0B_event_piranha_plant.m64": [1395,{"us":[8125264], "banks": [20]}],
+"sound/sequences/us/0C_level_underground.m64": [4887,{"us":[8126672], "banks": [21]}],
+"sound/sequences/us/0D_menu_star_select.m64": [134,{"us":[8131568], "banks": [22]}],
+"sound/sequences/us/0E_event_powerup.m64": [3129,{"us":[8131712], "banks": [23]}],
+"sound/sequences/us/0F_event_metal_cap.m64": [2770,{"us":[8134848], "banks": [24]}],
+"sound/sequences/us/10_event_koopa_message.m64": [552,{"us":[8137632], "banks": [18]}],
+"sound/sequences/us/11_level_koopa_road.m64": [4741,{"us":[8138192], "banks": [25]}],
+"sound/sequences/us/12_event_high_score.m64": [271,{"us":[8142944], "banks": [31]}],
+"sound/sequences/us/13_event_merry_go_round.m64": [1657,{"us":[8143216], "banks": [33]}],
+"sound/sequences/us/14_event_race.m64": [197,{"us":[8144880], "banks": [26]}],
+"sound/sequences/us/15_cutscene_star_spawn.m64": [644,{"us":[8145088], "banks": [14]}],
+"sound/sequences/us/16_event_boss.m64": [3435,{"us":[8145744], "banks": [27]}],
+"sound/sequences/us/17_cutscene_collect_key.m64": [671,{"us":[8149184], "banks": [26]}],
+"sound/sequences/us/18_event_endless_stairs.m64": [1777,{"us":[8149856], "banks": [28]}],
+"sound/sequences/us/19_level_boss_koopa_final.m64": [3515,{"us":[8151648], "banks": [29]}],
+"sound/sequences/us/1A_cutscene_credits.m64": [14313,{"us":[8155168], "banks": [37]}],
+"sound/sequences/us/1B_event_solve_puzzle.m64": [216,{"us":[8169488], "banks": [20]}],
+"sound/sequences/us/1C_event_toad_message.m64": [208,{"us":[8169712], "banks": [32]}],
+"sound/sequences/us/1D_event_peach_message.m64": [432,{"us":[8169920], "banks": [30]}],
+"sound/sequences/us/1E_cutscene_intro.m64": [1764,{"us":[8170352], "banks": [27]}],
+"sound/sequences/us/1F_cutscene_victory.m64": [2058,{"us":[8172128], "banks": [26]}],
+"sound/sequences/us/20_cutscene_ending.m64": [1882,{"us":[8174192], "banks": [35]}],
+"sound/sequences/us/21_menu_file_select.m64": [781,{"us":[8176080], "banks": [36]}],
+"sound/sequences/us/22_cutscene_lakitu.m64": [313,{"us":[8176864], "banks": [27]}],
+"sound/bank_sets.bset": [159, { "us": [8177185] }],
+"@sound_data": {
+ "us": {
+ "sound_ctl": [5748512, 97856],
+ "sound_tbl": [5846368, 2216704]
+ }
+},
+"sound/banks/us/00_bank.bnk": {"us": [0]},
+"sound/banks/us/01_bank.bnk": {"us": [1]},
+"sound/banks/us/02_bank.bnk": {"us": [2]},
+"sound/banks/us/03_bank.bnk": {"us": [3]},
+"sound/banks/us/04_bank.bnk": {"us": [4]},
+"sound/banks/us/05_bank.bnk": {"us": [5]},
+"sound/banks/us/06_bank.bnk": {"us": [6]},
+"sound/banks/us/07_bank.bnk": {"us": [7]},
+"sound/banks/us/08_bank.bnk": {"us": [8]},
+"sound/banks/us/09_bank.bnk": {"us": [9]},
+"sound/banks/us/0A_bank.bnk": {"us": [10]},
+"sound/banks/us/0B_bank.bnk": {"us": [11]},
+"sound/banks/us/0C_bank.bnk": {"us": [12]},
+"sound/banks/us/0D_bank.bnk": {"us": [13]},
+"sound/banks/us/0E_bank.bnk": {"us": [14]},
+"sound/banks/us/0F_bank.bnk": {"us": [15]},
+"sound/banks/us/10_bank.bnk": {"us": [16]},
+"sound/banks/us/11_bank.bnk": {"us": [17]},
+"sound/banks/us/12_bank.bnk": {"us": [18]},
+"sound/banks/us/13_bank.bnk": {"us": [19]},
+"sound/banks/us/14_bank.bnk": {"us": [20]},
+"sound/banks/us/15_bank.bnk": {"us": [21]},
+"sound/banks/us/16_bank.bnk": {"us": [22]},
+"sound/banks/us/17_bank.bnk": {"us": [23]},
+"sound/banks/us/18_bank.bnk": {"us": [24]},
+"sound/banks/us/19_bank.bnk": {"us": [25]},
+"sound/banks/us/1A_bank.bnk": {"us": [26]},
+"sound/banks/us/1B_bank.bnk": {"us": [27]},
+"sound/banks/us/1C_bank.bnk": {"us": [28]},
+"sound/banks/us/1D_bank.bnk": {"us": [29]},
+"sound/banks/us/1E_bank.bnk": {"us": [30]},
+"sound/banks/us/1F_bank.bnk": {"us": [31]},
+"sound/banks/us/20_bank.bnk": {"us": [32]},
+"sound/banks/us/21_bank.bnk": {"us": [33]},
+"sound/banks/us/22_bank.bnk": {"us": [34]},
+"sound/banks/us/23_bank.bnk": {"us": [35]},
+"sound/banks/us/24_bank.bnk": {"us": [36]},
+"sound/banks/us/25_bank.bnk": {"us": [37]},
"textures/cave/hmc_textures.00000.rgba16.png": [32,64,4096,{"jp":[3432432,0],"us":[3439184,0],"eu":[3312784,0],"sh":[3287152,0]}],
"textures/cave/hmc_textures.01000.rgba16.png": [32,32,2048,{"jp":[3432432,4096],"us":[3439184,4096],"eu":[3312784,4096],"sh":[3287152,4096]}],
"textures/cave/hmc_textures.01800.rgba16.png": [32,64,4096,{"jp":[3432432,6144],"us":[3439184,6144],"eu":[3312784,6144],"sh":[3287152,6144]}],
diff --git a/banks_table.h b/banks_table.h
new file mode 100644
index 0000000..1c05cb1
--- /dev/null
+++ b/banks_table.h
@@ -0,0 +1,129 @@
+#pragma once
+#include "align_asset_macro.h"
+
+#define dgBank00 "__OTR__sound/banks/us/00_bank"
+static const ALIGN_ASSET(2) char gBank00[] = dgBank00;
+
+#define dgBank01 "__OTR__sound/banks/us/01_bank"
+static const ALIGN_ASSET(2) char gBank01[] = dgBank01;
+
+#define dgBank02 "__OTR__sound/banks/us/02_bank"
+static const ALIGN_ASSET(2) char gBank02[] = dgBank02;
+
+#define dgBank03 "__OTR__sound/banks/us/03_bank"
+static const ALIGN_ASSET(2) char gBank03[] = dgBank03;
+
+#define dgBank04 "__OTR__sound/banks/us/04_bank"
+static const ALIGN_ASSET(2) char gBank04[] = dgBank04;
+
+#define dgBank05 "__OTR__sound/banks/us/05_bank"
+static const ALIGN_ASSET(2) char gBank05[] = dgBank05;
+
+#define dgBank06 "__OTR__sound/banks/us/06_bank"
+static const ALIGN_ASSET(2) char gBank06[] = dgBank06;
+
+#define dgBank07 "__OTR__sound/banks/us/07_bank"
+static const ALIGN_ASSET(2) char gBank07[] = dgBank07;
+
+#define dgBank08 "__OTR__sound/banks/us/08_bank"
+static const ALIGN_ASSET(2) char gBank08[] = dgBank08;
+
+#define dgBank09 "__OTR__sound/banks/us/09_bank"
+static const ALIGN_ASSET(2) char gBank09[] = dgBank09;
+
+#define dgBank0A "__OTR__sound/banks/us/0A_bank"
+static const ALIGN_ASSET(2) char gBank0A[] = dgBank0A;
+
+#define dgBank0B "__OTR__sound/banks/us/0B_bank"
+static const ALIGN_ASSET(2) char gBank0B[] = dgBank0B;
+
+#define dgBank0C "__OTR__sound/banks/us/0C_bank"
+static const ALIGN_ASSET(2) char gBank0C[] = dgBank0C;
+
+#define dgBank0D "__OTR__sound/banks/us/0D_bank"
+static const ALIGN_ASSET(2) char gBank0D[] = dgBank0D;
+
+#define dgBank0E "__OTR__sound/banks/us/0E_bank"
+static const ALIGN_ASSET(2) char gBank0E[] = dgBank0E;
+
+#define dgBank0F "__OTR__sound/banks/us/0F_bank"
+static const ALIGN_ASSET(2) char gBank0F[] = dgBank0F;
+
+#define dgBank10 "__OTR__sound/banks/us/10_bank"
+static const ALIGN_ASSET(2) char gBank10[] = dgBank10;
+
+#define dgBank11 "__OTR__sound/banks/us/11_bank"
+static const ALIGN_ASSET(2) char gBank11[] = dgBank11;
+
+#define dgBank12 "__OTR__sound/banks/us/12_bank"
+static const ALIGN_ASSET(2) char gBank12[] = dgBank12;
+
+#define dgBank13 "__OTR__sound/banks/us/13_bank"
+static const ALIGN_ASSET(2) char gBank13[] = dgBank13;
+
+#define dgBank14 "__OTR__sound/banks/us/14_bank"
+static const ALIGN_ASSET(2) char gBank14[] = dgBank14;
+
+#define dgBank15 "__OTR__sound/banks/us/15_bank"
+static const ALIGN_ASSET(2) char gBank15[] = dgBank15;
+
+#define dgBank16 "__OTR__sound/banks/us/16_bank"
+static const ALIGN_ASSET(2) char gBank16[] = dgBank16;
+
+#define dgBank17 "__OTR__sound/banks/us/17_bank"
+static const ALIGN_ASSET(2) char gBank17[] = dgBank17;
+
+#define dgBank18 "__OTR__sound/banks/us/18_bank"
+static const ALIGN_ASSET(2) char gBank18[] = dgBank18;
+
+#define dgBank19 "__OTR__sound/banks/us/19_bank"
+static const ALIGN_ASSET(2) char gBank19[] = dgBank19;
+
+#define dgBank1A "__OTR__sound/banks/us/1A_bank"
+static const ALIGN_ASSET(2) char gBank1A[] = dgBank1A;
+
+#define dgBank1B "__OTR__sound/banks/us/1B_bank"
+static const ALIGN_ASSET(2) char gBank1B[] = dgBank1B;
+
+#define dgBank1C "__OTR__sound/banks/us/1C_bank"
+static const ALIGN_ASSET(2) char gBank1C[] = dgBank1C;
+
+#define dgBank1D "__OTR__sound/banks/us/1D_bank"
+static const ALIGN_ASSET(2) char gBank1D[] = dgBank1D;
+
+#define dgBank1E "__OTR__sound/banks/us/1E_bank"
+static const ALIGN_ASSET(2) char gBank1E[] = dgBank1E;
+
+#define dgBank1F "__OTR__sound/banks/us/1F_bank"
+static const ALIGN_ASSET(2) char gBank1F[] = dgBank1F;
+
+#define dgBank20 "__OTR__sound/banks/us/20_bank"
+static const ALIGN_ASSET(2) char gBank20[] = dgBank20;
+
+#define dgBank21 "__OTR__sound/banks/us/21_bank"
+static const ALIGN_ASSET(2) char gBank21[] = dgBank21;
+
+#define dgBank22 "__OTR__sound/banks/us/22_bank"
+static const ALIGN_ASSET(2) char gBank22[] = dgBank22;
+
+#define dgBank23 "__OTR__sound/banks/us/23_bank"
+static const ALIGN_ASSET(2) char gBank23[] = dgBank23;
+
+#define dgBank24 "__OTR__sound/banks/us/24_bank"
+static const ALIGN_ASSET(2) char gBank24[] = dgBank24;
+
+#define dgBank25 "__OTR__sound/banks/us/25_bank"
+static const ALIGN_ASSET(2) char gBank25[] = dgBank25;
+
+static const char* gBankTable[] = {
+ gBank00, gBank01, gBank02, gBank03,
+ gBank04, gBank05, gBank06, gBank07,
+ gBank08, gBank09, gBank0A, gBank0B,
+ gBank0C, gBank0D, gBank0E, gBank0F,
+ gBank10, gBank11, gBank12, gBank13,
+ gBank14, gBank15, gBank16, gBank17,
+ gBank18, gBank19, gBank1A, gBank1B,
+ gBank1C, gBank1D, gBank1E, gBank1F,
+ gBank20, gBank21, gBank22, gBank23,
+ gBank24, gBank25,
+};
diff --git a/lib/binarytools/BinaryReader.cpp b/lib/binarytools/BinaryReader.cpp
index 3aff001..f802885 100644
--- a/lib/binarytools/BinaryReader.cpp
+++ b/lib/binarytools/BinaryReader.cpp
@@ -2,6 +2,7 @@
#include "MemoryStream.h"
#include <cmath>
#include <stdexcept>
+#include <locale>
LUS::BinaryReader::BinaryReader(char* nBuffer, size_t nBufferSize) {
mStream = std::make_shared<MemoryStream>(nBuffer, nBufferSize);
@@ -57,7 +58,6 @@ int16_t LUS::BinaryReader::ReadInt16() {
if (mEndianness != Endianness::Native) {
result = BSWAP16(result);
}
-
return result;
}
@@ -113,6 +113,28 @@ uint64_t LUS::BinaryReader::ReadUInt64() {
return result;
}
+unsigned short LUS::BinaryReader::ReadUShort() {
+ unsigned short result = 0;
+ mStream->Read((char*)&result, sizeof(unsigned short));
+
+ if (mEndianness != Endianness::Native) {
+ result = BSWAP16(result);
+ }
+
+ return result;
+}
+
+short LUS::BinaryReader::ReadShort() {
+ short result = 0;
+ mStream->Read((char*)&result, sizeof(short));
+
+ if (mEndianness != Endianness::Native) {
+ result = BSWAP16(result);
+ }
+
+ return result;
+}
+
float LUS::BinaryReader::ReadFloat() {
float result = NAN;
@@ -169,6 +191,7 @@ std::string LUS::BinaryReader::ReadString() {
for (int i = 0; i < numChars; i++) {
res += ReadChar();
}
+
return res;
}
@@ -188,6 +211,10 @@ std::string LUS::BinaryReader::ReadCString() {
return res;
}
+size_t LUS::BinaryReader::GetLength() {
+ return mStream->GetLength();
+}
+
std::vector<char> LUS::BinaryReader::ToVector() {
return mStream->ToVector();
-}
+} \ No newline at end of file
diff --git a/lib/binarytools/BinaryReader.h b/lib/binarytools/BinaryReader.h
index 59eeb52..02e65cc 100644
--- a/lib/binarytools/BinaryReader.h
+++ b/lib/binarytools/BinaryReader.h
@@ -23,6 +23,7 @@ class BinaryReader {
void Seek(int32_t offset, SeekOffsetType seekType);
uint32_t GetBaseAddress();
+ size_t GetLength();
void Read(int32_t length);
void Read(char* buffer, int32_t length);
@@ -34,6 +35,8 @@ class BinaryReader {
uint16_t ReadUInt16();
uint32_t ReadUInt32();
uint64_t ReadUInt64();
+ unsigned short ReadUShort();
+ short ReadShort();
float ReadFloat();
double ReadDouble();
std::string ReadString();
diff --git a/lib/binarytools/BinaryWriter.cpp b/lib/binarytools/BinaryWriter.cpp
index 362824f..6e0140f 100644
--- a/lib/binarytools/BinaryWriter.cpp
+++ b/lib/binarytools/BinaryWriter.cpp
@@ -132,10 +132,11 @@ void LUS::BinaryWriter::Write(double value) {
mStream->Write((char*)&value, sizeof(double));
}
-void LUS::BinaryWriter::Write(const std::string& str) {
- int strLen = str.size();
- Write(strLen);
-
+void LUS::BinaryWriter::Write(const std::string& str, bool writeLength) {
+ if(writeLength){
+ int strLen = str.size();
+ Write(strLen);
+ }
for (char c : str) {
mStream->WriteByte(c);
}
@@ -145,6 +146,10 @@ void LUS::BinaryWriter::Write(char* srcBuffer, size_t length) {
mStream->Write(srcBuffer, length);
}
+void LUS::BinaryWriter::WriteByte(char value) {
+ mStream->WriteByte(value);
+}
+
std::vector<char> LUS::BinaryWriter::ToVector() {
return mStream->ToVector();
}
diff --git a/lib/binarytools/BinaryWriter.h b/lib/binarytools/BinaryWriter.h
index fbd4f65..dca683f 100644
--- a/lib/binarytools/BinaryWriter.h
+++ b/lib/binarytools/BinaryWriter.h
@@ -33,8 +33,9 @@ class BinaryWriter {
void Write(uint64_t value);
void Write(float value);
void Write(double value);
- void Write(const std::string& str);
+ void Write(const std::string& str, bool writeLength = true);
void Write(char* srcBuffer, size_t length);
+ void WriteByte(char value);
std::vector<char> ToVector();
diff --git a/lib/hj/pyutils.h b/lib/hj/pyutils.h
new file mode 100644
index 0000000..f34c1d8
--- /dev/null
+++ b/lib/hj/pyutils.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <vector>
+#include <unordered_map>
+
+namespace PyUtils {
+template<typename T>
+std::vector<T> slice(std::vector<T> const &v, uint32_t m, uint32_t n = -1) {
+ auto first = v.cbegin() + m;
+ auto last = n == -1 ? v.cend() : v.cbegin() + n;
+
+ std::vector<T> vec(first, last);
+ return vec;
+}
+
+std::vector<uint32_t> range(uint32_t start, uint32_t end);
+
+template<typename T>
+T max(std::vector<T> const &v) {
+ T max = v[0];
+ for (auto const &value: v) {
+ if (value > max) {
+ max = value;
+ }
+ }
+ return max;
+}
+template<typename T>
+T min(std::vector<T> const &v) {
+ T min = v[0];
+ for (auto const &value: v) {
+ if (value < min) {
+ min = value;
+ }
+ }
+ return min;
+}
+
+template<typename T, typename X>
+std::vector<T> keys(std::unordered_map<T, X> const &map) {
+ std::vector<T> result;
+ for (auto const &pair: map) {
+ result.push_back(pair.first);
+ }
+ return result;
+}
+template<typename T, typename X>
+std::vector<T> keys(std::map<T, X> const &map) {
+ std::vector<T> result;
+ for (auto const &pair: map) {
+ result.push_back(pair.first);
+ }
+ return result;
+}
+}
+
+template <typename T>
+std::vector<T> operator+(std::vector<T> const &x, std::vector<T> const &y)
+{
+ std::vector<T> vec;
+ vec.reserve(x.size() + y.size());
+ vec.insert(vec.end(), x.begin(), x.end());
+ vec.insert(vec.end(), y.begin(), y.end());
+ return vec;
+} \ No newline at end of file
diff --git a/lib/hj/zip.h b/lib/hj/zip.h
new file mode 100644
index 0000000..0cc7ee2
--- /dev/null
+++ b/lib/hj/zip.h
@@ -0,0 +1,60 @@
+#pragma once
+#include <algorithm>
+#include <any>
+#include <iostream>
+#include <vector>
+#include <tuple>
+
+template<class TupType, size_t... I>
+void print_tuple(const TupType& _tup, std::index_sequence<I...>)
+{
+ std::cout << "(";
+ (..., (std::cout << (I == 0? "" : ", ") << std::get<I>(_tup)));
+ std::cout << ")\n";
+}
+
+template<class... T>
+void print_tuple(const std::tuple<T...>& _tup)
+{
+ print_tuple(_tup, std::make_index_sequence<sizeof...(T)>());
+}
+
+template<typename T>
+void variatic_min(std::vector<T> v, int &m) {
+ if (m > v.size()) m = v.size();
+}
+
+template<int N, typename... Ts>
+using NthTypeOf = typename std::tuple_element<N, std::tuple<Ts...>>::type;
+
+template <typename... Result, std::size_t... Indices>
+auto vec_to_tup_helper(const std::vector<std::any>& v, std::index_sequence<Indices...>) {
+ return std::make_tuple(
+ std::any_cast<NthTypeOf<Indices, Result...>>(v[Indices])...
+ );
+}
+
+template <typename ...Result>
+std::tuple<Result...> vec_to_tup(std::vector<std::any>& values) {
+ return vec_to_tup_helper<Result...>(values, std::make_index_sequence<sizeof...(Result)>());
+}
+
+template <typename T>
+void celem_at(std::vector<T> v, int i, std::vector<std::any> &r) {
+ r.push_back(v[i]);
+}
+
+template<typename... Types>
+std::vector<std::tuple<Types...>> zip(std::vector<Types>... args) {
+ int m = 0xFFFFFFFF;
+ std::vector<std::tuple<Types...>> res;
+
+ (variatic_min(args, m), ...);
+
+ for (int i = 0; i < m; i++) {
+ std::vector<std::any> vaux;
+ (celem_at(args, i, vaux), ...);
+ res.push_back(vec_to_tup<Types...>(vaux));
+ }
+ return res;
+} \ No newline at end of file
diff --git a/samples_table.h b/samples_table.h
new file mode 100644
index 0000000..5f1a3ae
--- /dev/null
+++ b/samples_table.h
@@ -0,0 +1,717 @@
+#pragma once
+#include "align_asset_macro.h"
+
+#define dgSample00 "__OTR__sound/samples/sfx_1/00_twirl"
+static const ALIGN_ASSET(2) char gSample00[] = dgSample00;
+
+#define dgSample01 "__OTR__sound/samples/sfx_1/01_brushing"
+static const ALIGN_ASSET(2) char gSample01[] = dgSample01;
+
+#define dgSample02 "__OTR__sound/samples/sfx_1/02_hand_touch"
+static const ALIGN_ASSET(2) char gSample02[] = dgSample02;
+
+#define dgSample03 "__OTR__sound/samples/sfx_1/03_yoshi"
+static const ALIGN_ASSET(2) char gSample03[] = dgSample03;
+
+#define dgSample04 "__OTR__sound/samples/sfx_1/04_plop"
+static const ALIGN_ASSET(2) char gSample04[] = dgSample04;
+
+#define dgSample05 "__OTR__sound/samples/sfx_1/05_heavy_landing"
+static const ALIGN_ASSET(2) char gSample05[] = dgSample05;
+
+#define dgSample06 "__OTR__sound/samples/sfx_terrain/00_step_default"
+static const ALIGN_ASSET(2) char gSample06[] = dgSample06;
+
+#define dgSample07 "__OTR__sound/samples/sfx_terrain/01_step_grass"
+static const ALIGN_ASSET(2) char gSample07[] = dgSample07;
+
+#define dgSample08 "__OTR__sound/samples/sfx_terrain/02_step_stone"
+static const ALIGN_ASSET(2) char gSample08[] = dgSample08;
+
+#define dgSample09 "__OTR__sound/samples/sfx_terrain/03_step_spooky"
+static const ALIGN_ASSET(2) char gSample09[] = dgSample09;
+
+#define dgSample0A "__OTR__sound/samples/sfx_terrain/04_step_snow"
+static const ALIGN_ASSET(2) char gSample0A[] = dgSample0A;
+
+#define dgSample0B "__OTR__sound/samples/sfx_terrain/05_step_ice"
+static const ALIGN_ASSET(2) char gSample0B[] = dgSample0B;
+
+#define dgSample0C "__OTR__sound/samples/sfx_terrain/06_step_metal"
+static const ALIGN_ASSET(2) char gSample0C[] = dgSample0C;
+
+#define dgSample0D "__OTR__sound/samples/sfx_terrain/07_step_sand"
+static const ALIGN_ASSET(2) char gSample0D[] = dgSample0D;
+
+#define dgSample0E "__OTR__sound/samples/sfx_water/00_plunge"
+static const ALIGN_ASSET(2) char gSample0E[] = dgSample0E;
+
+#define dgSample0F "__OTR__sound/samples/sfx_water/01_splash"
+static const ALIGN_ASSET(2) char gSample0F[] = dgSample0F;
+
+#define dgSample10 "__OTR__sound/samples/sfx_water/02_swim"
+static const ALIGN_ASSET(2) char gSample10[] = dgSample10;
+
+#define dgSample11 "__OTR__sound/samples/sfx_4/00"
+static const ALIGN_ASSET(2) char gSample11[] = dgSample11;
+
+#define dgSample12 "__OTR__sound/samples/sfx_4/01"
+static const ALIGN_ASSET(2) char gSample12[] = dgSample12;
+
+#define dgSample13 "__OTR__sound/samples/sfx_4/02"
+static const ALIGN_ASSET(2) char gSample13[] = dgSample13;
+
+#define dgSample14 "__OTR__sound/samples/sfx_4/03"
+static const ALIGN_ASSET(2) char gSample14[] = dgSample14;
+
+#define dgSample15 "__OTR__sound/samples/sfx_4/04"
+static const ALIGN_ASSET(2) char gSample15[] = dgSample15;
+
+#define dgSample16 "__OTR__sound/samples/sfx_4/05"
+static const ALIGN_ASSET(2) char gSample16[] = dgSample16;
+
+#define dgSample17 "__OTR__sound/samples/sfx_4/06"
+static const ALIGN_ASSET(2) char gSample17[] = dgSample17;
+
+#define dgSample18 "__OTR__sound/samples/sfx_4/07"
+static const ALIGN_ASSET(2) char gSample18[] = dgSample18;
+
+#define dgSample19 "__OTR__sound/samples/sfx_4/08"
+static const ALIGN_ASSET(2) char gSample19[] = dgSample19;
+
+#define dgSample1A "__OTR__sound/samples/sfx_4/09"
+static const ALIGN_ASSET(2) char gSample1A[] = dgSample1A;
+
+#define dgSample1B "__OTR__sound/samples/sfx_5/00"
+static const ALIGN_ASSET(2) char gSample1B[] = dgSample1B;
+
+#define dgSample1C "__OTR__sound/samples/sfx_5/01"
+static const ALIGN_ASSET(2) char gSample1C[] = dgSample1C;
+
+#define dgSample1D "__OTR__sound/samples/sfx_5/02"
+static const ALIGN_ASSET(2) char gSample1D[] = dgSample1D;
+
+#define dgSample1E "__OTR__sound/samples/sfx_5/03"
+static const ALIGN_ASSET(2) char gSample1E[] = dgSample1E;
+
+#define dgSample1F "__OTR__sound/samples/sfx_5/04"
+static const ALIGN_ASSET(2) char gSample1F[] = dgSample1F;
+
+#define dgSample20 "__OTR__sound/samples/sfx_5/05"
+static const ALIGN_ASSET(2) char gSample20[] = dgSample20;
+
+#define dgSample21 "__OTR__sound/samples/sfx_5/06"
+static const ALIGN_ASSET(2) char gSample21[] = dgSample21;
+
+#define dgSample22 "__OTR__sound/samples/sfx_5/07"
+static const ALIGN_ASSET(2) char gSample22[] = dgSample22;
+
+#define dgSample23 "__OTR__sound/samples/sfx_5/08"
+static const ALIGN_ASSET(2) char gSample23[] = dgSample23;
+
+#define dgSample24 "__OTR__sound/samples/sfx_5/09"
+static const ALIGN_ASSET(2) char gSample24[] = dgSample24;
+
+#define dgSample25 "__OTR__sound/samples/sfx_5/0A"
+static const ALIGN_ASSET(2) char gSample25[] = dgSample25;
+
+#define dgSample26 "__OTR__sound/samples/sfx_5/0B"
+static const ALIGN_ASSET(2) char gSample26[] = dgSample26;
+
+#define dgSample27 "__OTR__sound/samples/sfx_5/0C"
+static const ALIGN_ASSET(2) char gSample27[] = dgSample27;
+
+#define dgSample28 "__OTR__sound/samples/sfx_5/0D"
+static const ALIGN_ASSET(2) char gSample28[] = dgSample28;
+
+#define dgSample29 "__OTR__sound/samples/sfx_5/0E"
+static const ALIGN_ASSET(2) char gSample29[] = dgSample29;
+
+#define dgSample2A "__OTR__sound/samples/sfx_5/0F"
+static const ALIGN_ASSET(2) char gSample2A[] = dgSample2A;
+
+#define dgSample2B "__OTR__sound/samples/sfx_5/10"
+static const ALIGN_ASSET(2) char gSample2B[] = dgSample2B;
+
+#define dgSample2C "__OTR__sound/samples/sfx_5/11"
+static const ALIGN_ASSET(2) char gSample2C[] = dgSample2C;
+
+#define dgSample2D "__OTR__sound/samples/sfx_5/12"
+static const ALIGN_ASSET(2) char gSample2D[] = dgSample2D;
+
+#define dgSample2E "__OTR__sound/samples/sfx_5/13"
+static const ALIGN_ASSET(2) char gSample2E[] = dgSample2E;
+
+#define dgSample2F "__OTR__sound/samples/sfx_5/14"
+static const ALIGN_ASSET(2) char gSample2F[] = dgSample2F;
+
+#define dgSample30 "__OTR__sound/samples/sfx_5/15"
+static const ALIGN_ASSET(2) char gSample30[] = dgSample30;
+
+#define dgSample31 "__OTR__sound/samples/sfx_5/16"
+static const ALIGN_ASSET(2) char gSample31[] = dgSample31;
+
+#define dgSample32 "__OTR__sound/samples/sfx_5/17"
+static const ALIGN_ASSET(2) char gSample32[] = dgSample32;
+
+#define dgSample33 "__OTR__sound/samples/sfx_5/18"
+static const ALIGN_ASSET(2) char gSample33[] = dgSample33;
+
+#define dgSample34 "__OTR__sound/samples/sfx_5/19"
+static const ALIGN_ASSET(2) char gSample34[] = dgSample34;
+
+#define dgSample35 "__OTR__sound/samples/sfx_5/1A"
+static const ALIGN_ASSET(2) char gSample35[] = dgSample35;
+
+#define dgSample36 "__OTR__sound/samples/sfx_5/1B"
+static const ALIGN_ASSET(2) char gSample36[] = dgSample36;
+
+#define dgSample37 "__OTR__sound/samples/sfx_5/1C"
+static const ALIGN_ASSET(2) char gSample37[] = dgSample37;
+
+#define dgSample38 "__OTR__sound/samples/sfx_6/00"
+static const ALIGN_ASSET(2) char gSample38[] = dgSample38;
+
+#define dgSample39 "__OTR__sound/samples/sfx_6/01"
+static const ALIGN_ASSET(2) char gSample39[] = dgSample39;
+
+#define dgSample3A "__OTR__sound/samples/sfx_6/02"
+static const ALIGN_ASSET(2) char gSample3A[] = dgSample3A;
+
+#define dgSample3B "__OTR__sound/samples/sfx_6/03"
+static const ALIGN_ASSET(2) char gSample3B[] = dgSample3B;
+
+#define dgSample3C "__OTR__sound/samples/sfx_6/04"
+static const ALIGN_ASSET(2) char gSample3C[] = dgSample3C;
+
+#define dgSample3D "__OTR__sound/samples/sfx_6/05"
+static const ALIGN_ASSET(2) char gSample3D[] = dgSample3D;
+
+#define dgSample3E "__OTR__sound/samples/sfx_6/06"
+static const ALIGN_ASSET(2) char gSample3E[] = dgSample3E;
+
+#define dgSample3F "__OTR__sound/samples/sfx_6/07"
+static const ALIGN_ASSET(2) char gSample3F[] = dgSample3F;
+
+#define dgSample40 "__OTR__sound/samples/sfx_6/08"
+static const ALIGN_ASSET(2) char gSample40[] = dgSample40;
+
+#define dgSample41 "__OTR__sound/samples/sfx_6/09"
+static const ALIGN_ASSET(2) char gSample41[] = dgSample41;
+
+#define dgSample42 "__OTR__sound/samples/sfx_6/0A"
+static const ALIGN_ASSET(2) char gSample42[] = dgSample42;
+
+#define dgSample43 "__OTR__sound/samples/sfx_6/0B"
+static const ALIGN_ASSET(2) char gSample43[] = dgSample43;
+
+#define dgSample44 "__OTR__sound/samples/sfx_6/0C"
+static const ALIGN_ASSET(2) char gSample44[] = dgSample44;
+
+#define dgSample45 "__OTR__sound/samples/sfx_6/0D"
+static const ALIGN_ASSET(2) char gSample45[] = dgSample45;
+
+#define dgSample46 "__OTR__sound/samples/sfx_7/00"
+static const ALIGN_ASSET(2) char gSample46[] = dgSample46;
+
+#define dgSample47 "__OTR__sound/samples/sfx_7/01"
+static const ALIGN_ASSET(2) char gSample47[] = dgSample47;
+
+#define dgSample48 "__OTR__sound/samples/sfx_7/02"
+static const ALIGN_ASSET(2) char gSample48[] = dgSample48;
+
+#define dgSample49 "__OTR__sound/samples/sfx_7/03"
+static const ALIGN_ASSET(2) char gSample49[] = dgSample49;
+
+#define dgSample4A "__OTR__sound/samples/sfx_7/04"
+static const ALIGN_ASSET(2) char gSample4A[] = dgSample4A;
+
+#define dgSample4B "__OTR__sound/samples/sfx_7/05"
+static const ALIGN_ASSET(2) char gSample4B[] = dgSample4B;
+
+#define dgSample4C "__OTR__sound/samples/sfx_7/06"
+static const ALIGN_ASSET(2) char gSample4C[] = dgSample4C;
+
+#define dgSample4D "__OTR__sound/samples/sfx_7/07"
+static const ALIGN_ASSET(2) char gSample4D[] = dgSample4D;
+
+#define dgSample4E "__OTR__sound/samples/sfx_7/08"
+static const ALIGN_ASSET(2) char gSample4E[] = dgSample4E;
+
+#define dgSample4F "__OTR__sound/samples/sfx_7/09"
+static const ALIGN_ASSET(2) char gSample4F[] = dgSample4F;
+
+#define dgSample50 "__OTR__sound/samples/sfx_7/0A"
+static const ALIGN_ASSET(2) char gSample50[] = dgSample50;
+
+#define dgSample51 "__OTR__sound/samples/sfx_7/0B"
+static const ALIGN_ASSET(2) char gSample51[] = dgSample51;
+
+#define dgSample52 "__OTR__sound/samples/sfx_7/0C"
+static const ALIGN_ASSET(2) char gSample52[] = dgSample52;
+
+#define dgSample53 "__OTR__sound/samples/sfx_7/0D_chain_chomp_bark"
+static const ALIGN_ASSET(2) char gSample53[] = dgSample53;
+
+#define dgSample54 "__OTR__sound/samples/sfx_mario/00_mario_jump_hoo"
+static const ALIGN_ASSET(2) char gSample54[] = dgSample54;
+
+#define dgSample55 "__OTR__sound/samples/sfx_mario/01_mario_jump_wah"
+static const ALIGN_ASSET(2) char gSample55[] = dgSample55;
+
+#define dgSample56 "__OTR__sound/samples/sfx_mario/02_mario_yah"
+static const ALIGN_ASSET(2) char gSample56[] = dgSample56;
+
+#define dgSample57 "__OTR__sound/samples/sfx_mario/03_mario_haha"
+static const ALIGN_ASSET(2) char gSample57[] = dgSample57;
+
+#define dgSample58 "__OTR__sound/samples/sfx_mario/04_mario_yahoo"
+static const ALIGN_ASSET(2) char gSample58[] = dgSample58;
+
+#define dgSample59 "__OTR__sound/samples/sfx_mario/05_mario_uh"
+static const ALIGN_ASSET(2) char gSample59[] = dgSample59;
+
+#define dgSample5A "__OTR__sound/samples/sfx_mario/06_mario_hrmm"
+static const ALIGN_ASSET(2) char gSample5A[] = dgSample5A;
+
+#define dgSample5B "__OTR__sound/samples/sfx_mario/07_mario_wah2"
+static const ALIGN_ASSET(2) char gSample5B[] = dgSample5B;
+
+#define dgSample5C "__OTR__sound/samples/sfx_mario/08_mario_whoa"
+static const ALIGN_ASSET(2) char gSample5C[] = dgSample5C;
+
+#define dgSample5D "__OTR__sound/samples/sfx_mario/09_mario_eeuh"
+static const ALIGN_ASSET(2) char gSample5D[] = dgSample5D;
+
+#define dgSample5E "__OTR__sound/samples/sfx_mario/0A_mario_attacked"
+static const ALIGN_ASSET(2) char gSample5E[] = dgSample5E;
+
+#define dgSample5F "__OTR__sound/samples/sfx_mario/0B_mario_ooof"
+static const ALIGN_ASSET(2) char gSample5F[] = dgSample5F;
+
+#define dgSample60 "__OTR__sound/samples/sfx_mario/0C_mario_here_we_go"
+static const ALIGN_ASSET(2) char gSample60[] = dgSample60;
+
+#define dgSample61 "__OTR__sound/samples/sfx_mario/0D_mario_yawning"
+static const ALIGN_ASSET(2) char gSample61[] = dgSample61;
+
+#define dgSample62 "__OTR__sound/samples/sfx_mario/0E_mario_snoring1"
+static const ALIGN_ASSET(2) char gSample62[] = dgSample62;
+
+#define dgSample63 "__OTR__sound/samples/sfx_mario/0F_mario_snoring2"
+static const ALIGN_ASSET(2) char gSample63[] = dgSample63;
+
+#define dgSample64 "__OTR__sound/samples/sfx_mario/10_mario_doh"
+static const ALIGN_ASSET(2) char gSample64[] = dgSample64;
+
+#define dgSample65 "__OTR__sound/samples/sfx_mario/11_mario_game_over"
+static const ALIGN_ASSET(2) char gSample65[] = dgSample65;
+
+#define dgSample66 "__OTR__sound/samples/sfx_mario/12_mario_hello"
+static const ALIGN_ASSET(2) char gSample66[] = dgSample66;
+
+#define dgSample67 "__OTR__sound/samples/sfx_mario/13_mario_press_start_to_play"
+static const ALIGN_ASSET(2) char gSample67[] = dgSample67;
+
+#define dgSample68 "__OTR__sound/samples/sfx_mario/14_mario_twirl_bounce"
+static const ALIGN_ASSET(2) char gSample68[] = dgSample68;
+
+#define dgSample69 "__OTR__sound/samples/sfx_mario/15_mario_snoring3"
+static const ALIGN_ASSET(2) char gSample69[] = dgSample69;
+
+#define dgSample6A "__OTR__sound/samples/sfx_mario/16_mario_so_longa_bowser"
+static const ALIGN_ASSET(2) char gSample6A[] = dgSample6A;
+
+#define dgSample6B "__OTR__sound/samples/sfx_mario/17_mario_ima_tired"
+static const ALIGN_ASSET(2) char gSample6B[] = dgSample6B;
+
+#define dgSample6C "__OTR__sound/samples/sfx_mario/18_mario_waha"
+static const ALIGN_ASSET(2) char gSample6C[] = dgSample6C;
+
+#define dgSample6D "__OTR__sound/samples/sfx_mario/19_mario_yippee"
+static const ALIGN_ASSET(2) char gSample6D[] = dgSample6D;
+
+#define dgSample6E "__OTR__sound/samples/sfx_mario/1A_mario_lets_a_go"
+static const ALIGN_ASSET(2) char gSample6E[] = dgSample6E;
+
+#define dgSample6F "__OTR__sound/samples/sfx_9/00"
+static const ALIGN_ASSET(2) char gSample6F[] = dgSample6F;
+
+#define dgSample70 "__OTR__sound/samples/sfx_9/01"
+static const ALIGN_ASSET(2) char gSample70[] = dgSample70;
+
+#define dgSample71 "__OTR__sound/samples/sfx_9/02"
+static const ALIGN_ASSET(2) char gSample71[] = dgSample71;
+
+#define dgSample72 "__OTR__sound/samples/sfx_9/03"
+static const ALIGN_ASSET(2) char gSample72[] = dgSample72;
+
+#define dgSample73 "__OTR__sound/samples/sfx_9/04_camera_buzz"
+static const ALIGN_ASSET(2) char gSample73[] = dgSample73;
+
+#define dgSample74 "__OTR__sound/samples/sfx_9/05_camera_shutter"
+static const ALIGN_ASSET(2) char gSample74[] = dgSample74;
+
+#define dgSample75 "__OTR__sound/samples/sfx_9/06"
+static const ALIGN_ASSET(2) char gSample75[] = dgSample75;
+
+#define dgSample76 "__OTR__sound/samples/sfx_mario_peach/00_mario_waaaooow"
+static const ALIGN_ASSET(2) char gSample76[] = dgSample76;
+
+#define dgSample77 "__OTR__sound/samples/sfx_mario_peach/01_mario_hoohoo"
+static const ALIGN_ASSET(2) char gSample77[] = dgSample77;
+
+#define dgSample78 "__OTR__sound/samples/sfx_mario_peach/02_mario_panting"
+static const ALIGN_ASSET(2) char gSample78[] = dgSample78;
+
+#define dgSample79 "__OTR__sound/samples/sfx_mario_peach/03_mario_dying"
+static const ALIGN_ASSET(2) char gSample79[] = dgSample79;
+
+#define dgSample7A "__OTR__sound/samples/sfx_mario_peach/04_mario_on_fire"
+static const ALIGN_ASSET(2) char gSample7A[] = dgSample7A;
+
+#define dgSample7B "__OTR__sound/samples/sfx_mario_peach/05_mario_uh2"
+static const ALIGN_ASSET(2) char gSample7B[] = dgSample7B;
+
+#define dgSample7C "__OTR__sound/samples/sfx_mario_peach/06_mario_coughing"
+static const ALIGN_ASSET(2) char gSample7C[] = dgSample7C;
+
+#define dgSample7D "__OTR__sound/samples/sfx_mario_peach/07_mario_its_a_me_mario"
+static const ALIGN_ASSET(2) char gSample7D[] = dgSample7D;
+
+#define dgSample7E "__OTR__sound/samples/sfx_mario_peach/08_mario_punch_yah"
+static const ALIGN_ASSET(2) char gSample7E[] = dgSample7E;
+
+#define dgSample7F "__OTR__sound/samples/sfx_mario_peach/09_mario_punch_hoo"
+static const ALIGN_ASSET(2) char gSample7F[] = dgSample7F;
+
+#define dgSample80 "__OTR__sound/samples/sfx_mario_peach/0A_mario_mama_mia"
+static const ALIGN_ASSET(2) char gSample80[] = dgSample80;
+
+#define dgSample81 "__OTR__sound/samples/sfx_mario_peach/0B_mario_okey_dokey"
+static const ALIGN_ASSET(2) char gSample81[] = dgSample81;
+
+#define dgSample82 "__OTR__sound/samples/sfx_mario_peach/0C_mario_drowning"
+static const ALIGN_ASSET(2) char gSample82[] = dgSample82;
+
+#define dgSample83 "__OTR__sound/samples/sfx_mario_peach/0D_mario_thank_you_playing_my_game"
+static const ALIGN_ASSET(2) char gSample83[] = dgSample83;
+
+#define dgSample84 "__OTR__sound/samples/sfx_mario_peach/0E_peach_dear_mario"
+static const ALIGN_ASSET(2) char gSample84[] = dgSample84;
+
+#define dgSample85 "__OTR__sound/samples/sfx_mario_peach/0F_peach_mario"
+static const ALIGN_ASSET(2) char gSample85[] = dgSample85;
+
+#define dgSample86 "__OTR__sound/samples/sfx_mario_peach/10_peach_power_of_the_stars"
+static const ALIGN_ASSET(2) char gSample86[] = dgSample86;
+
+#define dgSample87 "__OTR__sound/samples/sfx_mario_peach/11_peach_thanks_to_you"
+static const ALIGN_ASSET(2) char gSample87[] = dgSample87;
+
+#define dgSample88 "__OTR__sound/samples/sfx_mario_peach/12_peach_thank_you_mario"
+static const ALIGN_ASSET(2) char gSample88[] = dgSample88;
+
+#define dgSample89 "__OTR__sound/samples/sfx_mario_peach/13_peach_something_special"
+static const ALIGN_ASSET(2) char gSample89[] = dgSample89;
+
+#define dgSample8A "__OTR__sound/samples/sfx_mario_peach/14_peach_bake_a_cake"
+static const ALIGN_ASSET(2) char gSample8A[] = dgSample8A;
+
+#define dgSample8B "__OTR__sound/samples/sfx_mario_peach/15_peach_for_mario"
+static const ALIGN_ASSET(2) char gSample8B[] = dgSample8B;
+
+#define dgSample8C "__OTR__sound/samples/sfx_mario_peach/16_peach_mario2"
+static const ALIGN_ASSET(2) char gSample8C[] = dgSample8C;
+
+#define dgSample8D "__OTR__sound/samples/instruments/00"
+static const ALIGN_ASSET(2) char gSample8D[] = dgSample8D;
+
+#define dgSample8E "__OTR__sound/samples/instruments/01_banjo_1"
+static const ALIGN_ASSET(2) char gSample8E[] = dgSample8E;
+
+#define dgSample8F "__OTR__sound/samples/instruments/02"
+static const ALIGN_ASSET(2) char gSample8F[] = dgSample8F;
+
+#define dgSample90 "__OTR__sound/samples/instruments/03_human_whistle"
+static const ALIGN_ASSET(2) char gSample90[] = dgSample90;
+
+#define dgSample91 "__OTR__sound/samples/instruments/04_bright_piano"
+static const ALIGN_ASSET(2) char gSample91[] = dgSample91;
+
+#define dgSample92 "__OTR__sound/samples/instruments/05_acoustic_bass"
+static const ALIGN_ASSET(2) char gSample92[] = dgSample92;
+
+#define dgSample93 "__OTR__sound/samples/instruments/06_kick_drum_1"
+static const ALIGN_ASSET(2) char gSample93[] = dgSample93;
+
+#define dgSample94 "__OTR__sound/samples/instruments/07_rimshot"
+static const ALIGN_ASSET(2) char gSample94[] = dgSample94;
+
+#define dgSample95 "__OTR__sound/samples/instruments/08"
+static const ALIGN_ASSET(2) char gSample95[] = dgSample95;
+
+#define dgSample96 "__OTR__sound/samples/instruments/09"
+static const ALIGN_ASSET(2) char gSample96[] = dgSample96;
+
+#define dgSample97 "__OTR__sound/samples/instruments/0A_tambourine"
+static const ALIGN_ASSET(2) char gSample97[] = dgSample97;
+
+#define dgSample98 "__OTR__sound/samples/instruments/0B"
+static const ALIGN_ASSET(2) char gSample98[] = dgSample98;
+
+#define dgSample99 "__OTR__sound/samples/instruments/0C_conga_stick"
+static const ALIGN_ASSET(2) char gSample99[] = dgSample99;
+
+#define dgSample9A "__OTR__sound/samples/instruments/0D_clave"
+static const ALIGN_ASSET(2) char gSample9A[] = dgSample9A;
+
+#define dgSample9B "__OTR__sound/samples/instruments/0E_hihat_closed"
+static const ALIGN_ASSET(2) char gSample9B[] = dgSample9B;
+
+#define dgSample9C "__OTR__sound/samples/instruments/0F_hihat_open"
+static const ALIGN_ASSET(2) char gSample9C[] = dgSample9C;
+
+#define dgSample9D "__OTR__sound/samples/instruments/10_cymbal_bell"
+static const ALIGN_ASSET(2) char gSample9D[] = dgSample9D;
+
+#define dgSample9E "__OTR__sound/samples/instruments/11_splash_cymbal"
+static const ALIGN_ASSET(2) char gSample9E[] = dgSample9E;
+
+#define dgSample9F "__OTR__sound/samples/instruments/12_snare_drum_1"
+static const ALIGN_ASSET(2) char gSample9F[] = dgSample9F;
+
+#define dgSampleA0 "__OTR__sound/samples/instruments/13_snare_drum_2"
+static const ALIGN_ASSET(2) char gSampleA0[] = dgSampleA0;
+
+#define dgSampleA1 "__OTR__sound/samples/instruments/14_strings_5"
+static const ALIGN_ASSET(2) char gSampleA1[] = dgSampleA1;
+
+#define dgSampleA2 "__OTR__sound/samples/instruments/15_strings_4"
+static const ALIGN_ASSET(2) char gSampleA2[] = dgSampleA2;
+
+#define dgSampleA3 "__OTR__sound/samples/instruments/16_french_horns"
+static const ALIGN_ASSET(2) char gSampleA3[] = dgSampleA3;
+
+#define dgSampleA4 "__OTR__sound/samples/instruments/17_trumpet"
+static const ALIGN_ASSET(2) char gSampleA4[] = dgSampleA4;
+
+#define dgSampleA5 "__OTR__sound/samples/instruments/18_timpani"
+static const ALIGN_ASSET(2) char gSampleA5[] = dgSampleA5;
+
+#define dgSampleA6 "__OTR__sound/samples/instruments/19_brass"
+static const ALIGN_ASSET(2) char gSampleA6[] = dgSampleA6;
+
+#define dgSampleA7 "__OTR__sound/samples/instruments/1A_slap_bass"
+static const ALIGN_ASSET(2) char gSampleA7[] = dgSampleA7;
+
+#define dgSampleA8 "__OTR__sound/samples/instruments/1B_organ_2"
+static const ALIGN_ASSET(2) char gSampleA8[] = dgSampleA8;
+
+#define dgSampleA9 "__OTR__sound/samples/instruments/1C"
+static const ALIGN_ASSET(2) char gSampleA9[] = dgSampleA9;
+
+#define dgSampleAA "__OTR__sound/samples/instruments/1D"
+static const ALIGN_ASSET(2) char gSampleAA[] = dgSampleAA;
+
+#define dgSampleAB "__OTR__sound/samples/instruments/1E_closed_triangle"
+static const ALIGN_ASSET(2) char gSampleAB[] = dgSampleAB;
+
+#define dgSampleAC "__OTR__sound/samples/instruments/1F_open_triangle"
+static const ALIGN_ASSET(2) char gSampleAC[] = dgSampleAC;
+
+#define dgSampleAD "__OTR__sound/samples/instruments/20_cabasa"
+static const ALIGN_ASSET(2) char gSampleAD[] = dgSampleAD;
+
+#define dgSampleAE "__OTR__sound/samples/instruments/21_sine_bass"
+static const ALIGN_ASSET(2) char gSampleAE[] = dgSampleAE;
+
+#define dgSampleAF "__OTR__sound/samples/instruments/22_boys_choir"
+static const ALIGN_ASSET(2) char gSampleAF[] = dgSampleAF;
+
+#define dgSampleB0 "__OTR__sound/samples/instruments/23_strings_1"
+static const ALIGN_ASSET(2) char gSampleB0[] = dgSampleB0;
+
+#define dgSampleB1 "__OTR__sound/samples/instruments/24_strings_2"
+static const ALIGN_ASSET(2) char gSampleB1[] = dgSampleB1;
+
+#define dgSampleB2 "__OTR__sound/samples/instruments/25_strings_3"
+static const ALIGN_ASSET(2) char gSampleB2[] = dgSampleB2;
+
+#define dgSampleB3 "__OTR__sound/samples/instruments/26_crystal_rhodes"
+static const ALIGN_ASSET(2) char gSampleB3[] = dgSampleB3;
+
+#define dgSampleB4 "__OTR__sound/samples/instruments/27_harpsichord"
+static const ALIGN_ASSET(2) char gSampleB4[] = dgSampleB4;
+
+#define dgSampleB5 "__OTR__sound/samples/instruments/28_sitar_1"
+static const ALIGN_ASSET(2) char gSampleB5[] = dgSampleB5;
+
+#define dgSampleB6 "__OTR__sound/samples/instruments/29_orchestra_hit"
+static const ALIGN_ASSET(2) char gSampleB6[] = dgSampleB6;
+
+#define dgSampleB7 "__OTR__sound/samples/instruments/2A"
+static const ALIGN_ASSET(2) char gSampleB7[] = dgSampleB7;
+
+#define dgSampleB8 "__OTR__sound/samples/instruments/2B"
+static const ALIGN_ASSET(2) char gSampleB8[] = dgSampleB8;
+
+#define dgSampleB9 "__OTR__sound/samples/instruments/2C"
+static const ALIGN_ASSET(2) char gSampleB9[] = dgSampleB9;
+
+#define dgSampleBA "__OTR__sound/samples/instruments/2D_trombone"
+static const ALIGN_ASSET(2) char gSampleBA[] = dgSampleBA;
+
+#define dgSampleBB "__OTR__sound/samples/instruments/2E_accordion"
+static const ALIGN_ASSET(2) char gSampleBB[] = dgSampleBB;
+
+#define dgSampleBC "__OTR__sound/samples/instruments/2F_sleigh_bells"
+static const ALIGN_ASSET(2) char gSampleBC[] = dgSampleBC;
+
+#define dgSampleBD "__OTR__sound/samples/instruments/30_rarefaction-lahna"
+static const ALIGN_ASSET(2) char gSampleBD[] = dgSampleBD;
+
+#define dgSampleBE "__OTR__sound/samples/instruments/31_rarefaction-convolution"
+static const ALIGN_ASSET(2) char gSampleBE[] = dgSampleBE;
+
+#define dgSampleBF "__OTR__sound/samples/instruments/32_metal_rimshot"
+static const ALIGN_ASSET(2) char gSampleBF[] = dgSampleBF;
+
+#define dgSampleC0 "__OTR__sound/samples/instruments/33_kick_drum_2"
+static const ALIGN_ASSET(2) char gSampleC0[] = dgSampleC0;
+
+#define dgSampleC1 "__OTR__sound/samples/instruments/34_alto_flute"
+static const ALIGN_ASSET(2) char gSampleC1[] = dgSampleC1;
+
+#define dgSampleC2 "__OTR__sound/samples/instruments/35_gospel_organ"
+static const ALIGN_ASSET(2) char gSampleC2[] = dgSampleC2;
+
+#define dgSampleC3 "__OTR__sound/samples/instruments/36_sawtooth_synth"
+static const ALIGN_ASSET(2) char gSampleC3[] = dgSampleC3;
+
+#define dgSampleC4 "__OTR__sound/samples/instruments/37_square_synth"
+static const ALIGN_ASSET(2) char gSampleC4[] = dgSampleC4;
+
+#define dgSampleC5 "__OTR__sound/samples/instruments/38_electric_kick_drum"
+static const ALIGN_ASSET(2) char gSampleC5[] = dgSampleC5;
+
+#define dgSampleC6 "__OTR__sound/samples/instruments/39_sitar_2"
+static const ALIGN_ASSET(2) char gSampleC6[] = dgSampleC6;
+
+#define dgSampleC7 "__OTR__sound/samples/instruments/3A_music_box"
+static const ALIGN_ASSET(2) char gSampleC7[] = dgSampleC7;
+
+#define dgSampleC8 "__OTR__sound/samples/instruments/3B_banjo_2"
+static const ALIGN_ASSET(2) char gSampleC8[] = dgSampleC8;
+
+#define dgSampleC9 "__OTR__sound/samples/instruments/3C_acoustic_guitar"
+static const ALIGN_ASSET(2) char gSampleC9[] = dgSampleC9;
+
+#define dgSampleCA "__OTR__sound/samples/instruments/3D"
+static const ALIGN_ASSET(2) char gSampleCA[] = dgSampleCA;
+
+#define dgSampleCB "__OTR__sound/samples/instruments/3E_monk_choir"
+static const ALIGN_ASSET(2) char gSampleCB[] = dgSampleCB;
+
+#define dgSampleCC "__OTR__sound/samples/instruments/3F"
+static const ALIGN_ASSET(2) char gSampleCC[] = dgSampleCC;
+
+#define dgSampleCD "__OTR__sound/samples/instruments/40_bell"
+static const ALIGN_ASSET(2) char gSampleCD[] = dgSampleCD;
+
+#define dgSampleCE "__OTR__sound/samples/instruments/41_pan_flute"
+static const ALIGN_ASSET(2) char gSampleCE[] = dgSampleCE;
+
+#define dgSampleCF "__OTR__sound/samples/instruments/42_vibraphone"
+static const ALIGN_ASSET(2) char gSampleCF[] = dgSampleCF;
+
+#define dgSampleD0 "__OTR__sound/samples/instruments/43_harmonica"
+static const ALIGN_ASSET(2) char gSampleD0[] = dgSampleD0;
+
+#define dgSampleD1 "__OTR__sound/samples/instruments/44_grand_piano"
+static const ALIGN_ASSET(2) char gSampleD1[] = dgSampleD1;
+
+#define dgSampleD2 "__OTR__sound/samples/instruments/45_french_horns_lq"
+static const ALIGN_ASSET(2) char gSampleD2[] = dgSampleD2;
+
+#define dgSampleD3 "__OTR__sound/samples/instruments/46_pizzicato_strings_1"
+static const ALIGN_ASSET(2) char gSampleD3[] = dgSampleD3;
+
+#define dgSampleD4 "__OTR__sound/samples/instruments/47_pizzicato_strings_2"
+static const ALIGN_ASSET(2) char gSampleD4[] = dgSampleD4;
+
+#define dgSampleD5 "__OTR__sound/samples/instruments/48_steel_drum"
+static const ALIGN_ASSET(2) char gSampleD5[] = dgSampleD5;
+
+#define dgSampleD6 "__OTR__sound/samples/piranha_music_box/00_music_box"
+static const ALIGN_ASSET(2) char gSampleD6[] = dgSampleD6;
+
+#define dgSampleD7 "__OTR__sound/samples/course_start/00_la"
+static const ALIGN_ASSET(2) char gSampleD7[] = dgSampleD7;
+
+#define dgSampleD8 "__OTR__sound/samples/bowser_organ/00_organ_1"
+static const ALIGN_ASSET(2) char gSampleD8[] = dgSampleD8;
+
+#define dgSampleD9 "__OTR__sound/samples/bowser_organ/01_organ_1_lq"
+static const ALIGN_ASSET(2) char gSampleD9[] = dgSampleD9;
+
+#define dgSampleDA "__OTR__sound/samples/bowser_organ/02_boys_choir"
+static const ALIGN_ASSET(2) char gSampleDA[] = dgSampleDA;
+
+static const char* gSampleTable[] = {
+ gSample00, gSample01, gSample02, gSample03,
+ gSample04, gSample05, gSample06, gSample07,
+ gSample08, gSample09, gSample0A, gSample0B,
+ gSample0C, gSample0D, gSample0E, gSample0F,
+ gSample10, gSample11, gSample12, gSample13,
+ gSample14, gSample15, gSample16, gSample17,
+ gSample18, gSample19, gSample1A, gSample1B,
+ gSample1C, gSample1D, gSample1E, gSample1F,
+ gSample20, gSample21, gSample22, gSample23,
+ gSample24, gSample25, gSample26, gSample27,
+ gSample28, gSample29, gSample2A, gSample2B,
+ gSample2C, gSample2D, gSample2E, gSample2F,
+ gSample30, gSample31, gSample32, gSample33,
+ gSample34, gSample35, gSample36, gSample37,
+ gSample38, gSample39, gSample3A, gSample3B,
+ gSample3C, gSample3D, gSample3E, gSample3F,
+ gSample40, gSample41, gSample42, gSample43,
+ gSample44, gSample45, gSample46, gSample47,
+ gSample48, gSample49, gSample4A, gSample4B,
+ gSample4C, gSample4D, gSample4E, gSample4F,
+ gSample50, gSample51, gSample52, gSample53,
+ gSample54, gSample55, gSample56, gSample57,
+ gSample58, gSample59, gSample5A, gSample5B,
+ gSample5C, gSample5D, gSample5E, gSample5F,
+ gSample60, gSample61, gSample62, gSample63,
+ gSample64, gSample65, gSample66, gSample67,
+ gSample68, gSample69, gSample6A, gSample6B,
+ gSample6C, gSample6D, gSample6E, gSample6F,
+ gSample70, gSample71, gSample72, gSample73,
+ gSample74, gSample75, gSample76, gSample77,
+ gSample78, gSample79, gSample7A, gSample7B,
+ gSample7C, gSample7D, gSample7E, gSample7F,
+ gSample80, gSample81, gSample82, gSample83,
+ gSample84, gSample85, gSample86, gSample87,
+ gSample88, gSample89, gSample8A, gSample8B,
+ gSample8C, gSample8D, gSample8E, gSample8F,
+ gSample90, gSample91, gSample92, gSample93,
+ gSample94, gSample95, gSample96, gSample97,
+ gSample98, gSample99, gSample9A, gSample9B,
+ gSample9C, gSample9D, gSample9E, gSample9F,
+ gSampleA0, gSampleA1, gSampleA2, gSampleA3,
+ gSampleA4, gSampleA5, gSampleA6, gSampleA7,
+ gSampleA8, gSampleA9, gSampleAA, gSampleAB,
+ gSampleAC, gSampleAD, gSampleAE, gSampleAF,
+ gSampleB0, gSampleB1, gSampleB2, gSampleB3,
+ gSampleB4, gSampleB5, gSampleB6, gSampleB7,
+ gSampleB8, gSampleB9, gSampleBA, gSampleBB,
+ gSampleBC, gSampleBD, gSampleBE, gSampleBF,
+ gSampleC0, gSampleC1, gSampleC2, gSampleC3,
+ gSampleC4, gSampleC5, gSampleC6, gSampleC7,
+ gSampleC8, gSampleC9, gSampleCA, gSampleCB,
+ gSampleCC, gSampleCD, gSampleCE, gSampleCF,
+ gSampleD0, gSampleD1, gSampleD2, gSampleD3,
+ gSampleD4, gSampleD5, gSampleD6, gSampleD7,
+ gSampleD8, gSampleD9, gSampleDA,
+};
diff --git a/sequences.json b/sequences.json
new file mode 100644
index 0000000..13e7895
--- /dev/null
+++ b/sequences.json
@@ -0,0 +1,37 @@
+{
+ "00_sound_player": ["00", "01_terrain", "02_water", "03", "04", "05", "06", "07", "08_mario", "09", "0A_mario_peach"],
+ "01_cutscene_collect_star": ["22"],
+ "02_menu_title_screen": ["11"],
+ "03_level_grass": ["22"],
+ "04_level_inside_castle": ["0E"],
+ "05_level_water": ["13"],
+ "06_level_hot": ["0F"],
+ "07_level_boss_koopa": ["12"],
+ "08_level_snow": ["0B"],
+ "09_level_slide": ["0D"],
+ "0A_level_spooky": ["10", "21"],
+ "0B_event_piranha_plant": ["14_piranha_music_box"],
+ "0C_level_underground": ["15"],
+ "0D_menu_star_select": ["16_course_start"],
+ "0E_event_powerup": ["17"],
+ "0F_event_metal_cap": ["18"],
+ "10_event_koopa_message": ["12"],
+ "11_level_koopa_road": ["19"],
+ "12_event_high_score": ["1F"],
+ "13_event_merry_go_round": ["21"],
+ "14_event_race": ["1A"],
+ "15_cutscene_star_spawn": ["0E"],
+ "16_event_boss": ["1B"],
+ "17_cutscene_collect_key": ["1A"],
+ "18_event_endless_stairs": ["1C_endless_stairs"],
+ "19_level_boss_koopa_final": ["1D_bowser_organ"],
+ "1A_cutscene_credits": ["25"],
+ "1B_event_solve_puzzle": ["14_piranha_music_box"],
+ "1C_event_toad_message": ["20"],
+ "1D_event_peach_message": ["1E"],
+ "1E_cutscene_intro": ["1B"],
+ "1F_cutscene_victory": ["1A"],
+ "20_cutscene_ending": ["23"],
+ "21_menu_file_select": ["24"],
+ "22_cutscene_lakitu": ["1B"]
+}
diff --git a/sequences_table.h b/sequences_table.h
new file mode 100644
index 0000000..f252b20
--- /dev/null
+++ b/sequences_table.h
@@ -0,0 +1,141 @@
+#pragma once
+#include "align_asset_macro.h"
+
+#define dgSequence01 "__OTR__sound/sequences/01_cutscene_collect_star.m64"
+static const ALIGN_ASSET(2) char gSequence01[] = dgSequence01;
+
+#define dgSequence02 "__OTR__sound/sequences/02_menu_title_screen.m64"
+static const ALIGN_ASSET(2) char gSequence02[] = dgSequence02;
+
+#define dgSequence03 "__OTR__sound/sequences/03_level_grass.m64"
+static const ALIGN_ASSET(2) char gSequence03[] = dgSequence03;
+
+#define dgSequence04 "__OTR__sound/sequences/04_level_inside_castle.m64"
+static const ALIGN_ASSET(2) char gSequence04[] = dgSequence04;
+
+#define dgSequence05 "__OTR__sound/sequences/05_level_water.m64"
+static const ALIGN_ASSET(2) char gSequence05[] = dgSequence05;
+
+#define dgSequence06 "__OTR__sound/sequences/06_level_hot.m64"
+static const ALIGN_ASSET(2) char gSequence06[] = dgSequence06;
+
+#define dgSequence07 "__OTR__sound/sequences/07_level_boss_koopa.m64"
+static const ALIGN_ASSET(2) char gSequence07[] = dgSequence07;
+
+#define dgSequence08 "__OTR__sound/sequences/08_level_snow.m64"
+static const ALIGN_ASSET(2) char gSequence08[] = dgSequence08;
+
+#define dgSequence09 "__OTR__sound/sequences/09_level_slide.m64"
+static const ALIGN_ASSET(2) char gSequence09[] = dgSequence09;
+
+#define dgSequence0A "__OTR__sound/sequences/0A_level_spooky.m64"
+static const ALIGN_ASSET(2) char gSequence0A[] = dgSequence0A;
+
+#define dgSequence0B "__OTR__sound/sequences/0B_event_piranha_plant.m64"
+static const ALIGN_ASSET(2) char gSequence0B[] = dgSequence0B;
+
+#define dgSequence0C "__OTR__sound/sequences/0C_level_underground.m64"
+static const ALIGN_ASSET(2) char gSequence0C[] = dgSequence0C;
+
+#define dgSequence0D "__OTR__sound/sequences/0D_menu_star_select.m64"
+static const ALIGN_ASSET(2) char gSequence0D[] = dgSequence0D;
+
+#define dgSequence0E "__OTR__sound/sequences/0E_event_powerup.m64"
+static const ALIGN_ASSET(2) char gSequence0E[] = dgSequence0E;
+
+#define dgSequence0F "__OTR__sound/sequences/0F_event_metal_cap.m64"
+static const ALIGN_ASSET(2) char gSequence0F[] = dgSequence0F;
+
+#define dgSequence10 "__OTR__sound/sequences/10_event_koopa_message.m64"
+static const ALIGN_ASSET(2) char gSequence10[] = dgSequence10;
+
+#define dgSequence11 "__OTR__sound/sequences/11_level_koopa_road.m64"
+static const ALIGN_ASSET(2) char gSequence11[] = dgSequence11;
+
+#define dgSequence12 "__OTR__sound/sequences/12_event_high_score.m64"
+static const ALIGN_ASSET(2) char gSequence12[] = dgSequence12;
+
+#define dgSequence13 "__OTR__sound/sequences/13_event_merry_go_round.m64"
+static const ALIGN_ASSET(2) char gSequence13[] = dgSequence13;
+
+#define dgSequence14 "__OTR__sound/sequences/14_event_race.m64"
+static const ALIGN_ASSET(2) char gSequence14[] = dgSequence14;
+
+#define dgSequence15 "__OTR__sound/sequences/15_cutscene_star_spawn.m64"
+static const ALIGN_ASSET(2) char gSequence15[] = dgSequence15;
+
+#define dgSequence16 "__OTR__sound/sequences/16_event_boss.m64"
+static const ALIGN_ASSET(2) char gSequence16[] = dgSequence16;
+
+#define dgSequence17 "__OTR__sound/sequences/17_cutscene_collect_key.m64"
+static const ALIGN_ASSET(2) char gSequence17[] = dgSequence17;
+
+#define dgSequence18 "__OTR__sound/sequences/18_event_endless_stairs.m64"
+static const ALIGN_ASSET(2) char gSequence18[] = dgSequence18;
+
+#define dgSequence19 "__OTR__sound/sequences/19_level_boss_koopa_final.m64"
+static const ALIGN_ASSET(2) char gSequence19[] = dgSequence19;
+
+#define dgSequence1A "__OTR__sound/sequences/1A_cutscene_credits.m64"
+static const ALIGN_ASSET(2) char gSequence1A[] = dgSequence1A;
+
+#define dgSequence1B "__OTR__sound/sequences/1B_event_solve_puzzle.m64"
+static const ALIGN_ASSET(2) char gSequence1B[] = dgSequence1B;
+
+#define dgSequence1C "__OTR__sound/sequences/1C_event_toad_message.m64"
+static const ALIGN_ASSET(2) char gSequence1C[] = dgSequence1C;
+
+#define dgSequence1D "__OTR__sound/sequences/1D_event_peach_message.m64"
+static const ALIGN_ASSET(2) char gSequence1D[] = dgSequence1D;
+
+#define dgSequence1E "__OTR__sound/sequences/1E_cutscene_intro.m64"
+static const ALIGN_ASSET(2) char gSequence1E[] = dgSequence1E;
+
+#define dgSequence1F "__OTR__sound/sequences/1F_cutscene_victory.m64"
+static const ALIGN_ASSET(2) char gSequence1F[] = dgSequence1F;
+
+#define dgSequence20 "__OTR__sound/sequences/20_cutscene_ending.m64"
+static const ALIGN_ASSET(2) char gSequence20[] = dgSequence20;
+
+#define dgSequence21 "__OTR__sound/sequences/21_menu_file_select.m64"
+static const ALIGN_ASSET(2) char gSequence21[] = dgSequence21;
+
+#define dgSequence22 "__OTR__sound/sequences/22_cutscene_lakitu.m64"
+static const ALIGN_ASSET(2) char gSequence22[] = dgSequence22;
+
+static const char* gSequenceTable[] = {
+ gSequence01,
+ gSequence02,
+ gSequence03,
+ gSequence04,
+ gSequence05,
+ gSequence06,
+ gSequence07,
+ gSequence08,
+ gSequence09,
+ gSequence0A,
+ gSequence0B,
+ gSequence0C,
+ gSequence0D,
+ gSequence0E,
+ gSequence0F,
+ gSequence10,
+ gSequence11,
+ gSequence12,
+ gSequence13,
+ gSequence14,
+ gSequence15,
+ gSequence16,
+ gSequence17,
+ gSequence18,
+ gSequence19,
+ gSequence1A,
+ gSequence1B,
+ gSequence1C,
+ gSequence1D,
+ gSequence1E,
+ gSequence1F,
+ gSequence20,
+ gSequence21,
+ gSequence22,
+};
diff --git a/src/Companion.cpp b/src/Companion.cpp
index 16d6c11..df793be 100644
--- a/src/Companion.cpp
+++ b/src/Companion.cpp
@@ -2,8 +2,10 @@
#include "storm/SWrapper.h"
#include "utils/MIODecoder.h"
+#include "audio/AudioManager.h"
#include "factories/RawFactory.h"
#include "factories/BlobFactory.h"
+#include "factories/AudioFactory.h"
#include "factories/TextureFactory.h"
#include "factories/AnimFactory.h"
@@ -18,9 +20,12 @@ namespace fs = std::filesystem;
static const std::unordered_map<std::string, RawFactory*> gFactories = {
{ ".png", new TextureFactory() },
{ ".anim", new AnimFactory() },
+ { ".aiff", new AudioFactory() },
+ { ".bnk", new AudioFactory() },
+ { ".bset", new AudioFactory() },
+ { ".m64", new AudioFactory() },
{ ".bin", new BlobFactory(LUS::ResourceType::Blob) },
{ ".sbox", new BlobFactory(LUS::ResourceType::Blob, true) },
- { ".aud", new BlobFactory(LUS::ResourceType::Blob, false) },
};
void Companion::Start() {
@@ -34,6 +39,9 @@ void Companion::Start() {
std::cout << "Detected Rom Size: " << this->gRomData.size() << '\n';
+ AudioManager::Instance = new AudioManager();
+ AudioManager::Instance->initialize(this->gRomData);
+
this->ProcessAssets();
}
@@ -45,7 +53,7 @@ void Companion::ProcessAssets() {
for( auto& [asset, data] : assets.items() ) {
std::string extension = fs::path(asset).extension().string();
if( gFactories.find(extension) == gFactories.end() ) {
- std::cout << "No factory found for " << asset << '\n';
+ std::cout << "No factory found for " << asset << '\n';
continue;
}
LUS::BinaryWriter write = LUS::BinaryWriter();
@@ -57,7 +65,7 @@ void Companion::ProcessAssets() {
RawFactory* factory = gFactories.at(extension);
if(!factory->process(&write, entry, this->gRomData)){
- std::cout << "Failed to process " << asset << '\n';
+ std::cout << "Failed to process " << asset << '\n';
continue;
}
@@ -70,13 +78,15 @@ void Companion::ProcessAssets() {
if(!isTexture) {
// Write to file too
std::string dpath = "debug/" + path;
- fs::create_directories(fs::path(dpath).parent_path());
+ if(!fs::exists(fs::path(dpath).parent_path())){
+ fs::create_directories(fs::path(dpath).parent_path());
+ }
std::ofstream output(dpath, std::ios::binary);
output.write((char*)buffer.data(), buffer.size());
output.close();
}
- std::cout << "Processed " << path << std::endl;
+ std::cout << "Processed " << path << std::endl;
write.Close();
}
diff --git a/src/audio/AIFCDecode.cpp b/src/audio/AIFCDecode.cpp
new file mode 100644
index 0000000..21eec08
--- /dev/null
+++ b/src/audio/AIFCDecode.cpp
@@ -0,0 +1,656 @@
+/**
+ * Bruteforcing decoder for converting ADPCM-encoded AIFC into AIFF, in a way
+ * that roundtrips with vadpcm_enc.
+ */
+#include "AIFCDecode.h"
+#include <cassert>
+#include <cstring>
+#include <cstdio>
+#include <cstdlib>
+#include <cstdarg>
+#include "binarytools/BinaryWriter.h"
+#include "BinaryReader.h"
+
+typedef signed char s8;
+typedef short s16;
+typedef int s32;
+typedef unsigned char u8;
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long long u64;
+typedef float f32;
+
+#undef BSWAP16
+#undef BSWAP32
+#undef BSWAP64
+
+#define bswap16(x) __builtin_bswap16(x)
+#define bswap32(x) __builtin_bswap32(x)
+#define BSWAP16(x) x = bswap16(x)
+#define BSWAP32(x) x = bswap32(x)
+
+#define BSWAP16_MANY(x, n) for (s32 _i = 0; _i < n; _i++) BSWAP16((x)[_i])
+
+#ifndef WIN32
+#define NORETURN __attribute__((noreturn))
+#define UNUSED __attribute__((unused))
+#else
+#define NORETURN
+#define UNUSED
+#endif
+
+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;
+
+#define checked_fread(a, b, c, d) d.Read((char*) a, b * c)
+
+NORETURN
+void fail_parse(const char *fmt, ...)
+{
+ char *formatted = nullptr;
+ va_list ap;
+ va_start(ap, fmt);
+ int size = vsnprintf(nullptr, 0, fmt, ap);
+ va_end(ap);
+ if (size >= 0) {
+ size++;
+ formatted = static_cast<char *>(malloc(size));
+ if (formatted != nullptr) {
+ va_start(ap, fmt);
+ size = vsnprintf(formatted, size, fmt, ap);
+ va_end(ap);
+ if (size < 0) {
+ free(formatted);
+ formatted = nullptr;
+ }
+ }
+ }
+
+ if (formatted != nullptr) {
+ throw std::runtime_error(formatted);
+ free(formatted);
+ }
+ throw std::runtime_error("Error parsing file");
+}
+
+s32 myrand()
+{
+ static u64 state = 1619236481962341ULL;
+ state *= 3123692312231ULL;
+ state++;
+ return state >> 33;
+}
+
+s16 qsample(s32 x, s32 scale)
+{
+ // Compute x / 2^scale rounded to the nearest integer, breaking ties towards zero.
+ if (scale == 0) return x;
+ return (x + (1 << (scale - 1)) - (x > 0)) >> scale;
+}
+
+s16 clamp_to_s16(s32 x)
+{
+ if (x < -0x8000) return -0x8000;
+ if (x > 0x7fff) return 0x7fff;
+ return (s16) x;
+}
+
+s32 toi4(s32 x)
+{
+ if (x >= 8) return x - 16;
+ return x;
+}
+
+s32 readaifccodebook(LUS::BinaryReader& fhandle, s32 ****table, s16 *order, s16 *npredictors)
+{
+ checked_fread(order, sizeof(s16), 1, fhandle);
+ BSWAP16(*order);
+ checked_fread(npredictors, sizeof(s16), 1, fhandle);
+ BSWAP16(*npredictors);
+ *table = static_cast<s32 ***>(malloc(*npredictors * sizeof(s32 **)));
+ for (s32 i = 0; i < *npredictors; i++) {
+ (*table)[i] = static_cast<s32 **>(malloc(8 * sizeof(s32 *)));
+ for (s32 j = 0; j < 8; j++) {
+ (*table)[i][j] = static_cast<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;
+ checked_fread(&ts, sizeof(s16), 1, fhandle);
+ 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(LUS::BinaryReader& reader, s16 *nloops) {
+ BSWAP16(*nloops);
+ checked_fread(nloops, sizeof(s16), 1, reader);
+ auto *al = static_cast<ALADPCMloop *>(malloc(*nloops * sizeof(ALADPCMloop)));
+ for (s32 i = 0; i < *nloops; i++) {
+ checked_fread(&al[i], sizeof(ALADPCMloop), 1, reader);
+ 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 *state, s32 order, s32 ***coefTable)
+{
+ s32 ix[16];
+
+ u8 header = frame[0];
+ s32 scale = 1 << (header >> 4);
+ s32 optimalp = header & 0xf;
+
+ 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 (ix[i] >= 8) ix[i] -= 16;
+ 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 my_encodeframe(u8 *out, s16 *inBuffer, s32 *state, s32 ***coefTable, s32 order, s32 npredictors)
+{
+ s16 ix[16];
+ s32 prediction[16];
+ s32 inVector[16];
+ s32 saveState[16];
+ s32 optimalp = 0;
+ s32 scale;
+ s32 ie[16];
+ s32 e[16];
+ f32 min = 1e30;
+
+ for (s32 k = 0; k < npredictors; k++) {
+ for (s32 j = 0; j < 2; j++) {
+ for (s32 i = 0; i < order; i++) {
+ inVector[i] = (j == 0 ? state[16 - order + i] : inBuffer[8 - order + i]);
+ }
+
+ for (s32 i = 0; i < 8; i++) {
+ prediction[j * 8 + i] = inner_product(order + i, coefTable[k][i], inVector);
+ e[j * 8 + i] = inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i];
+ }
+ }
+
+ f32 se = 0.0f;
+ for (s32 j = 0; j < 16; j++) {
+ se += (f32) e[j] * (f32) e[j];
+ }
+
+ if (se < min) {
+ min = se;
+ optimalp = k;
+ }
+ }
+
+ for (s32 j = 0; j < 2; j++) {
+ for (s32 i = 0; i < order; i++) {
+ inVector[i] = (j == 0 ? state[16 - order + i] : inBuffer[8 - order + i]);
+ }
+
+ for (s32 i = 0; i < 8; i++) {
+ prediction[j * 8 + i] = inner_product(order + i, coefTable[optimalp][i], inVector);
+ e[j * 8 + i] = inVector[i + order] = inBuffer[j * 8 + i] - prediction[j * 8 + i];
+ }
+ }
+
+ for (s32 i = 0; i < 16; i++) {
+ ie[i] = clamp_to_s16(e[i]);
+ }
+
+ s32 max = 0;
+ for (s32 i = 0; i < 16; i++) {
+ if (abs(ie[i]) > abs(max)) {
+ max = ie[i];
+ }
+ }
+
+ for (scale = 0; scale <= 12; scale++) {
+ if (max <= 7 && max >= -8) break;
+ max /= 2;
+ }
+
+ for (s32 i = 0; i < 16; i++) {
+ saveState[i] = state[i];
+ }
+
+ for (s32 nIter = 0, again = 1; nIter < 2 && again; nIter++) {
+ again = 0;
+ if (nIter == 1) scale++;
+ if (scale > 12) {
+ scale = 12;
+ }
+
+ for (s32 j = 0; j < 2; j++) {
+ s32 base = j * 8;
+ for (s32 i = 0; i < order; i++) {
+ inVector[i] = (j == 0 ?
+ saveState[16 - order + i] : state[8 - order + i]);
+ }
+
+ for (s32 i = 0; i < 8; i++) {
+ prediction[base + i] = inner_product(order + i, coefTable[optimalp][i], inVector);
+ s32 se = inBuffer[base + i] - prediction[base + i];
+ ix[base + i] = qsample(se, scale);
+ s32 cV = clamp_to_s16(ix[base + i]) - ix[base + i];
+ if (cV > 1 || cV < -1) again = 1;
+ ix[base + i] += cV;
+ inVector[i + order] = ix[base + i] * (1 << scale);
+ state[base + i] = prediction[base + i] + inVector[i + order];
+ }
+ }
+ }
+
+ u8 header = (scale << 4) | (optimalp & 0xf);
+ out[0] = header;
+ for (s32 i = 0; i < 16; i += 2) {
+ u8 c = ((ix[i] & 0xf) << 4) | (ix[i + 1] & 0xf);
+ out[1 + i/2] = c;
+ }
+}
+
+void permute(s16 *out, s32 *in, s32 scale)
+{
+ for (s32 i = 0; i < 16; i++) {
+ out[i] = clamp_to_s16(in[i] - scale / 2 + myrand() % (scale + 1));
+ }
+}
+
+void write_header(LUS::BinaryWriter& writer, const char *id, s32 size) {
+ writer.Write((char*) id, (size_t) 4);
+ BSWAP32(size);
+ writer.Write(size);
+}
+
+void write_aiff(std::vector<char> data, LUS::BinaryWriter& writer) {
+ s16 order = -1;
+ s16 nloops = 0;
+ ALADPCMloop *aloops = nullptr;
+ s16 npredictors = -1;
+ s32 ***coefTable = nullptr;
+ s32 state[16];
+ s32 soundPointer = -1;
+ s32 currPos = 0;
+ s32 nSamples = 0;
+ Chunk FormChunk;
+ ChunkHeader Header;
+ CommonChunk CommChunk;
+ InstrumentChunk InstChunk;
+ SoundDataChunk SndDChunk;
+
+ memset(&InstChunk, 0, sizeof(InstChunk));
+ LUS::BinaryReader reader((char*)data.data(), data.size());
+
+ checked_fread(&FormChunk, sizeof(FormChunk), 1, reader);
+ BSWAP32(FormChunk.ckID);
+ BSWAP32(FormChunk.formType);
+ if ((FormChunk.ckID != 0x464f524d) || (FormChunk.formType != 0x41494643)) { // FORM, AIFC
+ fail_parse("not an AIFF-C file");
+ }
+
+ for (;;) {
+ if (reader.GetBaseAddress() >= reader.GetLength()) {
+ break;
+ }
+ reader.Read((char*) &Header, sizeof(Header));
+ u32 ts;
+ BSWAP32(Header.ckID);
+ BSWAP32(Header.ckSize);
+
+ Header.ckSize++;
+ Header.ckSize &= ~1;
+ s32 offset = reader.GetBaseAddress();
+
+ if(Header.ckID == 0x434f4d4d) { // COMM
+ checked_fread(&CommChunk, sizeof(CommChunk), 1, reader);
+ 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) { // VAPC
+ fail_parse("file is of the wrong compression type");
+ }
+ 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--;
+ }
+
+ if (nSamples % 16 != 0) {
+ fail_parse("number of chunks must be a multiple of 16, found %d", nSamples);
+ }
+ }
+
+ if(Header.ckID == 0x53534e44) { //SSND
+ checked_fread(&SndDChunk, sizeof(SndDChunk), 1, reader);
+ BSWAP32(SndDChunk.offset);
+ BSWAP32(SndDChunk.blockSize);
+ assert(SndDChunk.offset == 0);
+ assert(SndDChunk.blockSize == 0);
+ soundPointer = reader.GetBaseAddress();
+ }
+
+ if(Header.ckID == 0x4150504c){ // APPL
+ checked_fread(&ts, sizeof(u32), 1, reader);
+ BSWAP32(ts);
+ if (ts == 0x73746f63) { // stoc
+ u8 len;
+ checked_fread(&len, 1, 1, reader);
+ if (len == 11) {
+ char ChunkName[12];
+ s16 version;
+ checked_fread(ChunkName, 11, 1, reader);
+ ChunkName[11] = '\0';
+ if (strcmp("VADPCMCODES", ChunkName) == 0) {
+ checked_fread(&version, sizeof(s16), 1, reader);
+ BSWAP16(version);
+ if (version != 1) {
+ fail_parse("Unknown codebook chunk version");
+ }
+ readaifccodebook(reader, &coefTable, &order, &npredictors);
+ }
+ else if (strcmp("VADPCMLOOPS", ChunkName) == 0) {
+ checked_fread(&version, sizeof(s16), 1, reader);
+ BSWAP16(version);
+ if (version != 1) {
+ fail_parse("Unknown loop chunk version");
+ }
+ aloops = readlooppoints(reader, &nloops);
+ BSWAP16(nloops);
+ if (nloops != 1) {
+ fail_parse("Only a single loop supported");
+ }
+ }
+ }
+ }
+ }
+
+ reader.Seek(offset + Header.ckSize, LUS::SeekOffsetType::Start);
+ }
+
+ if (coefTable == nullptr) {
+ fail_parse("Codebook missing from bitstream");
+ }
+
+ for (s32 i = 0; i < order; i++) {
+ state[15 - i] = 0;
+ }
+
+ u32 outputBytes = nSamples * sizeof(s16);
+
+ reader.Seek(soundPointer, LUS::SeekOffsetType::Start);
+
+ 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(lastState));
+ checked_fread(input, 9, 1, reader);
+
+ // Decode for real
+ my_decodeframe(input, state, order, coefTable);
+ memcpy(decoded, state, sizeof(lastState));
+
+ // Create a guess from that, by clamping to 16 bits
+ for (s32 i = 0; i < 16; i++) {
+ origGuess[i] = clamp_to_s16(state[i]);
+ }
+
+ // Encode the guess
+ memcpy(state, lastState, sizeof(lastState));
+ memcpy(guess, origGuess, sizeof(guess));
+ my_encodeframe(encoded, guess, state, coefTable, order, npredictors);
+
+ // If it doesn't match, randomly round numbers until it does.
+ if (memcmp(input, encoded, 9) != 0) {
+ s32 scale = 1 << (input[0] >> 4);
+ do {
+ permute(guess, decoded, scale);
+ memcpy(state, lastState, sizeof(lastState));
+ my_encodeframe(encoded, guess, state, coefTable, order, npredictors);
+ } while (memcmp(input, encoded, 9) != 0);
+
+ // Bring the matching closer to the original decode (not strictly
+ // necessary, but it will move us closer to the target on average).
+ for (s32 failures = 0; failures < 50; failures++) {
+ s32 ind = myrand() % 16;
+ s32 old = guess[ind];
+ if (old == origGuess[ind]) continue;
+ guess[ind] = origGuess[ind];
+ if (myrand() % 2) guess[ind] += (old - origGuess[ind]) / 2;
+ memcpy(state, lastState, sizeof(lastState));
+ my_encodeframe(encoded, guess, state, coefTable, order, npredictors);
+ if (memcmp(input, encoded, 9) == 0) {
+ failures = -1;
+ }
+ else {
+ guess[ind] = old;
+ }
+ }
+ }
+
+ memcpy(state, decoded, sizeof(lastState));
+ BSWAP16_MANY(guess, 16);
+ writer.Seek(currPos * 2, LUS::SeekOffsetType::Start);
+ writer.Write((char*) guess, sizeof(guess));
+ currPos += 16;
+ }
+
+ // Write an incomplete file header. We'll fill in the size later.
+ writer.Seek(0, LUS::SeekOffsetType::Start);
+ writer.Write((char*) "FORM\0\0\0\0AIFF", 12);
+
+ // Subtract 4 from the COMM size to skip the compression field.
+ write_header(writer, "COMM", sizeof(CommonChunk) - 4);
+ CommChunk.numFramesH = nSamples >> 16;
+ CommChunk.numFramesL = nSamples & 0xffff;
+ BSWAP16(CommChunk.numChannels);
+ BSWAP16(CommChunk.numFramesH);
+ BSWAP16(CommChunk.numFramesL);
+ BSWAP16(CommChunk.sampleSize);
+ writer.Write((char*) &CommChunk, sizeof(CommonChunk) - 4);
+
+ if (nloops > 0) {
+ s32 startPos = aloops[0].start, endPos = aloops[0].end;
+ const char *markerNames[2] = {"start", "end"};
+ Marker markers[2] = {
+ {1, static_cast<u16>((u16) startPos >> 16), static_cast<u16>((u16) startPos & 0xffff)},
+ {2, static_cast<u16>(endPos >> 16), static_cast<u16>(endPos & 0xffff)}
+ };
+ write_header(writer, "MARK", 2 + 2 * sizeof(Marker) + 1 + 5 + 1 + 3);
+ s16 numMarkers = bswap16(2);
+ writer.Write(numMarkers);
+ 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);
+ writer.Write(markers[i].MarkerID);
+ writer.Write(markers[i].positionH);
+ writer.Write(markers[i].positionL);
+ writer.Write(len);
+ writer.Write((char*) markerNames[i], len);
+ }
+
+ write_header(writer, "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;
+ writer.Write((char*) &InstChunk, sizeof(InstrumentChunk));
+ }
+
+ // 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(writer, "APPL", 4 + 12 + sizeof(CodeChunk) + npredictors * order * 8 * 2);
+ writer.Write("stoc", false);
+ CodeChunk cChunk;
+ cChunk.version = bswap16(1);
+ cChunk.order = bswap16(order);
+ cChunk.nEntries = bswap16(npredictors);
+ writer.Write("\x0bVADPCMCODES", false);
+ writer.Write((char*) &cChunk, sizeof(CodeChunk));
+ 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]);
+ writer.Write(ts);
+ }
+ }
+ }
+
+ write_header(writer, "SSND", outputBytes + 8);
+ SndDChunk.offset = 0;
+ SndDChunk.blockSize = 0;
+ writer.Write((char*) &SndDChunk, sizeof(SoundDataChunk));
+
+ // Fix the size in the header
+ s32 fileSize = bswap32(writer.GetLength() - 8);
+ writer.Seek(4, LUS::SeekOffsetType::Start);
+ writer.Write(fileSize);
+
+ reader.Close();
+}
diff --git a/src/audio/AIFCDecode.h b/src/audio/AIFCDecode.h
new file mode 100644
index 0000000..e141a80
--- /dev/null
+++ b/src/audio/AIFCDecode.h
@@ -0,0 +1,6 @@
+#pragma once
+
+#include <vector>
+#include "BinaryWriter.h"
+
+void write_aiff(std::vector<char> data, LUS::BinaryWriter& writer); \ No newline at end of file
diff --git a/src/audio/AudioManager.cpp b/src/audio/AudioManager.cpp
new file mode 100644
index 0000000..2316141
--- /dev/null
+++ b/src/audio/AudioManager.cpp
@@ -0,0 +1,664 @@
+#include "AudioManager.h"
+
+#include <vector>
+#include <sstream>
+#include <fstream>
+#include <iostream>
+#include <filesystem>
+#include "hj/pyutils.h"
+#include "binarytools/BinaryReader.h"
+#include "hj/zip.h"
+#include <nlohmann/json.hpp>
+
+std::unordered_map<std::string, uint32_t> name_table;
+AudioManager* AudioManager::Instance;
+
+std::vector<uint32_t> PyUtils::range(uint32_t start, uint32_t end) {
+ std::vector<uint32_t> result;
+ for (uint32_t i = start; i < end; ++i) {
+ result.push_back(i);
+ }
+ return result;
+}
+
+std::string gen_name(const std::string& prefix){
+ if(!name_table.contains(prefix)){
+ name_table[prefix] = 0;
+ }
+ return prefix + std::to_string(name_table[prefix]++);
+}
+
+AudioBankSample* SampleBank::AddSample(uint32_t addr, size_t sampleSize, const AdpcmBook& book, const AdpcmLoop& loop){
+ assert(sampleSize % 2 == 0);
+ if(sampleSize % 9 != 0){
+ assert(sampleSize % 9 == 1);
+ sampleSize -= 1;
+ }
+
+ AudioBankSample* entry;
+
+ if(this->entries.contains(addr)){
+ entry = this->entries[addr];
+ assert(entry->book == book);
+ assert(entry->loop == loop);
+ assert(entry->data.size() == sampleSize);
+ } else {
+ entry = new AudioBankSample{ gen_name("aifc"), PyUtils::slice(this->data, addr, addr + sampleSize), book, loop };
+ this->entries[addr] = entry;
+ }
+
+ return entry;
+}
+
+void Bank::print() const {
+ std::cout << "Bank: " << name << std::endl;
+ std::cout << "Instruments: " << std::to_string(insts.size()) << std::endl;
+ std::cout << "Drums: " << std::to_string(drums.size()) << std::endl;
+ std::cout << "Samples: " << std::to_string(samples.size()) << std::endl;
+ std::cout << "Envelopes: " << std::to_string(envelopes.size()) << std::endl;
+ std::cout << "All Instruments: " << std::to_string(allInsts.size()) << std::endl;
+ std::cout << "Inst Offsets: " << std::to_string(instOffsets.size()) << std::endl;
+ std::cout << "Sample Bank: " << sampleBank->name << std::endl;
+ std::cout << "Sample Bank Offset: " << std::to_string(sampleBank->offset) << std::endl;
+}
+
+std::vector<Entry> AudioManager::parse_seq_file(std::vector<uint8_t>& buffer, uint32_t offset, bool isCTL){
+ std::vector<Entry> entries;
+ LUS::BinaryReader reader((char*) buffer.data(), buffer.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+ reader.Seek(offset, LUS::SeekOffsetType::Start);
+
+ uint16_t magic = reader.ReadUInt16();
+ uint16_t num_entries = reader.ReadUInt16();
+ uint32_t prev = ALIGN(4 + num_entries * 8, 16);
+
+ assert(magic == (isCTL ? 1 : 2));
+
+ for (int i = 0; i < num_entries; ++i) {
+ reader.Seek((offset + 4) + (i * 8), LUS::SeekOffsetType::Start);
+ uint32_t addr = reader.ReadUInt32();
+ uint32_t length = reader.ReadUInt32();
+
+ if(isCTL){
+ assert(addr == prev);
+ } else {
+ assert(addr <= prev);
+ }
+
+ prev = std::max(prev, addr + length);
+ entries.push_back({addr, length});
+ }
+
+ reader.Close();
+ return entries;
+}
+
+CTLHeader AudioManager::parse_ctl_header(std::vector<uint8_t>& data){
+ LUS::BinaryReader reader((char*) data.data(), data.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+
+ CTLHeader header = { reader.ReadUInt32(), reader.ReadUInt32(), reader.ReadUInt32() };
+
+ reader.Close();
+ return header;
+}
+
+Bank AudioManager::parse_ctl(CTLHeader header, std::vector<uint8_t> data, SampleBank* bank, uint32_t index) {
+ name_table.clear();
+ std::ostringstream ss;
+ ss << std::hex << std::setw(2) << std::setfill('0') << index;
+ std::string name = ss.str();
+ uint32_t numInstruments = header.instruments;
+ uint32_t numDrums = header.numDrums;
+ char* rawData = (char*) data.data();
+
+ uint32_t drumBaseAddr;
+ memcpy(&drumBaseAddr, rawData, 4);
+ drumBaseAddr = BSWAP32(drumBaseAddr);
+
+ std::vector<uint32_t> drumOffsets;
+
+ if(numDrums != 0){
+ assert(drumBaseAddr != 0);
+ for (size_t i = 0; i < numDrums; ++i) {
+ uint32_t drumOffset;
+ memcpy(&drumOffset, rawData + drumBaseAddr + i * 4, 4);
+ drumOffset = BSWAP32(drumOffset);
+ assert(drumOffset != 0);
+ drumOffsets.push_back(drumOffset);
+ }
+ } else {
+ assert(drumBaseAddr == 0);
+ }
+
+ uint32_t instrumentBaseAddr = 4;
+ std::vector<uint32_t> instrumentOffsets;
+ std::vector<uint32_t> instrumentList;
+
+ for (size_t i = 0; i < numInstruments; ++i) {
+ uint32_t instOffset;
+ memcpy(&instOffset, rawData + (instrumentBaseAddr + i * 4), 4);
+ instOffset = BSWAP32(instOffset);
+ if(instOffset == 0){
+ instrumentList.push_back(NONE);
+ instrumentOffsets.push_back(NONE);
+ } else {
+ instrumentOffsets.push_back(instOffset);
+ instrumentList.push_back(instOffset);
+ }
+ }
+
+// std::sort(instrumentOffsets.begin(), instrumentOffsets.end());
+
+ std::vector<Instrument> insts;
+ for(auto &offset : instrumentOffsets){
+ if(offset == NONE){
+ Instrument invalid = { .valid = false };
+ insts.push_back(invalid);
+ continue;
+ }
+ auto rInst = PyUtils::slice(data, offset, offset + 32);
+ Instrument inst = parse_inst(rInst, offset);
+ insts.push_back(inst);
+ }
+
+ std::vector<Drum> drums;
+ for(auto &offset : drumOffsets){
+ auto rDrum = PyUtils::slice(data, offset, offset + 16);
+ Drum drum = parse_drum(rDrum, offset);
+ drums.push_back(drum);
+ }
+
+ auto envOffsets = std::vector<uint32_t>();
+ auto sampleOffsets = std::vector<uint32_t>();
+ auto tunings = std::unordered_map<uint32_t, float>();
+
+ for(auto &inst : insts){
+ for(auto &sound : {inst.soundLo, inst.soundMed, inst.soundHi}){
+ if(sound.has_value()){
+ sampleOffsets.push_back(sound.value().offset);
+ tunings[sound.value().offset] = sound.value().tuning;
+ }
+ }
+ envOffsets.push_back(inst.envelope);
+ }
+ for(auto &drum : drums){
+ sampleOffsets.push_back(drum.sound.offset);
+ tunings[drum.sound.offset] = drum.sound.tuning;
+ envOffsets.push_back(drum.envelope);
+ }
+ // Put drums somewhere in the middle of the instruments to make sample
+ // addresses come in increasing order. (This logic isn't totally right,
+ // but it works for our purposes.)
+ std::vector<std::variant<Instrument, std::vector<Drum>>> allInsts;
+ bool needDrums = !drums.empty();
+ for(auto &inst : insts){
+ std::vector<std::optional<AudioBankSound>> sounds = {inst.soundLo, inst.soundMed, inst.soundHi};
+
+ if(needDrums && std::any_of(sounds.cbegin(), sounds.cend(), [&drums](std::optional<AudioBankSound> sound){ return sound.has_value() && sound.value().offset > drums[0].sound.offset; })){
+ allInsts.emplace_back(drums);
+ needDrums = false;
+ }
+
+ allInsts.emplace_back(inst);
+ }
+
+
+ if(needDrums){
+ allInsts.emplace_back(drums);
+ }
+
+ std::map<uint32_t, AudioBankSample*> samples;
+ std::sort(sampleOffsets.begin(), sampleOffsets.end());
+ for(auto &offset : sampleOffsets){
+ auto rSample = PyUtils::slice(data, offset, offset + 20);
+ AudioBankSample* sample = parse_sample(rSample, data, bank);
+ for(auto &tuning : tunings){
+ sample->tunings.push_back(tuning.second);
+ }
+ samples[offset] = sample;
+ }
+
+ std::unordered_map<uint32_t, std::vector<AdsrEnvelope>> envData;
+ std::vector<uint32_t> usedEnvOffsets;
+ std::sort(envOffsets.begin(), envOffsets.end());
+ for(auto &offset : envOffsets){
+ auto env = parse_envelope(offset, data);
+ envData[offset] = env;
+ for(int i = 0; i < ALIGN(env.size(), 4); i++){
+ usedEnvOffsets.push_back(offset + (i * 4));
+ }
+ }
+
+ std::vector<uint32_t> unusedEnvOffsets;
+ if(!usedEnvOffsets.empty()){
+ size_t min = std::min_element(usedEnvOffsets.begin(), usedEnvOffsets.end()) - usedEnvOffsets.begin();
+ size_t max = std::max_element(usedEnvOffsets.begin(), usedEnvOffsets.end()) - usedEnvOffsets.begin();
+ for(size_t idx = min + 4; idx < max; idx += 4){
+ uint32_t addr = usedEnvOffsets[idx];
+ if(std::find(usedEnvOffsets.begin(), usedEnvOffsets.end(), addr) == usedEnvOffsets.end()){
+ unusedEnvOffsets.push_back(addr);
+ uint32_t stubMarker;
+ memcpy(&stubMarker, rawData + addr, 4);
+ stubMarker = BSWAP32(stubMarker);
+ assert(stubMarker == 0);
+ auto env = parse_envelope(addr, data);
+ envData[addr] = env;
+ for(int i = 0; i < ALIGN(env.size(), 4); i++){
+ usedEnvOffsets.push_back(addr + (i * 4));
+ }
+ }
+ }
+ }
+
+ std::map<uint32_t, Envelope> envelopes;
+ for(auto &entry : envData){
+ Envelope env = { gen_name("envelope"), entry.second };
+ envelopes[entry.first] = env;
+ }
+
+ Bank bankData = { name, bank, insts, drums, allInsts, instrumentList, envelopes, samples };
+ return bankData;
+}
+
+std::optional<AudioBankSound> AudioManager::parse_sound(std::vector<uint8_t> data) {
+ LUS::BinaryReader reader((char*) data.data(), data.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+
+ uint32_t addr = reader.ReadUInt32();
+ float tuning = reader.ReadFloat();
+
+ if(addr == 0){
+ assert(tuning == 0.0f);
+ return std::nullopt;
+ }
+
+ AudioBankSound sound = { addr, tuning };
+
+ reader.Close();
+ return sound;
+}
+
+Drum AudioManager::parse_drum(std::vector<uint8_t>& data, uint32_t addr) {
+ LUS::BinaryReader reader((char*) data.data(), data.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+ std::string name = gen_name("drum");
+
+ uint8_t releaseRate = reader.ReadInt8();
+ uint8_t pan = reader.ReadInt8();
+
+ reader.Seek(12, LUS::SeekOffsetType::Start);
+ AudioBankSound sound = parse_sound(PyUtils::slice(data, 4, 12)).value();
+ uint32_t envOffset = reader.ReadInt32();
+ assert(envOffset != 0);
+
+ Drum drum = { name, addr, releaseRate, pan, envOffset, sound };
+
+ return drum;
+}
+
+Instrument AudioManager::parse_inst(std::vector<uint8_t>& data, uint32_t addr) {
+ std::string name = gen_name("inst");
+ uint8_t normalRangeLo = data[1];
+ uint8_t normalRangeHi = data[2];
+ uint8_t releaseRate = data[3];
+
+ uint32_t envAddr;
+ memcpy(&envAddr, (char*) data.data() + 4, 4);
+ envAddr = BSWAP32(envAddr);
+
+ assert(envAddr != 0);
+
+ auto soundLo = parse_sound(PyUtils::slice(data, 8, 16));
+ auto soundMed = parse_sound(PyUtils::slice(data, 16, 24));
+ auto soundHi = parse_sound(PyUtils::slice(data, 24));
+
+ if (soundLo == std::nullopt) {
+ assert(normalRangeLo == 0);
+ }
+ if (soundHi == std::nullopt) {
+ assert(normalRangeHi == 127);
+ }
+
+ Instrument inst = { true, name, addr, releaseRate, normalRangeLo, normalRangeHi, envAddr, soundLo, soundMed, soundHi };
+ return inst;
+}
+
+AdpcmLoop AudioManager::parse_loop(uint32_t addr, std::vector<uint8_t>& bankData){
+ LUS::BinaryReader reader((char*) bankData.data(), bankData.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+ reader.Seek(addr, LUS::SeekOffsetType::Start);
+
+ std::optional<std::vector<int16_t>> state = std::nullopt;
+ uint32_t start = reader.ReadUInt32();
+ uint32_t end = reader.ReadUInt32();
+ int32_t count = reader.ReadInt32();
+ uint32_t pad = reader.ReadUInt32();
+
+ if(count != 0){
+ state = std::vector<int16_t>();
+ for (size_t i = 0; i < 16; ++i) {
+ state.value().push_back(reader.ReadInt16());
+ }
+ }
+ AdpcmLoop loop = { start, end, count, pad, state };
+ return loop;
+}
+
+AdpcmBook AudioManager::parse_book(uint32_t addr, std::vector<uint8_t>& bankData){
+ LUS::BinaryReader reader((char*) bankData.data(), bankData.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+ reader.Seek(addr, LUS::SeekOffsetType::Start);
+
+ int32_t order = reader.ReadInt32();
+ int32_t npredictors = reader.ReadInt32();
+
+ assert(order == 2);
+ assert(npredictors == 2);
+
+ std::vector<int16_t> table;
+ std::vector<uint8_t> tableData = PyUtils::slice(bankData, addr + 8, addr + 8 + 16 * order * npredictors);
+ for (size_t i = 0; i < ( 16 * order * npredictors ); i += 2) {
+ int16_t dtable;
+ memcpy(&dtable, tableData.data() + i, 2);
+ table.push_back(BSWAP16(dtable));
+ }
+
+ AdpcmBook book = { order, npredictors, table };
+ return book;
+}
+
+AudioBankSample* AudioManager::parse_sample(std::vector<uint8_t>& data, std::vector<uint8_t>& bankData, SampleBank* sampleBank){
+ LUS::BinaryReader reader((char*) data.data(), data.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+
+ uint32_t zero = reader.ReadUInt32();
+ uint32_t addr = reader.ReadUInt32();
+ uint32_t loop = reader.ReadUInt32();
+ uint32_t book = reader.ReadUInt32();
+ uint32_t sampleSize = reader.ReadUInt32();
+ assert(zero == 0);
+ assert(loop != 0);
+ assert(book != 0);
+
+ AdpcmLoop loopData = parse_loop(loop, bankData);
+ AdpcmBook bookData = parse_book(book, bankData);
+
+ reader.Close();
+ return sampleBank->AddSample(addr, sampleSize, bookData, loopData);
+}
+
+
+std::vector<AdsrEnvelope> AudioManager::parse_envelope(uint32_t addr, std::vector<uint8_t>& dataBank){
+ std::vector<AdsrEnvelope> entries;
+ LUS::BinaryReader reader((char*) dataBank.data(), dataBank.size());
+ reader.SetEndianness(LUS::Endianness::Big);
+
+ while(true){
+ reader.Seek(addr, LUS::SeekOffsetType::Start);
+ int16_t delay = reader.ReadInt16();
+ int16_t arg = reader.ReadInt16();
+ AdsrEnvelope entry = { delay, arg };
+ entries.push_back(entry);
+ addr += 4;
+ if (1 <= (-delay) % (1 << 16) && (-delay) % (1 << 16) <= 3){
+ break;
+ }
+ }
+
+ reader.Close();
+ return entries;
+}
+
+TBLFile AudioManager::parse_tbl(std::vector<uint8_t>& data, std::vector<Entry>& entries) {
+ TBLFile tbl;
+ std::unordered_map<uint32_t, std::string> cache;
+ for(auto &entry : entries){
+ if(!cache.contains(entry.offset)){
+ std::string name = gen_name("sample_bank");
+ auto* sampleBank = new SampleBank{
+ name, entry.offset, PyUtils::slice(data, entry.offset, entry.offset + entry.length)
+ };
+ tbl.banks.push_back(sampleBank);
+ tbl.map[name] = sampleBank;
+ cache[entry.offset] = name;
+ }
+ tbl.tbls.push_back(cache[entry.offset]);
+ }
+ cache.clear();
+ return tbl;
+}
+
+void AudioManager::initialize(std::vector<uint8_t>& buffer) {
+ auto assets = nlohmann::json::parse(std::ifstream( "assets.json" ));
+ auto sound_data = assets["@sound_data"]["us"];
+
+ auto sound_tbl = sound_data["sound_tbl"];
+ auto sound_ctl = sound_data["sound_ctl"];
+
+ std::vector<Entry> tbl = parse_seq_file(buffer, sound_tbl[0], false);
+ std::vector<Entry> ctl = parse_seq_file(buffer, sound_ctl[0], true);
+
+ std::cout << "Table entries: " << tbl.size() << std::endl;
+ std::cout << "Control entries: " << ctl.size() << std::endl;
+
+ std::vector<uint8_t> tbl_data = PyUtils::slice(buffer, sound_tbl[0], (size_t) sound_tbl[0] + (size_t) sound_tbl[1]);
+ std::vector<uint8_t> ctl_data = PyUtils::slice(buffer, sound_ctl[0], (size_t) sound_ctl[0] + (size_t) sound_ctl[1]);
+ this->loaded_tbl = parse_tbl(tbl_data, tbl);
+
+ std::cout << "TBLs: " << this->loaded_tbl.tbls.size() << std::endl;
+ std::cout << "Banks: " << this->loaded_tbl.banks.size() << std::endl;
+ std::cout << "Map: " << this->loaded_tbl.map.size() << std::endl;
+
+ auto zipped = zip(PyUtils::range(0, ctl.size()), ctl, this->loaded_tbl.tbls);
+
+ for (const auto& item : zipped) {
+ auto [index, ctrl, sample_bank_name] = item;
+ auto sample_bank = this->loaded_tbl.map[sample_bank_name];
+ auto entry = PyUtils::slice(ctl_data, ctrl.offset, ctrl.offset + ctrl.length);
+ auto headerRaw = PyUtils::slice(entry, 0, 16);
+ auto header = parse_ctl_header(headerRaw);
+ auto bank = parse_ctl(header, PyUtils::slice(entry, 16), sample_bank, index);
+ banks[index] = bank;
+ }
+
+ int32_t idx = -1;
+ for(auto &sample_bank : this->loaded_tbl.banks){
+ auto offsets = PyUtils::keys(sample_bank->entries);
+ std::sort(offsets.begin(), offsets.end());
+
+ for(auto &offset : offsets){
+ this->sampleMap[sample_bank->entries[offset]] = ++idx;
+ }
+ }
+}
+
+void serialize_f80(double num, LUS::BinaryWriter &writer) {
+ // Convert the input double to an uint64_t
+ std::uint64_t f64;
+ std::memcpy(&f64, &num, sizeof(double));
+
+ std::uint64_t f64_sign_bit = f64 & (std::uint64_t) pow(2, 63);
+ if (num == 0.0) {
+ if (f64_sign_bit) {
+ writer.Write(0x80000000);
+ } else {
+ writer.Write(0x00000000);
+ }
+ }
+
+ std::uint64_t exponent = ((f64 ^ f64_sign_bit) >> 52);
+
+ assert(exponent != 0);
+ assert(exponent != 0x7FF);
+
+ exponent -= 1023;
+ uint64_t f64_mantissa_bits = f64 & (uint64_t) pow(2, 52) - 1;
+ uint64_t f80_sign_bit = f64_sign_bit << (80 - 64);
+ uint64_t f80_exponent = (exponent + 0x3FFF) << 64;
+ uint64_t f80_mantissa_bits = (uint64_t) pow(2, 63) | (f64_mantissa_bits << (63 - 52));
+ uint64_t f80 = f80_sign_bit | f80_exponent | f80_mantissa_bits;
+
+ // Split the f80 representation into two parts (high and low)
+ uint16_t high = BSWAP16((uint16_t) f80 >> 64);
+ writer.Write((char*) &high, 2);
+ uint64_t low = BSWAP64(f80 & ((uint64_t) pow(2, 64) - 1));
+ writer.Write((char*) &low, 8);
+}
+
+#define START_SECTION(section) \
+ { \
+ out.Write(BSWAP32(section)); \
+ LUS::BinaryWriter tmp = LUS::BinaryWriter(); \
+ tmp.SetEndianness(LUS::Endianness::Big); \
+
+#define START_CUSTOM_SECTION(section) \
+ { \
+ LUS::BinaryWriter tmp = LUS::BinaryWriter(); \
+ tmp.SetEndianness(LUS::Endianness::Big); \
+ out.Write(BSWAP32(AIFC::MagicValues::AAPL)); \
+ tmp.Write(AIFC::MagicValues::stoc); \
+ tmp.Write(section, false); \
+
+#define END_SECTION() \
+ auto odata = tmp.ToVector(); \
+ size_t size = odata.size(); \
+ len += ALIGN(size, 2) + 8; \
+ out.Write(BSWAP32((uint32_t) size)); \
+ out.Write(odata.data(), odata.size()); \
+ if(size % 2){ \
+ out.WriteByte(0); \
+ } \
+ } \
+
+void AudioManager::write_aifc(AudioBankSample* entry, LUS::BinaryWriter &out) {
+ int16_t num_channels = 1;
+ auto data = entry->data;
+ size_t len = 0;
+ assert(data.size() % 9 == 0);
+ if(data.size() % 2 == 1){
+ data.push_back('\0');
+ }
+ uint32_t num_frames = data.size() * 16 / 9;
+ int16_t sample_size = 16;
+
+ uint32_t sample_rate = -1;
+ if(entry->tunings.size() == 1){
+ sample_rate = 32000 * entry->tunings[0];
+ } else {
+ float tmin = PyUtils::min(entry->tunings);
+ float tmax = PyUtils::max(entry->tunings);
+
+ if(tmin <= 0.5f <= tmax){
+ sample_rate = 16000;
+ } else if(tmin <= 1.0f <= tmax){
+ sample_rate = 32000;
+ } else if(tmin <= 1.5f <= tmax){
+ sample_rate = 48000;
+ } else if(tmin <= 2.5f <= tmax){
+ sample_rate = 80000;
+ } else {
+ sample_rate = 16000 * (tmin + tmax);
+ }
+ }
+
+ out.Write(BSWAP32(AIFC::MagicValues::FORM));
+ // This should be where the size is, but we need to write it later
+ out.Write((uint32_t) 0);
+ out.Write(BSWAP32(AIFC::MagicValues::AIFC));
+
+ START_SECTION(AIFC::MagicValues::COMM);
+
+ tmp.Write((uint16_t) num_channels);
+ tmp.Write((uint32_t) num_frames);
+
+ tmp.Write((uint16_t) sample_size);
+ serialize_f80(sample_rate, tmp);
+ tmp.Write(AIFC::MagicValues::VAPC);
+ tmp.Write("\x0bVADPCM ~4-1", false);
+
+ END_SECTION();
+
+ START_SECTION(AIFC::MagicValues::INST)
+ tmp.Write(std::string(20, '\0'), false);
+ END_SECTION();
+
+ START_CUSTOM_SECTION("\x0bVADPCMCODES")
+ tmp.Write((uint16_t) 1);
+ tmp.Write((uint16_t) entry->book.order);
+ tmp.Write((uint16_t) entry->book.npredictors);
+
+ for(auto x : entry->book.table){
+ tmp.Write((int16_t) x);
+ }
+ END_SECTION();
+
+ START_SECTION(AIFC::MagicValues::SSND)
+ uint32_t zero = 0;
+ tmp.Write((char*) &zero, 4);
+ tmp.Write((char*) &zero, 4);
+ tmp.Write((char*) data.data(), data.size());
+ END_SECTION();
+
+ if(entry->loop.count != 0){
+ START_CUSTOM_SECTION("\x0bVADPCMLOOPS")
+ uint16_t one = BSWAP16(1);
+ tmp.Write((char*) &one, 2);
+ tmp.Write((char*) &one, 2);
+ tmp.Write((uint32_t) entry->loop.start);
+ tmp.Write((uint32_t) entry->loop.end);
+ tmp.Write((int32_t) entry->loop.count);
+ for(size_t i = 0; i < 16; i++){
+ int16_t loop = BSWAP16(entry->loop.state.value()[i]);
+ tmp.Write((char*) &loop, 2);
+ }
+ END_SECTION();
+ }
+
+ len += 4;
+ out.Seek(4, LUS::SeekOffsetType::Start);
+ out.Write((uint32_t) BSWAP32(len));
+
+}
+
+void AudioManager::create_aifc(int32_t index, LUS::BinaryWriter &out) {
+ int32_t idx = -1;
+ for(auto &sample_bank : this->loaded_tbl.banks){
+ auto offsets = PyUtils::keys(sample_bank->entries);
+ std::sort(offsets.begin(), offsets.end());
+
+ for(auto &offset : offsets){
+ if(++idx == index){
+ write_aifc(sample_bank->entries[offset], out);
+ return;
+ }
+ }
+ }
+}
+
+AudioBankSample AudioManager::get_aifc(int32_t index) {
+ int32_t idx = -1;
+ for(auto &sample_bank : this->loaded_tbl.banks){
+ auto offsets = PyUtils::keys(sample_bank->entries);
+ std::sort(offsets.begin(), offsets.end());
+
+ for(auto &offset : offsets){
+ if(++idx == index){
+ return *sample_bank->entries[offset];
+ }
+ }
+ }
+
+ throw std::runtime_error("Invalid index");
+}
+
+uint32_t AudioManager::get_index(AudioBankSample* entry) {
+ if(!this->sampleMap.contains(entry)){
+ return -1;
+ }
+ return this->sampleMap[entry];
+}
+
+std::map<uint32_t, Bank> AudioManager::get_banks() {
+ return this->banks;
+} \ No newline at end of file
diff --git a/src/audio/AudioManager.h b/src/audio/AudioManager.h
new file mode 100644
index 0000000..4b5d9ce
--- /dev/null
+++ b/src/audio/AudioManager.h
@@ -0,0 +1,161 @@
+#pragma once
+
+#include <map>
+#include <vector>
+#include <string>
+#include <iostream>
+#include "binarytools/BinaryWriter.h"
+
+#define NONE 0xFFFF
+#define ALIGN(val, al) (size_t) ((val + (al - 1)) & -al)
+
+namespace AIFC {
+ enum MagicValues {
+ FORM = 0x464f524d,
+ AIFC = 0x41494643,
+ COMM = 0x434f4d4d,
+ INST = 0x494e5354,
+ VAPC = 0x56415043,
+ SSND = 0x53534e44,
+ AAPL = 0x4150504c,
+ stoc = 0x73746f63,
+ };
+}
+
+struct Entry {
+ uint32_t offset;
+ uint32_t length;
+};
+
+struct AudioBankSound {
+ uint32_t offset;
+ float tuning;
+ bool operator==(const AudioBankSound& other) const {
+ return offset == other.offset && tuning == other.tuning;
+ }
+};
+
+struct Instrument {
+ bool valid;
+ std::string name;
+ uint32_t offset;
+ uint8_t releaseRate;
+ uint8_t normalRangeLo;
+ uint8_t normalRangeHi;
+ uint32_t envelope;
+ std::optional<AudioBankSound> soundLo;
+ std::optional<AudioBankSound> soundMed;
+ std::optional<AudioBankSound> soundHi;
+};
+
+struct AdpcmBook {
+ int32_t order{};
+ int32_t npredictors{};
+ std::vector<int16_t> table;
+ bool operator==(const AdpcmBook& other) const {
+ return order == other.order && npredictors == other.npredictors && table == other.table;
+ }
+};
+
+struct Drum {
+ std::string name;
+ uint32_t offset;
+ uint8_t releaseRate;
+ uint8_t pan;
+ uint32_t envelope;
+ AudioBankSound sound;
+ bool operator==(const Drum& other) const {
+ return name == other.name && offset == other.offset && releaseRate == other.releaseRate && pan == other.pan && envelope == other.envelope && sound == other.sound;
+ }
+};
+
+struct AdpcmLoop {
+ uint32_t start{};
+ uint32_t end{};
+ int32_t count{};
+ uint32_t pad{};
+ std::optional<std::vector<int16_t>> state;
+ bool operator==(const AdpcmLoop& other) const {
+ return start == other.start && end == other.end && count == other.count && pad == other.pad && state == other.state;
+ }
+};
+
+struct AudioBankSample {
+ std::string name;
+ std::vector<uint8_t> data;
+ AdpcmBook book;
+ AdpcmLoop loop;
+ std::vector<float> tunings;
+};
+
+struct SampleBank {
+ std::string name;
+ uint32_t offset;
+ std::vector<uint8_t> data;
+ std::map<uint32_t, AudioBankSample*> entries;
+
+ AudioBankSample* AddSample(uint32_t addr, size_t sampleSize, const AdpcmBook& book, const AdpcmLoop& loop);
+};
+
+struct TBLFile {
+ std::vector<SampleBank*> banks;
+ std::vector<std::string> tbls;
+ std::map<std::string, SampleBank*> map;
+};
+
+struct CTLHeader {
+ uint32_t instruments;
+ uint32_t numDrums;
+ uint32_t shared;
+};
+
+struct AdsrEnvelope {
+ int16_t delay;
+ int16_t arg;
+};
+
+struct Envelope {
+ std::string name;
+ std::vector<AdsrEnvelope> entries;
+};
+
+struct Bank {
+ std::string name;
+ SampleBank* sampleBank;
+ std::vector<Instrument> insts;
+ std::vector<Drum> drums;
+ std::vector<std::variant<Instrument, std::vector<Drum>>> allInsts;
+ std::vector<uint32_t> instOffsets;
+ std::map<uint32_t, Envelope> envelopes;
+ std::map<uint32_t, AudioBankSample*> samples;
+ void print() const;
+};
+
+class AudioManager {
+public:
+ static AudioManager* Instance;
+ void initialize(std::vector<uint8_t>& buffer);
+ void create_aifc(int32_t index, LUS::BinaryWriter& writer);
+ AudioBankSample get_aifc(int32_t index);
+ std::map<uint32_t, Bank> get_banks();
+ uint32_t get_index(AudioBankSample* bank);
+
+private:
+ std::map<uint32_t, Bank> banks;
+ std::map<AudioBankSample*, uint32_t> sampleMap;
+ TBLFile loaded_tbl;
+
+ static std::vector<Entry> parse_seq_file(std::vector<uint8_t>& buffer, uint32_t offset, bool isCTL);
+ static CTLHeader parse_ctl_header(std::vector<uint8_t>& data);
+ static std::optional<AudioBankSound> parse_sound(std::vector<uint8_t> data);
+ static Drum parse_drum(std::vector<uint8_t>& data, uint32_t addr);
+ static Instrument parse_inst(std::vector<uint8_t>& data, uint32_t addr);
+ static AdpcmLoop parse_loop(uint32_t addr, std::vector<uint8_t>& bankData);
+ static AdpcmBook parse_book(uint32_t addr, std::vector<uint8_t>& bankData);
+ static AudioBankSample* parse_sample(std::vector<uint8_t>& data, std::vector<uint8_t>& bankData, SampleBank* sampleBank);
+ static std::vector<AdsrEnvelope> parse_envelope(uint32_t addr, std::vector<uint8_t>& dataBank);
+ static Bank parse_ctl(CTLHeader header, std::vector<uint8_t> data, SampleBank* bank, uint32_t index);
+ static TBLFile parse_tbl(std::vector<uint8_t>& data, std::vector<Entry>& entries);
+
+ static void write_aifc(AudioBankSample* entry, LUS::BinaryWriter& writer);
+}; \ No newline at end of file
diff --git a/src/audio/samples_table.h b/src/audio/samples_table.h
new file mode 100644
index 0000000..2946d05
--- /dev/null
+++ b/src/audio/samples_table.h
@@ -0,0 +1,722 @@
+#pragma once
+
+#if defined(_WIN32)
+#define ALIGN_ASSET(x) __declspec(align(x))
+#else
+#define ALIGN_ASSET(x) __attribute__((aligned (x)))
+#endif
+
+#define dgSample00 "__OTR__sound/samples/sfx_1/00_twirl"
+static const ALIGN_ASSET(2) char gSample00[] = dgSample00;
+
+#define dgSample01 "__OTR__sound/samples/sfx_1/01_brushing"
+static const ALIGN_ASSET(2) char gSample01[] = dgSample01;
+
+#define dgSample02 "__OTR__sound/samples/sfx_1/02_hand_touch"
+static const ALIGN_ASSET(2) char gSample02[] = dgSample02;
+
+#define dgSample03 "__OTR__sound/samples/sfx_1/03_yoshi"
+static const ALIGN_ASSET(2) char gSample03[] = dgSample03;
+
+#define dgSample04 "__OTR__sound/samples/sfx_1/04_plop"
+static const ALIGN_ASSET(2) char gSample04[] = dgSample04;
+
+#define dgSample05 "__OTR__sound/samples/sfx_1/05_heavy_landing"
+static const ALIGN_ASSET(2) char gSample05[] = dgSample05;
+
+#define dgSample06 "__OTR__sound/samples/sfx_terrain/00_step_default"
+static const ALIGN_ASSET(2) char gSample06[] = dgSample06;
+
+#define dgSample07 "__OTR__sound/samples/sfx_terrain/01_step_grass"
+static const ALIGN_ASSET(2) char gSample07[] = dgSample07;
+
+#define dgSample08 "__OTR__sound/samples/sfx_terrain/02_step_stone"
+static const ALIGN_ASSET(2) char gSample08[] = dgSample08;
+
+#define dgSample09 "__OTR__sound/samples/sfx_terrain/03_step_spooky"
+static const ALIGN_ASSET(2) char gSample09[] = dgSample09;
+
+#define dgSample0A "__OTR__sound/samples/sfx_terrain/04_step_snow"
+static const ALIGN_ASSET(2) char gSample0A[] = dgSample0A;
+
+#define dgSample0B "__OTR__sound/samples/sfx_terrain/05_step_ice"
+static const ALIGN_ASSET(2) char gSample0B[] = dgSample0B;
+
+#define dgSample0C "__OTR__sound/samples/sfx_terrain/06_step_metal"
+static const ALIGN_ASSET(2) char gSample0C[] = dgSample0C;
+
+#define dgSample0D "__OTR__sound/samples/sfx_terrain/07_step_sand"
+static const ALIGN_ASSET(2) char gSample0D[] = dgSample0D;
+
+#define dgSample0E "__OTR__sound/samples/sfx_water/00_plunge"
+static const ALIGN_ASSET(2) char gSample0E[] = dgSample0E;
+
+#define dgSample0F "__OTR__sound/samples/sfx_water/01_splash"
+static const ALIGN_ASSET(2) char gSample0F[] = dgSample0F;
+
+#define dgSample10 "__OTR__sound/samples/sfx_water/02_swim"
+static const ALIGN_ASSET(2) char gSample10[] = dgSample10;
+
+#define dgSample11 "__OTR__sound/samples/sfx_4/00"
+static const ALIGN_ASSET(2) char gSample11[] = dgSample11;
+
+#define dgSample12 "__OTR__sound/samples/sfx_4/01"
+static const ALIGN_ASSET(2) char gSample12[] = dgSample12;
+
+#define dgSample13 "__OTR__sound/samples/sfx_4/02"
+static const ALIGN_ASSET(2) char gSample13[] = dgSample13;
+
+#define dgSample14 "__OTR__sound/samples/sfx_4/03"
+static const ALIGN_ASSET(2) char gSample14[] = dgSample14;
+
+#define dgSample15 "__OTR__sound/samples/sfx_4/04"
+static const ALIGN_ASSET(2) char gSample15[] = dgSample15;
+
+#define dgSample16 "__OTR__sound/samples/sfx_4/05"
+static const ALIGN_ASSET(2) char gSample16[] = dgSample16;
+
+#define dgSample17 "__OTR__sound/samples/sfx_4/06"
+static const ALIGN_ASSET(2) char gSample17[] = dgSample17;
+
+#define dgSample18 "__OTR__sound/samples/sfx_4/07"
+static const ALIGN_ASSET(2) char gSample18[] = dgSample18;
+
+#define dgSample19 "__OTR__sound/samples/sfx_4/08"
+static const ALIGN_ASSET(2) char gSample19[] = dgSample19;
+
+#define dgSample1A "__OTR__sound/samples/sfx_4/09"
+static const ALIGN_ASSET(2) char gSample1A[] = dgSample1A;
+
+#define dgSample1B "__OTR__sound/samples/sfx_5/00"
+static const ALIGN_ASSET(2) char gSample1B[] = dgSample1B;
+
+#define dgSample1C "__OTR__sound/samples/sfx_5/01"
+static const ALIGN_ASSET(2) char gSample1C[] = dgSample1C;
+
+#define dgSample1D "__OTR__sound/samples/sfx_5/02"
+static const ALIGN_ASSET(2) char gSample1D[] = dgSample1D;
+
+#define dgSample1E "__OTR__sound/samples/sfx_5/03"
+static const ALIGN_ASSET(2) char gSample1E[] = dgSample1E;
+
+#define dgSample1F "__OTR__sound/samples/sfx_5/04"
+static const ALIGN_ASSET(2) char gSample1F[] = dgSample1F;
+
+#define dgSample20 "__OTR__sound/samples/sfx_5/05"
+static const ALIGN_ASSET(2) char gSample20[] = dgSample20;
+
+#define dgSample21 "__OTR__sound/samples/sfx_5/06"
+static const ALIGN_ASSET(2) char gSample21[] = dgSample21;
+
+#define dgSample22 "__OTR__sound/samples/sfx_5/07"
+static const ALIGN_ASSET(2) char gSample22[] = dgSample22;
+
+#define dgSample23 "__OTR__sound/samples/sfx_5/08"
+static const ALIGN_ASSET(2) char gSample23[] = dgSample23;
+
+#define dgSample24 "__OTR__sound/samples/sfx_5/09"
+static const ALIGN_ASSET(2) char gSample24[] = dgSample24;
+
+#define dgSample25 "__OTR__sound/samples/sfx_5/0A"
+static const ALIGN_ASSET(2) char gSample25[] = dgSample25;
+
+#define dgSample26 "__OTR__sound/samples/sfx_5/0B"
+static const ALIGN_ASSET(2) char gSample26[] = dgSample26;
+
+#define dgSample27 "__OTR__sound/samples/sfx_5/0C"
+static const ALIGN_ASSET(2) char gSample27[] = dgSample27;
+
+#define dgSample28 "__OTR__sound/samples/sfx_5/0D"
+static const ALIGN_ASSET(2) char gSample28[] = dgSample28;
+
+#define dgSample29 "__OTR__sound/samples/sfx_5/0E"
+static const ALIGN_ASSET(2) char gSample29[] = dgSample29;
+
+#define dgSample2A "__OTR__sound/samples/sfx_5/0F"
+static const ALIGN_ASSET(2) char gSample2A[] = dgSample2A;
+
+#define dgSample2B "__OTR__sound/samples/sfx_5/10"
+static const ALIGN_ASSET(2) char gSample2B[] = dgSample2B;
+
+#define dgSample2C "__OTR__sound/samples/sfx_5/11"
+static const ALIGN_ASSET(2) char gSample2C[] = dgSample2C;
+
+#define dgSample2D "__OTR__sound/samples/sfx_5/12"
+static const ALIGN_ASSET(2) char gSample2D[] = dgSample2D;
+
+#define dgSample2E "__OTR__sound/samples/sfx_5/13"
+static const ALIGN_ASSET(2) char gSample2E[] = dgSample2E;
+
+#define dgSample2F "__OTR__sound/samples/sfx_5/14"
+static const ALIGN_ASSET(2) char gSample2F[] = dgSample2F;
+
+#define dgSample30 "__OTR__sound/samples/sfx_5/15"
+static const ALIGN_ASSET(2) char gSample30[] = dgSample30;
+
+#define dgSample31 "__OTR__sound/samples/sfx_5/16"
+static const ALIGN_ASSET(2) char gSample31[] = dgSample31;
+
+#define dgSample32 "__OTR__sound/samples/sfx_5/17"
+static const ALIGN_ASSET(2) char gSample32[] = dgSample32;
+
+#define dgSample33 "__OTR__sound/samples/sfx_5/18"
+static const ALIGN_ASSET(2) char gSample33[] = dgSample33;
+
+#define dgSample34 "__OTR__sound/samples/sfx_5/19"
+static const ALIGN_ASSET(2) char gSample34[] = dgSample34;
+
+#define dgSample35 "__OTR__sound/samples/sfx_5/1A"
+static const ALIGN_ASSET(2) char gSample35[] = dgSample35;
+
+#define dgSample36 "__OTR__sound/samples/sfx_5/1B"
+static const ALIGN_ASSET(2) char gSample36[] = dgSample36;
+
+#define dgSample37 "__OTR__sound/samples/sfx_5/1C"
+static const ALIGN_ASSET(2) char gSample37[] = dgSample37;
+
+#define dgSample38 "__OTR__sound/samples/sfx_6/00"
+static const ALIGN_ASSET(2) char gSample38[] = dgSample38;
+
+#define dgSample39 "__OTR__sound/samples/sfx_6/01"
+static const ALIGN_ASSET(2) char gSample39[] = dgSample39;
+
+#define dgSample3A "__OTR__sound/samples/sfx_6/02"
+static const ALIGN_ASSET(2) char gSample3A[] = dgSample3A;
+
+#define dgSample3B "__OTR__sound/samples/sfx_6/03"
+static const ALIGN_ASSET(2) char gSample3B[] = dgSample3B;
+
+#define dgSample3C "__OTR__sound/samples/sfx_6/04"
+static const ALIGN_ASSET(2) char gSample3C[] = dgSample3C;
+
+#define dgSample3D "__OTR__sound/samples/sfx_6/05"
+static const ALIGN_ASSET(2) char gSample3D[] = dgSample3D;
+
+#define dgSample3E "__OTR__sound/samples/sfx_6/06"
+static const ALIGN_ASSET(2) char gSample3E[] = dgSample3E;
+
+#define dgSample3F "__OTR__sound/samples/sfx_6/07"
+static const ALIGN_ASSET(2) char gSample3F[] = dgSample3F;
+
+#define dgSample40 "__OTR__sound/samples/sfx_6/08"
+static const ALIGN_ASSET(2) char gSample40[] = dgSample40;
+
+#define dgSample41 "__OTR__sound/samples/sfx_6/09"
+static const ALIGN_ASSET(2) char gSample41[] = dgSample41;
+
+#define dgSample42 "__OTR__sound/samples/sfx_6/0A"
+static const ALIGN_ASSET(2) char gSample42[] = dgSample42;
+
+#define dgSample43 "__OTR__sound/samples/sfx_6/0B"
+static const ALIGN_ASSET(2) char gSample43[] = dgSample43;
+
+#define dgSample44 "__OTR__sound/samples/sfx_6/0C"
+static const ALIGN_ASSET(2) char gSample44[] = dgSample44;
+
+#define dgSample45 "__OTR__sound/samples/sfx_6/0D"
+static const ALIGN_ASSET(2) char gSample45[] = dgSample45;
+
+#define dgSample46 "__OTR__sound/samples/sfx_7/00"
+static const ALIGN_ASSET(2) char gSample46[] = dgSample46;
+
+#define dgSample47 "__OTR__sound/samples/sfx_7/01"
+static const ALIGN_ASSET(2) char gSample47[] = dgSample47;
+
+#define dgSample48 "__OTR__sound/samples/sfx_7/02"
+static const ALIGN_ASSET(2) char gSample48[] = dgSample48;
+
+#define dgSample49 "__OTR__sound/samples/sfx_7/03"
+static const ALIGN_ASSET(2) char gSample49[] = dgSample49;
+
+#define dgSample4A "__OTR__sound/samples/sfx_7/04"
+static const ALIGN_ASSET(2) char gSample4A[] = dgSample4A;
+
+#define dgSample4B "__OTR__sound/samples/sfx_7/05"
+static const ALIGN_ASSET(2) char gSample4B[] = dgSample4B;
+
+#define dgSample4C "__OTR__sound/samples/sfx_7/06"
+static const ALIGN_ASSET(2) char gSample4C[] = dgSample4C;
+
+#define dgSample4D "__OTR__sound/samples/sfx_7/07"
+static const ALIGN_ASSET(2) char gSample4D[] = dgSample4D;
+
+#define dgSample4E "__OTR__sound/samples/sfx_7/08"
+static const ALIGN_ASSET(2) char gSample4E[] = dgSample4E;
+
+#define dgSample4F "__OTR__sound/samples/sfx_7/09"
+static const ALIGN_ASSET(2) char gSample4F[] = dgSample4F;
+
+#define dgSample50 "__OTR__sound/samples/sfx_7/0A"
+static const ALIGN_ASSET(2) char gSample50[] = dgSample50;
+
+#define dgSample51 "__OTR__sound/samples/sfx_7/0B"
+static const ALIGN_ASSET(2) char gSample51[] = dgSample51;
+
+#define dgSample52 "__OTR__sound/samples/sfx_7/0C"
+static const ALIGN_ASSET(2) char gSample52[] = dgSample52;
+
+#define dgSample53 "__OTR__sound/samples/sfx_7/0D_chain_chomp_bark"
+static const ALIGN_ASSET(2) char gSample53[] = dgSample53;
+
+#define dgSample54 "__OTR__sound/samples/sfx_mario/00_mario_jump_hoo"
+static const ALIGN_ASSET(2) char gSample54[] = dgSample54;
+
+#define dgSample55 "__OTR__sound/samples/sfx_mario/01_mario_jump_wah"
+static const ALIGN_ASSET(2) char gSample55[] = dgSample55;
+
+#define dgSample56 "__OTR__sound/samples/sfx_mario/02_mario_yah"
+static const ALIGN_ASSET(2) char gSample56[] = dgSample56;
+
+#define dgSample57 "__OTR__sound/samples/sfx_mario/03_mario_haha"
+static const ALIGN_ASSET(2) char gSample57[] = dgSample57;
+
+#define dgSample58 "__OTR__sound/samples/sfx_mario/04_mario_yahoo"
+static const ALIGN_ASSET(2) char gSample58[] = dgSample58;
+
+#define dgSample59 "__OTR__sound/samples/sfx_mario/05_mario_uh"
+static const ALIGN_ASSET(2) char gSample59[] = dgSample59;
+
+#define dgSample5A "__OTR__sound/samples/sfx_mario/06_mario_hrmm"
+static const ALIGN_ASSET(2) char gSample5A[] = dgSample5A;
+
+#define dgSample5B "__OTR__sound/samples/sfx_mario/07_mario_wah2"
+static const ALIGN_ASSET(2) char gSample5B[] = dgSample5B;
+
+#define dgSample5C "__OTR__sound/samples/sfx_mario/08_mario_whoa"
+static const ALIGN_ASSET(2) char gSample5C[] = dgSample5C;
+
+#define dgSample5D "__OTR__sound/samples/sfx_mario/09_mario_eeuh"
+static const ALIGN_ASSET(2) char gSample5D[] = dgSample5D;
+
+#define dgSample5E "__OTR__sound/samples/sfx_mario/0A_mario_attacked"
+static const ALIGN_ASSET(2) char gSample5E[] = dgSample5E;
+
+#define dgSample5F "__OTR__sound/samples/sfx_mario/0B_mario_ooof"
+static const ALIGN_ASSET(2) char gSample5F[] = dgSample5F;
+
+#define dgSample60 "__OTR__sound/samples/sfx_mario/0C_mario_here_we_go"
+static const ALIGN_ASSET(2) char gSample60[] = dgSample60;
+
+#define dgSample61 "__OTR__sound/samples/sfx_mario/0D_mario_yawning"
+static const ALIGN_ASSET(2) char gSample61[] = dgSample61;
+
+#define dgSample62 "__OTR__sound/samples/sfx_mario/0E_mario_snoring1"
+static const ALIGN_ASSET(2) char gSample62[] = dgSample62;
+
+#define dgSample63 "__OTR__sound/samples/sfx_mario/0F_mario_snoring2"
+static const ALIGN_ASSET(2) char gSample63[] = dgSample63;
+
+#define dgSample64 "__OTR__sound/samples/sfx_mario/10_mario_doh"
+static const ALIGN_ASSET(2) char gSample64[] = dgSample64;
+
+#define dgSample65 "__OTR__sound/samples/sfx_mario/11_mario_game_over"
+static const ALIGN_ASSET(2) char gSample65[] = dgSample65;
+
+#define dgSample66 "__OTR__sound/samples/sfx_mario/12_mario_hello"
+static const ALIGN_ASSET(2) char gSample66[] = dgSample66;
+
+#define dgSample67 "__OTR__sound/samples/sfx_mario/13_mario_press_start_to_play"
+static const ALIGN_ASSET(2) char gSample67[] = dgSample67;
+
+#define dgSample68 "__OTR__sound/samples/sfx_mario/14_mario_twirl_bounce"
+static const ALIGN_ASSET(2) char gSample68[] = dgSample68;
+
+#define dgSample69 "__OTR__sound/samples/sfx_mario/15_mario_snoring3"
+static const ALIGN_ASSET(2) char gSample69[] = dgSample69;
+
+#define dgSample6A "__OTR__sound/samples/sfx_mario/16_mario_so_longa_bowser"
+static const ALIGN_ASSET(2) char gSample6A[] = dgSample6A;
+
+#define dgSample6B "__OTR__sound/samples/sfx_mario/17_mario_ima_tired"
+static const ALIGN_ASSET(2) char gSample6B[] = dgSample6B;
+
+#define dgSample6C "__OTR__sound/samples/sfx_mario/18_mario_waha"
+static const ALIGN_ASSET(2) char gSample6C[] = dgSample6C;
+
+#define dgSample6D "__OTR__sound/samples/sfx_mario/19_mario_yippee"
+static const ALIGN_ASSET(2) char gSample6D[] = dgSample6D;
+
+#define dgSample6E "__OTR__sound/samples/sfx_mario/1A_mario_lets_a_go"
+static const ALIGN_ASSET(2) char gSample6E[] = dgSample6E;
+
+#define dgSample6F "__OTR__sound/samples/sfx_9/00"
+static const ALIGN_ASSET(2) char gSample6F[] = dgSample6F;
+
+#define dgSample70 "__OTR__sound/samples/sfx_9/01"
+static const ALIGN_ASSET(2) char gSample70[] = dgSample70;
+
+#define dgSample71 "__OTR__sound/samples/sfx_9/02"
+static const ALIGN_ASSET(2) char gSample71[] = dgSample71;
+
+#define dgSample72 "__OTR__sound/samples/sfx_9/03"
+static const ALIGN_ASSET(2) char gSample72[] = dgSample72;
+
+#define dgSample73 "__OTR__sound/samples/sfx_9/04_camera_buzz"
+static const ALIGN_ASSET(2) char gSample73[] = dgSample73;
+
+#define dgSample74 "__OTR__sound/samples/sfx_9/05_camera_shutter"
+static const ALIGN_ASSET(2) char gSample74[] = dgSample74;
+
+#define dgSample75 "__OTR__sound/samples/sfx_9/06"
+static const ALIGN_ASSET(2) char gSample75[] = dgSample75;
+
+#define dgSample76 "__OTR__sound/samples/sfx_mario_peach/00_mario_waaaooow"
+static const ALIGN_ASSET(2) char gSample76[] = dgSample76;
+
+#define dgSample77 "__OTR__sound/samples/sfx_mario_peach/01_mario_hoohoo"
+static const ALIGN_ASSET(2) char gSample77[] = dgSample77;
+
+#define dgSample78 "__OTR__sound/samples/sfx_mario_peach/02_mario_panting"
+static const ALIGN_ASSET(2) char gSample78[] = dgSample78;
+
+#define dgSample79 "__OTR__sound/samples/sfx_mario_peach/03_mario_dying"
+static const ALIGN_ASSET(2) char gSample79[] = dgSample79;
+
+#define dgSample7A "__OTR__sound/samples/sfx_mario_peach/04_mario_on_fire"
+static const ALIGN_ASSET(2) char gSample7A[] = dgSample7A;
+
+#define dgSample7B "__OTR__sound/samples/sfx_mario_peach/05_mario_uh2"
+static const ALIGN_ASSET(2) char gSample7B[] = dgSample7B;
+
+#define dgSample7C "__OTR__sound/samples/sfx_mario_peach/06_mario_coughing"
+static const ALIGN_ASSET(2) char gSample7C[] = dgSample7C;
+
+#define dgSample7D "__OTR__sound/samples/sfx_mario_peach/07_mario_its_a_me_mario"
+static const ALIGN_ASSET(2) char gSample7D[] = dgSample7D;
+
+#define dgSample7E "__OTR__sound/samples/sfx_mario_peach/08_mario_punch_yah"
+static const ALIGN_ASSET(2) char gSample7E[] = dgSample7E;
+
+#define dgSample7F "__OTR__sound/samples/sfx_mario_peach/09_mario_punch_hoo"
+static const ALIGN_ASSET(2) char gSample7F[] = dgSample7F;
+
+#define dgSample80 "__OTR__sound/samples/sfx_mario_peach/0A_mario_mama_mia"
+static const ALIGN_ASSET(2) char gSample80[] = dgSample80;
+
+#define dgSample81 "__OTR__sound/samples/sfx_mario_peach/0B_mario_okey_dokey"
+static const ALIGN_ASSET(2) char gSample81[] = dgSample81;
+
+#define dgSample82 "__OTR__sound/samples/sfx_mario_peach/0C_mario_drowning"
+static const ALIGN_ASSET(2) char gSample82[] = dgSample82;
+
+#define dgSample83 "__OTR__sound/samples/sfx_mario_peach/0D_mario_thank_you_playing_my_game"
+static const ALIGN_ASSET(2) char gSample83[] = dgSample83;
+
+#define dgSample84 "__OTR__sound/samples/sfx_mario_peach/0E_peach_dear_mario"
+static const ALIGN_ASSET(2) char gSample84[] = dgSample84;
+
+#define dgSample85 "__OTR__sound/samples/sfx_mario_peach/0F_peach_mario"
+static const ALIGN_ASSET(2) char gSample85[] = dgSample85;
+
+#define dgSample86 "__OTR__sound/samples/sfx_mario_peach/10_peach_power_of_the_stars"
+static const ALIGN_ASSET(2) char gSample86[] = dgSample86;
+
+#define dgSample87 "__OTR__sound/samples/sfx_mario_peach/11_peach_thanks_to_you"
+static const ALIGN_ASSET(2) char gSample87[] = dgSample87;
+
+#define dgSample88 "__OTR__sound/samples/sfx_mario_peach/12_peach_thank_you_mario"
+static const ALIGN_ASSET(2) char gSample88[] = dgSample88;
+
+#define dgSample89 "__OTR__sound/samples/sfx_mario_peach/13_peach_something_special"
+static const ALIGN_ASSET(2) char gSample89[] = dgSample89;
+
+#define dgSample8A "__OTR__sound/samples/sfx_mario_peach/14_peach_bake_a_cake"
+static const ALIGN_ASSET(2) char gSample8A[] = dgSample8A;
+
+#define dgSample8B "__OTR__sound/samples/sfx_mario_peach/15_peach_for_mario"
+static const ALIGN_ASSET(2) char gSample8B[] = dgSample8B;
+
+#define dgSample8C "__OTR__sound/samples/sfx_mario_peach/16_peach_mario2"
+static const ALIGN_ASSET(2) char gSample8C[] = dgSample8C;
+
+#define dgSample8D "__OTR__sound/samples/instruments/00"
+static const ALIGN_ASSET(2) char gSample8D[] = dgSample8D;
+
+#define dgSample8E "__OTR__sound/samples/instruments/01_banjo_1"
+static const ALIGN_ASSET(2) char gSample8E[] = dgSample8E;
+
+#define dgSample8F "__OTR__sound/samples/instruments/02"
+static const ALIGN_ASSET(2) char gSample8F[] = dgSample8F;
+
+#define dgSample90 "__OTR__sound/samples/instruments/03_human_whistle"
+static const ALIGN_ASSET(2) char gSample90[] = dgSample90;
+
+#define dgSample91 "__OTR__sound/samples/instruments/04_bright_piano"
+static const ALIGN_ASSET(2) char gSample91[] = dgSample91;
+
+#define dgSample92 "__OTR__sound/samples/instruments/05_acoustic_bass"
+static const ALIGN_ASSET(2) char gSample92[] = dgSample92;
+
+#define dgSample93 "__OTR__sound/samples/instruments/06_kick_drum_1"
+static const ALIGN_ASSET(2) char gSample93[] = dgSample93;
+
+#define dgSample94 "__OTR__sound/samples/instruments/07_rimshot"
+static const ALIGN_ASSET(2) char gSample94[] = dgSample94;
+
+#define dgSample95 "__OTR__sound/samples/instruments/08"
+static const ALIGN_ASSET(2) char gSample95[] = dgSample95;
+
+#define dgSample96 "__OTR__sound/samples/instruments/09"
+static const ALIGN_ASSET(2) char gSample96[] = dgSample96;
+
+#define dgSample97 "__OTR__sound/samples/instruments/0A_tambourine"
+static const ALIGN_ASSET(2) char gSample97[] = dgSample97;
+
+#define dgSample98 "__OTR__sound/samples/instruments/0B"
+static const ALIGN_ASSET(2) char gSample98[] = dgSample98;
+
+#define dgSample99 "__OTR__sound/samples/instruments/0C_conga_stick"
+static const ALIGN_ASSET(2) char gSample99[] = dgSample99;
+
+#define dgSample9A "__OTR__sound/samples/instruments/0D_clave"
+static const ALIGN_ASSET(2) char gSample9A[] = dgSample9A;
+
+#define dgSample9B "__OTR__sound/samples/instruments/0E_hihat_closed"
+static const ALIGN_ASSET(2) char gSample9B[] = dgSample9B;
+
+#define dgSample9C "__OTR__sound/samples/instruments/0F_hihat_open"
+static const ALIGN_ASSET(2) char gSample9C[] = dgSample9C;
+
+#define dgSample9D "__OTR__sound/samples/instruments/10_cymbal_bell"
+static const ALIGN_ASSET(2) char gSample9D[] = dgSample9D;
+
+#define dgSample9E "__OTR__sound/samples/instruments/11_splash_cymbal"
+static const ALIGN_ASSET(2) char gSample9E[] = dgSample9E;
+
+#define dgSample9F "__OTR__sound/samples/instruments/12_snare_drum_1"
+static const ALIGN_ASSET(2) char gSample9F[] = dgSample9F;
+
+#define dgSampleA0 "__OTR__sound/samples/instruments/13_snare_drum_2"
+static const ALIGN_ASSET(2) char gSampleA0[] = dgSampleA0;
+
+#define dgSampleA1 "__OTR__sound/samples/instruments/14_strings_5"
+static const ALIGN_ASSET(2) char gSampleA1[] = dgSampleA1;
+
+#define dgSampleA2 "__OTR__sound/samples/instruments/15_strings_4"
+static const ALIGN_ASSET(2) char gSampleA2[] = dgSampleA2;
+
+#define dgSampleA3 "__OTR__sound/samples/instruments/16_french_horns"
+static const ALIGN_ASSET(2) char gSampleA3[] = dgSampleA3;
+
+#define dgSampleA4 "__OTR__sound/samples/instruments/17_trumpet"
+static const ALIGN_ASSET(2) char gSampleA4[] = dgSampleA4;
+
+#define dgSampleA5 "__OTR__sound/samples/instruments/18_timpani"
+static const ALIGN_ASSET(2) char gSampleA5[] = dgSampleA5;
+
+#define dgSampleA6 "__OTR__sound/samples/instruments/19_brass"
+static const ALIGN_ASSET(2) char gSampleA6[] = dgSampleA6;
+
+#define dgSampleA7 "__OTR__sound/samples/instruments/1A_slap_bass"
+static const ALIGN_ASSET(2) char gSampleA7[] = dgSampleA7;
+
+#define dgSampleA8 "__OTR__sound/samples/instruments/1B_organ_2"
+static const ALIGN_ASSET(2) char gSampleA8[] = dgSampleA8;
+
+#define dgSampleA9 "__OTR__sound/samples/instruments/1C"
+static const ALIGN_ASSET(2) char gSampleA9[] = dgSampleA9;
+
+#define dgSampleAA "__OTR__sound/samples/instruments/1D"
+static const ALIGN_ASSET(2) char gSampleAA[] = dgSampleAA;
+
+#define dgSampleAB "__OTR__sound/samples/instruments/1E_closed_triangle"
+static const ALIGN_ASSET(2) char gSampleAB[] = dgSampleAB;
+
+#define dgSampleAC "__OTR__sound/samples/instruments/1F_open_triangle"
+static const ALIGN_ASSET(2) char gSampleAC[] = dgSampleAC;
+
+#define dgSampleAD "__OTR__sound/samples/instruments/20_cabasa"
+static const ALIGN_ASSET(2) char gSampleAD[] = dgSampleAD;
+
+#define dgSampleAE "__OTR__sound/samples/instruments/21_sine_bass"
+static const ALIGN_ASSET(2) char gSampleAE[] = dgSampleAE;
+
+#define dgSampleAF "__OTR__sound/samples/instruments/22_boys_choir"
+static const ALIGN_ASSET(2) char gSampleAF[] = dgSampleAF;
+
+#define dgSampleB0 "__OTR__sound/samples/instruments/23_strings_1"
+static const ALIGN_ASSET(2) char gSampleB0[] = dgSampleB0;
+
+#define dgSampleB1 "__OTR__sound/samples/instruments/24_strings_2"
+static const ALIGN_ASSET(2) char gSampleB1[] = dgSampleB1;
+
+#define dgSampleB2 "__OTR__sound/samples/instruments/25_strings_3"
+static const ALIGN_ASSET(2) char gSampleB2[] = dgSampleB2;
+
+#define dgSampleB3 "__OTR__sound/samples/instruments/26_crystal_rhodes"
+static const ALIGN_ASSET(2) char gSampleB3[] = dgSampleB3;
+
+#define dgSampleB4 "__OTR__sound/samples/instruments/27_harpsichord"
+static const ALIGN_ASSET(2) char gSampleB4[] = dgSampleB4;
+
+#define dgSampleB5 "__OTR__sound/samples/instruments/28_sitar_1"
+static const ALIGN_ASSET(2) char gSampleB5[] = dgSampleB5;
+
+#define dgSampleB6 "__OTR__sound/samples/instruments/29_orchestra_hit"
+static const ALIGN_ASSET(2) char gSampleB6[] = dgSampleB6;
+
+#define dgSampleB7 "__OTR__sound/samples/instruments/2A"
+static const ALIGN_ASSET(2) char gSampleB7[] = dgSampleB7;
+
+#define dgSampleB8 "__OTR__sound/samples/instruments/2B"
+static const ALIGN_ASSET(2) char gSampleB8[] = dgSampleB8;
+
+#define dgSampleB9 "__OTR__sound/samples/instruments/2C"
+static const ALIGN_ASSET(2) char gSampleB9[] = dgSampleB9;
+
+#define dgSampleBA "__OTR__sound/samples/instruments/2D_trombone"
+static const ALIGN_ASSET(2) char gSampleBA[] = dgSampleBA;
+
+#define dgSampleBB "__OTR__sound/samples/instruments/2E_accordion"
+static const ALIGN_ASSET(2) char gSampleBB[] = dgSampleBB;
+
+#define dgSampleBC "__OTR__sound/samples/instruments/2F_sleigh_bells"
+static const ALIGN_ASSET(2) char gSampleBC[] = dgSampleBC;
+
+#define dgSampleBD "__OTR__sound/samples/instruments/30_rarefaction-lahna"
+static const ALIGN_ASSET(2) char gSampleBD[] = dgSampleBD;
+
+#define dgSampleBE "__OTR__sound/samples/instruments/31_rarefaction-convolution"
+static const ALIGN_ASSET(2) char gSampleBE[] = dgSampleBE;
+
+#define dgSampleBF "__OTR__sound/samples/instruments/32_metal_rimshot"
+static const ALIGN_ASSET(2) char gSampleBF[] = dgSampleBF;
+
+#define dgSampleC0 "__OTR__sound/samples/instruments/33_kick_drum_2"
+static const ALIGN_ASSET(2) char gSampleC0[] = dgSampleC0;
+
+#define dgSampleC1 "__OTR__sound/samples/instruments/34_alto_flute"
+static const ALIGN_ASSET(2) char gSampleC1[] = dgSampleC1;
+
+#define dgSampleC2 "__OTR__sound/samples/instruments/35_gospel_organ"
+static const ALIGN_ASSET(2) char gSampleC2[] = dgSampleC2;
+
+#define dgSampleC3 "__OTR__sound/samples/instruments/36_sawtooth_synth"
+static const ALIGN_ASSET(2) char gSampleC3[] = dgSampleC3;
+
+#define dgSampleC4 "__OTR__sound/samples/instruments/37_square_synth"
+static const ALIGN_ASSET(2) char gSampleC4[] = dgSampleC4;
+
+#define dgSampleC5 "__OTR__sound/samples/instruments/38_electric_kick_drum"
+static const ALIGN_ASSET(2) char gSampleC5[] = dgSampleC5;
+
+#define dgSampleC6 "__OTR__sound/samples/instruments/39_sitar_2"
+static const ALIGN_ASSET(2) char gSampleC6[] = dgSampleC6;
+
+#define dgSampleC7 "__OTR__sound/samples/instruments/3A_music_box"
+static const ALIGN_ASSET(2) char gSampleC7[] = dgSampleC7;
+
+#define dgSampleC8 "__OTR__sound/samples/instruments/3B_banjo_2"
+static const ALIGN_ASSET(2) char gSampleC8[] = dgSampleC8;
+
+#define dgSampleC9 "__OTR__sound/samples/instruments/3C_acoustic_guitar"
+static const ALIGN_ASSET(2) char gSampleC9[] = dgSampleC9;
+
+#define dgSampleCA "__OTR__sound/samples/instruments/3D"
+static const ALIGN_ASSET(2) char gSampleCA[] = dgSampleCA;
+
+#define dgSampleCB "__OTR__sound/samples/instruments/3E_monk_choir"
+static const ALIGN_ASSET(2) char gSampleCB[] = dgSampleCB;
+
+#define dgSampleCC "__OTR__sound/samples/instruments/3F"
+static const ALIGN_ASSET(2) char gSampleCC[] = dgSampleCC;
+
+#define dgSampleCD "__OTR__sound/samples/instruments/40_bell"
+static const ALIGN_ASSET(2) char gSampleCD[] = dgSampleCD;
+
+#define dgSampleCE "__OTR__sound/samples/instruments/41_pan_flute"
+static const ALIGN_ASSET(2) char gSampleCE[] = dgSampleCE;
+
+#define dgSampleCF "__OTR__sound/samples/instruments/42_vibraphone"
+static const ALIGN_ASSET(2) char gSampleCF[] = dgSampleCF;
+
+#define dgSampleD0 "__OTR__sound/samples/instruments/43_harmonica"
+static const ALIGN_ASSET(2) char gSampleD0[] = dgSampleD0;
+
+#define dgSampleD1 "__OTR__sound/samples/instruments/44_grand_piano"
+static const ALIGN_ASSET(2) char gSampleD1[] = dgSampleD1;
+
+#define dgSampleD2 "__OTR__sound/samples/instruments/45_french_horns_lq"
+static const ALIGN_ASSET(2) char gSampleD2[] = dgSampleD2;
+
+#define dgSampleD3 "__OTR__sound/samples/instruments/46_pizzicato_strings_1"
+static const ALIGN_ASSET(2) char gSampleD3[] = dgSampleD3;
+
+#define dgSampleD4 "__OTR__sound/samples/instruments/47_pizzicato_strings_2"
+static const ALIGN_ASSET(2) char gSampleD4[] = dgSampleD4;
+
+#define dgSampleD5 "__OTR__sound/samples/instruments/48_steel_drum"
+static const ALIGN_ASSET(2) char gSampleD5[] = dgSampleD5;
+
+#define dgSampleD6 "__OTR__sound/samples/piranha_music_box/00_music_box"
+static const ALIGN_ASSET(2) char gSampleD6[] = dgSampleD6;
+
+#define dgSampleD7 "__OTR__sound/samples/course_start/00_la"
+static const ALIGN_ASSET(2) char gSampleD7[] = dgSampleD7;
+
+#define dgSampleD8 "__OTR__sound/samples/bowser_organ/00_organ_1"
+static const ALIGN_ASSET(2) char gSampleD8[] = dgSampleD8;
+
+#define dgSampleD9 "__OTR__sound/samples/bowser_organ/01_organ_1_lq"
+static const ALIGN_ASSET(2) char gSampleD9[] = dgSampleD9;
+
+#define dgSampleDA "__OTR__sound/samples/bowser_organ/02_boys_choir"
+static const ALIGN_ASSET(2) char gSampleDA[] = dgSampleDA;
+
+static const char* gSampleTable[] = {
+ gSample00, gSample01, gSample02, gSample03,
+ gSample04, gSample05, gSample06, gSample07,
+ gSample08, gSample09, gSample0A, gSample0B,
+ gSample0C, gSample0D, gSample0E, gSample0F,
+ gSample10, gSample11, gSample12, gSample13,
+ gSample14, gSample15, gSample16, gSample17,
+ gSample18, gSample19, gSample1A, gSample1B,
+ gSample1C, gSample1D, gSample1E, gSample1F,
+ gSample20, gSample21, gSample22, gSample23,
+ gSample24, gSample25, gSample26, gSample27,
+ gSample28, gSample29, gSample2A, gSample2B,
+ gSample2C, gSample2D, gSample2E, gSample2F,
+ gSample30, gSample31, gSample32, gSample33,
+ gSample34, gSample35, gSample36, gSample37,
+ gSample38, gSample39, gSample3A, gSample3B,
+ gSample3C, gSample3D, gSample3E, gSample3F,
+ gSample40, gSample41, gSample42, gSample43,
+ gSample44, gSample45, gSample46, gSample47,
+ gSample48, gSample49, gSample4A, gSample4B,
+ gSample4C, gSample4D, gSample4E, gSample4F,
+ gSample50, gSample51, gSample52, gSample53,
+ gSample54, gSample55, gSample56, gSample57,
+ gSample58, gSample59, gSample5A, gSample5B,
+ gSample5C, gSample5D, gSample5E, gSample5F,
+ gSample60, gSample61, gSample62, gSample63,
+ gSample64, gSample65, gSample66, gSample67,
+ gSample68, gSample69, gSample6A, gSample6B,
+ gSample6C, gSample6D, gSample6E, gSample6F,
+ gSample70, gSample71, gSample72, gSample73,
+ gSample74, gSample75, gSample76, gSample77,
+ gSample78, gSample79, gSample7A, gSample7B,
+ gSample7C, gSample7D, gSample7E, gSample7F,
+ gSample80, gSample81, gSample82, gSample83,
+ gSample84, gSample85, gSample86, gSample87,
+ gSample88, gSample89, gSample8A, gSample8B,
+ gSample8C, gSample8D, gSample8E, gSample8F,
+ gSample90, gSample91, gSample92, gSample93,
+ gSample94, gSample95, gSample96, gSample97,
+ gSample98, gSample99, gSample9A, gSample9B,
+ gSample9C, gSample9D, gSample9E, gSample9F,
+ gSampleA0, gSampleA1, gSampleA2, gSampleA3,
+ gSampleA4, gSampleA5, gSampleA6, gSampleA7,
+ gSampleA8, gSampleA9, gSampleAA, gSampleAB,
+ gSampleAC, gSampleAD, gSampleAE, gSampleAF,
+ gSampleB0, gSampleB1, gSampleB2, gSampleB3,
+ gSampleB4, gSampleB5, gSampleB6, gSampleB7,
+ gSampleB8, gSampleB9, gSampleBA, gSampleBB,
+ gSampleBC, gSampleBD, gSampleBE, gSampleBF,
+ gSampleC0, gSampleC1, gSampleC2, gSampleC3,
+ gSampleC4, gSampleC5, gSampleC6, gSampleC7,
+ gSampleC8, gSampleC9, gSampleCA, gSampleCB,
+ gSampleCC, gSampleCD, gSampleCE, gSampleCF,
+ gSampleD0, gSampleD1, gSampleD2, gSampleD3,
+ gSampleD4, gSampleD5, gSampleD6, gSampleD7,
+ gSampleD8, gSampleD9, gSampleDA,
+};
diff --git a/src/factories/AudioFactory.cpp b/src/factories/AudioFactory.cpp
new file mode 100644
index 0000000..bd91a20
--- /dev/null
+++ b/src/factories/AudioFactory.cpp
@@ -0,0 +1,191 @@
+#include "AudioFactory.h"
+
+#include <vector>
+#include "audio/AudioManager.h"
+#include "audio/samples_table.h"
+#include "binarytools/BinaryReader.h"
+
+bool AudioFactory::process(LUS::BinaryWriter* writer, nlohmann::json& data, std::vector<uint8_t>& buffer) {
+ auto metadata = data["offsets"];
+ std::string path = data["path"];
+
+ if(path.find("bank_sets") != std::string::npos){
+ WRITE_HEADER(LUS::ResourceType::Blob, 0);
+ char* raw = (char*) (buffer.data() + metadata[1]["us"][0]);
+ WRITE_U32(metadata[0]);
+ for(int i = 0; i < 0x23; i++){
+ int16_t value;
+ memcpy(&value, raw + (i * 2), 2);
+ WRITE_I16(BSWAP16(value));
+ }
+ writer->Write(raw + 0x46, 0x5A);
+ return true;
+ }
+
+ if(path.find("sound/banks") != std::string::npos){
+ auto banks = AudioManager::Instance->get_banks();
+ auto bankId = metadata["us"][0];
+ auto bank = banks[bankId];
+
+ if(bankId == 10){
+ int bp = 1;
+ }
+
+ WRITE_HEADER(LUS::ResourceType::Bank, 0);
+
+ WRITE_U32(bank.insts.size());
+ for(auto &instrument : bank.insts){
+ WRITE_U8(instrument.valid);
+ if(!instrument.valid){
+ continue;
+ }
+ WRITE_U8(instrument.releaseRate);
+ WRITE_U8(instrument.normalRangeLo);
+ WRITE_U8(instrument.normalRangeHi);
+
+ auto envelope = bank.envelopes[instrument.envelope];
+ if(!envelope.entries.empty()){
+ WRITE_U32(envelope.entries.size());
+ for(auto &entry : envelope.entries){
+ writer->Write(entry.delay);
+ writer->Write(entry.arg);
+ }
+ } else {
+ WRITE_U32(0);
+ }
+
+ uint32_t soundFlags = 0;
+ bool hasLo = instrument.soundLo.has_value();
+ bool hasMed = instrument.soundMed.has_value();
+ bool hasHi = instrument.soundHi.has_value();
+ if(hasLo){
+ soundFlags |= (1 << 0);
+ }
+ if(hasMed){
+ soundFlags |= (1 << 1);
+ }
+ if(hasHi){
+ soundFlags |= (1 << 2);
+ }
+
+ WRITE_U32(soundFlags);
+ if(hasLo){
+ auto value = instrument.soundLo.value();
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
+ writer->Write(std::string(gSampleTable[idx]));
+ writer->Write(value.tuning);
+ }
+ if(hasMed){
+ auto value = instrument.soundMed.value();
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
+ writer->Write(std::string(gSampleTable[idx]));
+ writer->Write(value.tuning);
+ }
+ if(hasHi){
+ auto value = instrument.soundHi.value();
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[value.offset]);
+ writer->Write(std::string(gSampleTable[idx]));
+ writer->Write(value.tuning);
+ }
+
+ }
+
+ WRITE_U32(bank.drums.size());
+ for(auto &drum : bank.drums){
+ WRITE_U8(drum.releaseRate);
+ WRITE_U8(drum.pan);
+ auto envelope = bank.envelopes[drum.envelope];
+ if(!envelope.entries.empty()){
+ std::cout << "Envelope entries: " << envelope.entries.size() << std::endl;
+ WRITE_U32(envelope.entries.size());
+ for(auto &entry : envelope.entries){
+ writer->Write(entry.delay);
+ writer->Write(entry.arg);
+ }
+ } else {
+ WRITE_U32(0);
+ }
+
+ uint32_t idx = AudioManager::Instance->get_index(bank.samples[drum.sound.offset]);
+ std::string out = std::string(gSampleTable[idx]);
+ writer->Write(out);
+ writer->Write(drum.sound.tuning);
+ }
+
+ return true;
+ }
+
+ if(path.find("sound/sequences") != std::string::npos){
+
+ if(!metadata[1].contains("us")){
+ return false;
+ }
+
+ WRITE_HEADER(LUS::ResourceType::Sequence, 0);
+
+ size_t size = metadata[0];
+ auto offsets = metadata[1]["us"];
+
+ std::vector<uint8_t> bank = metadata[1]["banks"];
+
+ WRITE_U32(bank.size());
+ WRITE_ARRAY(bank.data(), bank.size());
+
+ WRITE_U32(size);
+ WRITE_ARRAY(buffer.data() + (size_t)offsets[0], size);
+
+ return true;
+ }
+
+ if(path.find("sound/samples") == std::string::npos || metadata.size() < 2 || !metadata[1].contains("us")){
+ return false;
+ }
+
+ /*
+ * HINT: Uncomment this to write the aiff to a file
+ LUS::BinaryWriter aifcWriter;
+ AudioManager::Instance->create_aifc(metadata[1]["us"][1], aifcWriter);
+ std::vector<char> aifcData = aifcWriter.ToVector();
+ aifcWriter.Close();
+ write_aiff(aifcData, *writer);
+ */
+
+ WRITE_HEADER(LUS::ResourceType::Sample, 0);
+
+ AudioBankSample entry = AudioManager::Instance->get_aifc(metadata[1]["us"][1]);
+
+ // Write AdpcmLoop
+ WRITE_U32(entry.loop.start);
+ WRITE_U32(entry.loop.end);
+ WRITE_I32(entry.loop.count);
+ WRITE_U32(entry.loop.pad);
+
+ if(entry.loop.state.has_value()){
+ std::vector<int16_t> state = entry.loop.state.value();
+ WRITE_U32(state.size());
+ for(auto &value : state){
+ writer->Write(value);
+ }
+ } else {
+ WRITE_U32(0);
+ }
+
+ // Write AdpcmBook
+ WRITE_I32(entry.book.order);
+ WRITE_I32(entry.book.npredictors);
+
+ WRITE_U32(entry.book.table.size());
+ for(auto &value : entry.book.table){
+ writer->Write(value);
+ }
+
+ // Write sample
+ WRITE_I32(entry.data.size());
+ for(auto &value : entry.data){
+ WRITE_U8(value);
+ }
+
+ writer->Write(entry.name);
+
+ return true;
+} \ No newline at end of file
diff --git a/src/factories/AudioFactory.h b/src/factories/AudioFactory.h
new file mode 100644
index 0000000..fdfdb9c
--- /dev/null
+++ b/src/factories/AudioFactory.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include "RawFactory.h"
+
+class AudioFactory : public RawFactory {
+public:
+ AudioFactory() = default;
+ bool process(LUS::BinaryWriter* write, nlohmann::json& data, std::vector<uint8_t>& buffer) override;
+}; \ No newline at end of file
diff --git a/src/factories/BlobFactory.cpp b/src/factories/BlobFactory.cpp
index 7071a45..30714b1 100644
--- a/src/factories/BlobFactory.cpp
+++ b/src/factories/BlobFactory.cpp
@@ -13,11 +13,7 @@ bool BlobFactory::process(LUS::BinaryWriter* writer, nlohmann::json& data, std::
return false;
}
- if(this->bigEndian){
- WRITE_BHEADER(this->type, 0);
- } else {
- WRITE_HEADER(this->type, 0);
- }
+ WRITE_HEADER(this->type, 0);
size_t size = metadata[0];
auto offsets = metadata[1]["us"];
diff --git a/src/factories/RawFactory.h b/src/factories/RawFactory.h
index 7057740..8918b8b 100644
--- a/src/factories/RawFactory.h
+++ b/src/factories/RawFactory.h
@@ -8,10 +8,13 @@
#define WRITE_HEADER(type, version) this->WriteHeader(writer, type, version)
#define WRITE_BHEADER(type, version) this->WriteHeader(writer, type, version, true)
+#define WRITE_U8(value) writer->Write((uint8_t) value)
#define WRITE_U16(value) writer->Write((uint16_t) value)
#define WRITE_U32(value) writer->Write((uint32_t) value)
#define WRITE_U64(value) writer->Write((uint64_t) value)
+#define WRITE_I8(value) writer->Write((int8_t) value)
#define WRITE_I16(value) writer->Write((int16_t) value)
+#define WRITE_I32(value) writer->Write((int32_t) value)
#define WRITE_DATA(vec) writer->Write((char*) vec.data(), data.size())
#define WRITE_ARRAY(data, size) writer->Write((char*) data, size)
diff --git a/src/factories/ResourceType.h b/src/factories/ResourceType.h
index 3d4013b..7dfac06 100644
--- a/src/factories/ResourceType.h
+++ b/src/factories/ResourceType.h
@@ -19,5 +19,8 @@ enum class ResourceType {
Demo = 0x44454D4F, // DEMO
Skybox = 0x534B5942, // SKYB
Anim = 0x414E494D, // ANIM
+ Bank = 0x42414E4B, // BANK
+ Sample = 0x41554643, // AIFC
+ Sequence = 0x53455143, // SEQC
};
} // namespace LUS
diff --git a/tools/gen_banks.js b/tools/gen_banks.js
new file mode 100644
index 0000000..6e1da48
--- /dev/null
+++ b/tools/gen_banks.js
@@ -0,0 +1,37 @@
+const fs = require('fs');
+const data = require('../assets.json');
+
+const header = [
+ '#pragma once',
+ '#include "align_asset_macro.h"',
+ '',
+]
+const banks = []
+
+async function main(){
+ const files = Object.keys(data).filter(f => f.endsWith(".bnk") && data[f]['us'] != undefined).map(m => {
+ return {
+ file: m,
+ offset: data[m]['us'][0]
+ }
+ })
+
+ files.sort((a, b) => a.offset - b.offset);
+
+ for(const entry of files){
+ const sampleId = entry.offset.toString(16).padStart(2, '0').toUpperCase();
+ banks.push(`gBank${sampleId}`);
+ header.push(`#define dgBank${sampleId} "__OTR__${entry.file.replace('.bnk', '')}"`);
+ header.push(`static const ALIGN_ASSET(2) char gBank${sampleId}[] = dgBank${sampleId};\n`);
+ }
+
+ header.push('static const char* gBankTable[] = {');
+ for (const bank of banks) {
+ header.push(` ${bank},`);
+ }
+ header.push('};\n');
+
+ fs.writeFileSync('./banks_table.h', header.join('\n'));
+}
+
+main(); \ No newline at end of file
diff --git a/tools/gen_bankset.js b/tools/gen_bankset.js
new file mode 100644
index 0000000..4b07141
--- /dev/null
+++ b/tools/gen_bankset.js
@@ -0,0 +1,23 @@
+const fs = require('fs');
+const data = require('../sequences.json');
+
+const header = [
+ '#pragma once',
+ '',
+]
+const bankset = []
+
+async function main(){
+ // header.push('static const uint8_t gBankIdxMap[][16] = {');
+ let idx = 0;
+ for(const values of Object.values(data)){
+ const indices = values.map(v => `${parseInt(v.split('_')[0], 16)}`);
+ // header.push(` // Bank: ${Object.keys(data)[idx++]}`);
+ header.push(`[${indices.join(', ')}],`);
+ }
+ // header.push('};\n');
+
+ fs.writeFileSync('./bankset_table.h', header.join('\n'));
+}
+
+main(); \ No newline at end of file
diff --git a/tools/gen_samples.js b/tools/gen_samples.js
new file mode 100644
index 0000000..56cead5
--- /dev/null
+++ b/tools/gen_samples.js
@@ -0,0 +1,37 @@
+const fs = require('fs');
+const data = require('../assets.json');
+
+const header = [
+ '#pragma once',
+ '#include "align_asset_macro.h"',
+ '',
+]
+const samples = []
+
+async function main(){
+ const files = Object.keys(data).filter(f => f.endsWith(".aiff") && data[f][1]['us'] != undefined).map(m => {
+ return {
+ file: m,
+ offset: data[m][1]['us'][1]
+ }
+ })
+
+ files.sort((a, b) => a.offset - b.offset);
+
+ for(const entry of files){
+ const sampleId = entry.offset.toString(16).padStart(2, '0').toUpperCase();
+ samples.push(`gSample${sampleId}`);
+ header.push(`#define dgSample${sampleId} "__OTR__${entry.file.replace('.aiff', '')}"`);
+ header.push(`static const ALIGN_ASSET(2) char gSample${sampleId}[] = dgSample${sampleId};\n`);
+ }
+
+ header.push('static const char* gSampleTable[] = {');
+ for (const sample of samples) {
+ header.push(` ${sample},`);
+ }
+ header.push('};\n');
+
+ fs.writeFileSync('./samples_table.h', header.join('\n'));
+}
+
+main(); \ No newline at end of file
diff --git a/tools/m64test.js b/tools/m64test.js
new file mode 100644
index 0000000..0e4a6f3
--- /dev/null
+++ b/tools/m64test.js
@@ -0,0 +1,32 @@
+const fs = require('fs');
+
+const bytes = fs.readFileSync('./baserom.us.z64');
+const bpath = '../sound/sequences/us/'
+const header = [
+ '#pragma once',
+ '#include "align_asset_macro.h"',
+ '',
+]
+const sequences = []
+
+fs.readdirSync(bpath).forEach(seq => {
+ const seqData = fs.readFileSync(bpath+seq);
+ const seqOffset = bytes.indexOf(seqData);
+ const output = `sound/sequences/${seq}`
+ const seqId = seq.split("_")[0]
+ console.log(`"${output}": ${JSON.stringify([
+ seqData.length,
+ { "us": [ seqOffset ]}
+ ])},`);
+ sequences.push(`gSequence${seqId}`);
+ header.push(`#define dgSequence${seqId} "__OTR__${output}"`);
+ header.push(`static const ALIGN_ASSET(2) char gSequence${seqId}[] = dgSequence${seqId};\n`);
+});
+
+header.push('static const char* gSequenceTable[] = {');
+for (const seq of sequences.sort((a, b) => b.localeCompare(a))) {
+ header.push(` ${seq},`);
+}
+header.push('};\n');
+
+fs.writeFileSync('./sequences_table.h', header.join('\n')); \ No newline at end of file