summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPikalaxALT <PikalaxALT@users.noreply.github.com>2019-08-10 05:15:50 -0400
committerGitHub <noreply@github.com>2019-08-10 05:15:50 -0400
commit9e969601456fb0ef392910d505e0e0673a902bd3 (patch)
treeaf8fdeb1c6cdf9cd8584f0d693a4049bfc408b9d /src
parent250a331df9dbd312d572aaf0d629503417cfc9d4 (diff)
parentba6f243c728de5d5c024aeb177026bcc59909e2e (diff)
Merge pull request #4 from nullableVoidPtr/master
Overhaul
Diffstat (limited to 'src')
-rw-r--r--src/bg_palette_buffer.c248
-rw-r--r--src/file_system.c66
-rw-r--r--src/flash.c3
-rw-r--r--src/m4a_2.c947
-rw-r--r--src/m4a_4.c384
-rw-r--r--src/m4a_tables.c223
-rw-r--r--src/memory.c145
-rw-r--r--src/save.c64
-rw-r--r--src/save1.c13
-rw-r--r--src/sprite.c10
-rw-r--r--src/text.c198
11 files changed, 2254 insertions, 47 deletions
diff --git a/src/bg_palette_buffer.c b/src/bg_palette_buffer.c
new file mode 100644
index 0000000..9917adf
--- /dev/null
+++ b/src/bg_palette_buffer.c
@@ -0,0 +1,248 @@
+#include "global.h"
+
+#define BG_PALETTE_BUFFER_SIZE 512
+#define BG_PALETTE_BUFFER_CHUNK_SIZE 16
+
+extern u16 gBGPaletteBuffer[BG_PALETTE_BUFFER_SIZE];
+extern bool8 gBGPaletteUsed[BG_PALETTE_BUFFER_SIZE / BG_PALETTE_BUFFER_CHUNK_SIZE];
+
+extern void CpuCopy(void* src, void* dest, u32 size);
+
+#ifndef NONMATCHING
+NAKED
+#endif
+void InitBGPaletteBuffer(void)
+{
+#ifdef NONMATCHING
+ u16 color = 0;
+ u16* ptr;
+ u32 i;
+ bool8 paletteUsed;
+
+ u8* p;
+
+ ptr = gBGPaletteBuffer;
+
+ i = 0x80;
+ i <<= 2;
+
+ do {
+ *ptr++ = color;
+ i--;
+ } while (i);
+
+ paletteUsed = TRUE;
+
+ p = gBGPaletteUsed;
+ p += 31;
+
+ do
+ *p-- = paletteUsed;
+ while ((s32) p >= (s32) &gBGPaletteUsed);
+#else
+ asm_unified("\tpush {lr}\n"
+ "\tmovs r2, 0\n"
+ "\tldr r1, =gBGPaletteBuffer\n"
+ "\tmovs r0, 0x80\n"
+ "\tlsls r0, 2\n"
+ "_0800463E:\n"
+ "\tstrh r2, [r1]\n"
+ "\tadds r1, 0x2\n"
+ "\tsubs r0, 0x1\n"
+ "\tcmp r0, 0\n"
+ "\tbne _0800463E\n"
+ "\tldr r1, =gBGPaletteUsed\n"
+ "\tmovs r2, 0x1\n"
+ "\tadds r0, r1, 0\n"
+ "\tadds r0, 0x1F\n"
+ "_08004650:\n"
+ "\tstrb r2, [r0]\n"
+ "\tsubs r0, 0x1\n"
+ "\tcmp r0, r1\n"
+ "\tbge _08004650\n"
+ "\tpop {r0}\n"
+ "\tbx r0\n"
+ "\t.align 2, 0\n"
+ "\t.pool");
+#endif
+}
+
+#ifndef NONMATCHING
+NAKED
+#endif
+void SetBGPaletteBufferColorRGB(s32 index, u8 *RGBArray, s32 a1, u8 *a2)
+{
+#ifdef NONMATCHING
+ if (a1 < 0) {
+ a1 = 0;
+ }
+ if (a1 > 31) {
+ a1 = 31;
+ }
+ gBGPaletteUsed[index / 16] = 1;
+ if (!a2) {
+ gBGPaletteBuffer[index] = ((RGBArray[2] * a1 / 256 & 0x1F) << 10) | ((RGBArray[1] * a1 / 256 & 0x1F) << 5) | (RGBArray[0] * a1 / 256 & 0x1F);
+ }
+ else
+ {
+ gBGPaletteBuffer[index] = ((a2[4 * RGBArray[2] + 2] * a1 / 256 & 0x1F) << 10) | ((a2[4 * RGBArray[1] + 1] * a1 / 256 & 0x1F) << 5) | (a2[4 * RGBArray[0]] * a1 / 256 & 0x1F);
+ }
+#else
+ asm_unified("\tpush {r4-r7,lr}\n"
+ "\tadds r4, r0, 0\n"
+ "\tadds r5, r1, 0\n"
+ "\tcmp r2, 0\n"
+ "\tbge _08004670\n"
+ "\tmovs r2, 0\n"
+ "_08004670:\n"
+ "\tcmp r2, 0x1F\n"
+ "\tble _08004676\n"
+ "\tmovs r2, 0x1F\n"
+ "_08004676:\n"
+ "\tldr r1, =gBGPaletteUsed\n"
+ "\tadds r0, r4, 0\n"
+ "\tcmp r4, 0\n"
+ "\tbge _08004680\n"
+ "\tadds r0, 0xF\n"
+ "_08004680:\n"
+ "\tasrs r0, 4\n"
+ "\tadds r0, r1\n"
+ "\tmovs r1, 0x1\n"
+ "\tstrb r1, [r0]\n"
+ "\tcmp r3, 0\n"
+ "\tbne _080046D4\n"
+ "\tldr r0, =gBGPaletteBuffer\n"
+ "\tlsls r1, r4, 1\n"
+ "\tadds r6, r1, r0\n"
+ "\tldrb r0, [r5, 0x2]\n"
+ "\tmuls r0, r2\n"
+ "\tcmp r0, 0\n"
+ "\tbge _0800469C\n"
+ "\tadds r0, 0xFF\n"
+ "_0800469C:\n"
+ "\tasrs r0, 8\n"
+ "\tmovs r3, 0x1F\n"
+ "\tands r0, r3\n"
+ "\tlsls r4, r0, 10\n"
+ "\tldrb r0, [r5, 0x1]\n"
+ "\tmuls r0, r2\n"
+ "\tcmp r0, 0\n"
+ "\tbge _080046AE\n"
+ "\tadds r0, 0xFF\n"
+ "_080046AE:\n"
+ "\tasrs r0, 8\n"
+ "\tands r0, r3\n"
+ "\tlsls r1, r0, 5\n"
+ "\torrs r1, r4\n"
+ "\tldrb r0, [r5]\n"
+ "\tmuls r0, r2\n"
+ "\tcmp r0, 0\n"
+ "\tbge _080046C0\n"
+ "\tadds r0, 0xFF\n"
+ "_080046C0:\n"
+ "\tasrs r0, 8\n"
+ "\tands r0, r3\n"
+ "\torrs r1, r0\n"
+ "\tstrh r1, [r6]\n"
+ "\tb _08004722\n"
+ "\t.align 2, 0\n"
+ "\t.pool\n"
+ "_080046D4:\n"
+ "\tldr r1, =gBGPaletteBuffer\n"
+ "\tlsls r0, r4, 1\n"
+ "\tadds r7, r0, r1\n"
+ "\tldrb r0, [r5, 0x2]\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r3\n"
+ "\tldrb r0, [r0, 0x2]\n"
+ "\tmuls r0, r2\n"
+ "\tcmp r0, 0\n"
+ "\tbge _080046EA\n"
+ "\tadds r0, 0xFF\n"
+ "_080046EA:\n"
+ "\tasrs r0, 8\n"
+ "\tmovs r4, 0x1F\n"
+ "\tands r0, r4\n"
+ "\tlsls r6, r0, 10\n"
+ "\tldrb r0, [r5, 0x1]\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r3\n"
+ "\tldrb r0, [r0, 0x1]\n"
+ "\tmuls r0, r2\n"
+ "\tcmp r0, 0\n"
+ "\tbge _08004702\n"
+ "\tadds r0, 0xFF\n"
+ "_08004702:\n"
+ "\tasrs r0, 8\n"
+ "\tands r0, r4\n"
+ "\tlsls r1, r0, 5\n"
+ "\torrs r1, r6\n"
+ "\tldrb r0, [r5]\n"
+ "\tlsls r0, 2\n"
+ "\tadds r0, r3\n"
+ "\tldrb r0, [r0]\n"
+ "\tmuls r0, r2\n"
+ "\tcmp r0, 0\n"
+ "\tbge _0800471A\n"
+ "\tadds r0, 0xFF\n"
+ "_0800471A:\n"
+ "\tasrs r0, 8\n"
+ "\tands r0, r4\n"
+ "\torrs r1, r0\n"
+ "\tstrh r1, [r7]\n"
+ "_08004722:\n"
+ "\tpop {r4-r7}\n"
+ "\tpop {r0}\n"
+ "\tbx r0\n"
+ "\t.align 2, 0\n"
+ "\t.pool");
+#endif
+}
+
+void SetBGPaletteBufferColorArray(s32 index, u8 *colorArray)
+{
+ gBGPaletteUsed[index / BG_PALETTE_BUFFER_CHUNK_SIZE] = TRUE;
+ gBGPaletteBuffer[index] = (colorArray[2] >> 3) << 10 | (colorArray[1] >> 3) << 5 | colorArray[0] >> 3;
+}
+
+void SetBGPaletteBufferColor(s32 index, u16 *color)
+{
+ gBGPaletteUsed[index / BG_PALETTE_BUFFER_CHUNK_SIZE] = TRUE;
+ gBGPaletteBuffer[index] = *color;
+}
+
+void nullsub_4(void)
+{
+
+}
+void nullsub_5(void)
+{
+
+}
+void nullsub_143(void)
+{
+
+}
+
+void TransferBGPaletteBuffer(void)
+{
+ u32 i;
+ s32 paletteBufferIndex;
+ u16 *dest;
+
+ i = 0;
+ paletteBufferIndex = 0;
+ dest = (u16 *)PLTT;
+ do
+ {
+ if (gBGPaletteUsed[i])
+ {
+ gBGPaletteUsed[i] = 0;
+ CpuCopy(dest, &gBGPaletteBuffer[paletteBufferIndex], sizeof(u16) * 16);
+ }
+ ++i;
+ dest += 16;
+ paletteBufferIndex += 16;
+ }
+ while ( paletteBufferIndex < BG_PALETTE_BUFFER_SIZE );
+}
diff --git a/src/file_system.c b/src/file_system.c
index 296478d..61d9ec4 100644
--- a/src/file_system.c
+++ b/src/file_system.c
@@ -1,33 +1,9 @@
#include "global.h"
+#include "file_system.h"
-struct File
-{
- char *name;
- u8 *data;
-};
-
-struct OpenedFile
-{
- struct File *file;
- u8 *data;
-};
-
-struct FileArchive
-{
- char magic[8];
- s32 count;
- struct File *entries;
-};
-
-struct SiroArchive
-{
- u32 magic;
- u8 *data;
-};
-
-extern struct OpenedFile gUnknown_202D2A8[];
+extern struct OpenedFile gFileCache[64];
-extern u32 gUnknown_203B094;
+extern u32 gFileCacheCursorPosition;
extern u32 gUnknown_202D2A4;
extern int sprintf(char *, const char *, ...);
@@ -41,11 +17,11 @@ void InitFileSystem(void)
for (i = 0; i < 64; i++)
{
- gUnknown_202D2A8[i].file = NULL;
- gUnknown_202D2A8[i].data = NULL;
+ gFileCache[i].file = NULL;
+ gFileCache[i].data = NULL;
}
- gUnknown_203B094 = 0;
+ gFileCacheCursorPosition = 0;
gUnknown_202D2A4 = 1;
}
@@ -56,14 +32,14 @@ u32 sub_800A8F8(u32 value)
return oldValue;
}
-struct OpenedFile *OpenFile(char *filename, struct FileArchive *arc)
+struct OpenedFile *OpenFile(const char *filename, const struct FileArchive *arc)
{
char buffer[0x12C];
s32 left, right;
s32 cursor;
s32 i;
- s32 magic = 0;
- s32 magicFound;
+ u32 magic = 0;
+ bool32 magicFound;
struct File *entries;
struct File *file;
@@ -71,7 +47,7 @@ struct OpenedFile *OpenFile(char *filename, struct FileArchive *arc)
magicFound = 0;
- if (!(u8)magic)
+ if (!(bool8)magic)
magicFound = 1;
if (!magicFound)
@@ -108,18 +84,18 @@ struct OpenedFile *OpenFile(char *filename, struct FileArchive *arc)
return NULL;
}
- cursor = gUnknown_203B094;
+ cursor = gFileCacheCursorPosition;
for (i = 0; i < 64; i++)
{
cursor++;
if (cursor > 63)
cursor = 0;
- if (!gUnknown_202D2A8[cursor].file)
+ if (!gFileCache[cursor].file)
{
- gUnknown_202D2A8[cursor].file = file;
- gUnknown_202D2A8[cursor].data = NULL;
- return &gUnknown_202D2A8[cursor];
+ gFileCache[cursor].file = file;
+ gFileCache[cursor].data = NULL;
+ return &gFileCache[cursor];
}
}
@@ -138,7 +114,7 @@ u8 *GetFileDataPtr(struct OpenedFile *openedFile, int unused)
return GetSiroPtr(openedFile);
}
-struct OpenedFile *OpenFileAndGetFileDataPtr(char *filename, struct FileArchive *arc)
+struct OpenedFile *OpenFileAndGetFileDataPtr(const char *filename, const struct FileArchive *arc)
{
struct OpenedFile *openedFile = OpenFile(filename, arc);
if (openedFile)
@@ -146,7 +122,7 @@ struct OpenedFile *OpenFileAndGetFileDataPtr(char *filename, struct FileArchive
return openedFile;
}
-struct OpenedFile *Call_OpenFileAndGetFileDataPtr(char *filename, struct FileArchive *arc)
+struct OpenedFile *Call_OpenFileAndGetFileDataPtr(const char *filename, const struct FileArchive *arc)
{
return OpenFileAndGetFileDataPtr(filename, arc);
}
@@ -157,11 +133,11 @@ void CloseFile(struct OpenedFile *openedFile)
for (i = 0; i < 64; i++)
{
- if (&gUnknown_202D2A8[i] == openedFile)
+ if (&gFileCache[i] == openedFile)
{
- gUnknown_202D2A8[i].file = NULL;
- gUnknown_202D2A8[i].data = NULL;
- gUnknown_203B094 = i;
+ gFileCache[i].file = NULL;
+ gFileCache[i].data = NULL;
+ gFileCacheCursorPosition = i;
return;
}
}
diff --git a/src/flash.c b/src/flash.c
index b9ccf40..11520b4 100644
--- a/src/flash.c
+++ b/src/flash.c
@@ -1,12 +1,11 @@
#include "global.h"
#include "gba/flash.h"
#include "flash.h"
+#include "memory.h"
extern u8 gFlashEnabled;
extern FlashIntrFunc *sub_800B6E8(s32);
-extern void MemoryFill8(void *, u8, s32);
-extern void MemoryCopy8(void *, void *, s32);
static u8 TryProgramSector(s32, u8 *);
diff --git a/src/m4a_2.c b/src/m4a_2.c
new file mode 100644
index 0000000..ce9ac19
--- /dev/null
+++ b/src/m4a_2.c
@@ -0,0 +1,947 @@
+#include "gba/m4a_internal.h"
+#include "global.h"
+
+extern char SoundMainRAM_Buffer[0x400];
+
+extern struct SoundInfo gSoundInfo;
+
+
+u32 MidiKeyToFreq(struct WaveData *wav, u8 key, u8 fineAdjust)
+{
+ u32 val1;
+ u32 val2;
+ u32 fineAdjustShifted = fineAdjust << 24;
+
+ if (key > 178)
+ {
+ key = 178;
+ fineAdjustShifted = 255 << 24;
+ }
+
+ val1 = gScaleTable[key];
+ val1 = gFreqTable[val1 & 0xF] >> (val1 >> 4);
+
+ val2 = gScaleTable[key + 1];
+ val2 = gFreqTable[val2 & 0xF] >> (val2 >> 4);
+
+ return umul3232H32(wav->freq, val1 + umul3232H32(val2 - val1, fineAdjustShifted));
+}
+
+void UnusedDummyFunc()
+{
+}
+
+void MPlayContinue(struct MusicPlayerInfo *mplayInfo)
+{
+ if (mplayInfo->ident == ID_NUMBER)
+ {
+ mplayInfo->ident++;
+ mplayInfo->status &= ~MUSICPLAYER_STATUS_PAUSE;
+ mplayInfo->ident = ID_NUMBER;
+ }
+}
+
+void MPlayFadeOut(struct MusicPlayerInfo *mplayInfo, u16 speed)
+{
+ if (mplayInfo->ident == ID_NUMBER)
+ {
+ mplayInfo->ident++;
+ mplayInfo->fadeOC = speed;
+ mplayInfo->fadeOI = speed;
+ mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT);
+ mplayInfo->ident = ID_NUMBER;
+ }
+}
+
+void m4aSoundInit(void)
+{
+ s32 i;
+
+ CpuCopy32((void *)((s32)SoundMainRAM & ~1), SoundMainRAM_Buffer, sizeof(SoundMainRAM_Buffer));
+
+ SoundInit(&gSoundInfo);
+ MPlayExtender(gCgbChans);
+ m4aSoundMode(SOUND_MODE_DA_BIT_8
+ | SOUND_MODE_FREQ_18157
+ | (14 << SOUND_MODE_MASVOL_SHIFT)
+ | (5 << SOUND_MODE_MAXCHN_SHIFT));
+
+ for (i = 0; i < NUM_MUSIC_PLAYERS; i++)
+ {
+ struct MusicPlayerInfo *mplayInfo = gMPlayTable[i].info;
+ MPlayOpen(mplayInfo, gMPlayTable[i].track, gMPlayTable[i].unk_8);
+ mplayInfo->unk_B = gMPlayTable[i].unk_A;
+ mplayInfo->memAccArea = gMPlayMemAccArea;
+ }
+}
+
+void m4aSoundMain(void)
+{
+ SoundMain();
+}
+
+void m4aSongNumStart(u16 n)
+{
+ const struct MusicPlayer *mplayTable = gMPlayTable;
+ const struct Song *songTable = gSongTable;
+ const struct Song *song = &songTable[n];
+ const struct MusicPlayer *mplay = &mplayTable[song->ms];
+
+ MPlayStart(mplay->info, song->header);
+}
+
+void m4aSongNumStartOrChange(u16 n)
+{
+ const struct MusicPlayer *mplayTable = gMPlayTable;
+ const struct Song *songTable = gSongTable;
+ const struct Song *song = &songTable[n];
+ const struct MusicPlayer *mplay = &mplayTable[song->ms];
+
+ if (mplay->info->songHeader != song->header)
+ {
+ MPlayStart(mplay->info, song->header);
+ }
+ else
+ {
+ if ((mplay->info->status & MUSICPLAYER_STATUS_TRACK) == 0
+ || (mplay->info->status & MUSICPLAYER_STATUS_PAUSE))
+ {
+ MPlayStart(mplay->info, song->header);
+ }
+ }
+}
+
+void m4aSongNumStartOrContinue(u16 n)
+{
+ const struct MusicPlayer *mplayTable = gMPlayTable;
+ const struct Song *songTable = gSongTable;
+ const struct Song *song = &songTable[n];
+ const struct MusicPlayer *mplay = &mplayTable[song->ms];
+
+ if (mplay->info->songHeader != song->header)
+ MPlayStart(mplay->info, song->header);
+ else if ((mplay->info->status & MUSICPLAYER_STATUS_TRACK) == 0)
+ MPlayStart(mplay->info, song->header);
+ else if (mplay->info->status & MUSICPLAYER_STATUS_PAUSE)
+ MPlayContinue(mplay->info);
+}
+
+
+void m4aSongNumStop(u16 n)
+{
+ const struct MusicPlayer *mplayTable = gMPlayTable;
+ const struct Song *songTable = gSongTable;
+ const struct Song *song = &songTable[n];
+ const struct MusicPlayer *mplay = &mplayTable[song->ms];
+
+ if (mplay->info->songHeader == song->header)
+ m4aMPlayStop(mplay->info);
+}
+
+void m4aSongNumContinue(u16 n)
+{
+ const struct MusicPlayer *mplayTable = gMPlayTable;
+ const struct Song *songTable = gSongTable;
+ const struct Song *song = &songTable[n];
+ const struct MusicPlayer *mplay = &mplayTable[song->ms];
+
+ if (mplay->info->songHeader == song->header)
+ MPlayContinue(mplay->info);
+}
+
+void m4aMPlayAllStop(void)
+{
+ s32 i;
+
+ for (i = 0; i < NUM_MUSIC_PLAYERS; i++)
+ m4aMPlayStop(gMPlayTable[i].info);
+}
+
+void m4aMPlayContinue(struct MusicPlayerInfo *mplayInfo)
+{
+ MPlayContinue(mplayInfo);
+}
+
+void m4aMPlayAllContinue(void)
+{
+ s32 i;
+
+ for (i = 0; i < NUM_MUSIC_PLAYERS; i++)
+ MPlayContinue(gMPlayTable[i].info);
+}
+
+void m4aMPlayFadeOut(struct MusicPlayerInfo *mplayInfo, u16 speed)
+{
+ MPlayFadeOut(mplayInfo, speed);
+}
+
+void m4aMPlayFadeOutTemporarily(struct MusicPlayerInfo *mplayInfo, u16 speed)
+{
+ if (mplayInfo->ident == ID_NUMBER)
+ {
+ mplayInfo->ident++;
+ mplayInfo->fadeOC = speed;
+ mplayInfo->fadeOI = speed;
+ mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT) | TEMPORARY_FADE;
+ mplayInfo->ident = ID_NUMBER;
+ }
+}
+void m4aMPlayFadeIn(struct MusicPlayerInfo *mplayInfo, u16 speed)
+{
+ if (mplayInfo->ident == ID_NUMBER)
+ {
+ mplayInfo->ident++;
+ mplayInfo->fadeOC = speed;
+ mplayInfo->fadeOI = speed;
+ mplayInfo->fadeOV = (0 << FADE_VOL_SHIFT) | FADE_IN;
+ mplayInfo->status &= ~MUSICPLAYER_STATUS_PAUSE;
+ mplayInfo->ident = ID_NUMBER;
+ }
+}
+
+void m4aMPlayImmInit(struct MusicPlayerInfo *mplayInfo)
+{
+ s32 trackCount = mplayInfo->trackCount;
+ struct MusicPlayerTrack *track = mplayInfo->tracks;
+
+ while (trackCount > 0)
+ {
+ if (track->flags & MPT_FLG_EXIST)
+ {
+ if (track->flags & MPT_FLG_START)
+ {
+ Clear64byte(track);
+ track->flags = MPT_FLG_EXIST;
+ track->bendRange = 2;
+ track->volX = 64;
+ track->lfoSpeed = 22;
+ track->tone.type = 1;
+ }
+ }
+
+ trackCount--;
+ track++;
+ }
+}
+
+void MPlayExtender(struct CgbChannel *cgbChans)
+{
+ struct SoundInfo *soundInfo;
+ u32 ident;
+
+ REG_SOUNDCNT_X = SOUND_MASTER_ENABLE
+ | SOUND_4_ON
+ | SOUND_3_ON
+ | SOUND_2_ON
+ | SOUND_1_ON;
+ REG_SOUNDCNT_L = 0; // set master volume to zero
+ REG_NR12 = 0x8;
+ REG_NR22 = 0x8;
+ REG_NR42 = 0x8;
+ REG_NR14 = 0x80;
+ REG_NR24 = 0x80;
+ REG_NR44 = 0x80;
+ REG_NR30 = 0;
+ REG_NR50 = 0x77;
+
+ soundInfo = SOUND_INFO_PTR;
+
+ ident = soundInfo->ident;
+
+ if (ident != ID_NUMBER)
+ return;
+
+ soundInfo->ident++;
+
+ gMPlayJumpTable[8] = ply_memacc;
+ gMPlayJumpTable[17] = ply_lfos;
+ gMPlayJumpTable[19] = ply_mod;
+ gMPlayJumpTable[28] = ply_xcmd;
+ gMPlayJumpTable[29] = ply_endtie;
+ gMPlayJumpTable[30] = SampleFreqSet;
+ gMPlayJumpTable[31] = TrackStop;
+ gMPlayJumpTable[32] = FadeOutBody;
+ gMPlayJumpTable[33] = TrkVolPitSet;
+
+ soundInfo->cgbChans = (struct CgbChannel *)cgbChans;
+ soundInfo->CgbSound = CgbSound;
+ soundInfo->CgbOscOff = CgbOscOff;
+ soundInfo->MidiKeyToCgbFreq = MidiKeyToCgbFreq;
+ soundInfo->maxLines = MAX_LINES;
+
+ CpuFill32(0, cgbChans, sizeof(struct CgbChannel) * 4);
+
+ cgbChans[0].ty = 1;
+ cgbChans[0].panMask = 0x11;
+ cgbChans[1].ty = 2;
+ cgbChans[1].panMask = 0x22;
+ cgbChans[2].ty = 3;
+ cgbChans[2].panMask = 0x44;
+ cgbChans[3].ty = 4;
+ cgbChans[3].panMask = 0x88;
+
+ soundInfo->ident = ident;
+}
+
+void MusicPlayerJumpTableCopy(void)
+{
+ asm("swi 0x2A");
+}
+
+void ClearChain(void *x)
+{
+ void (*func)(void *) = *(&gMPlayJumpTable[34]);
+ func(x);
+}
+
+void Clear64byte(void *x)
+{
+ void (*func)(void *) = *(&gMPlayJumpTable[35]);
+ func(x);
+}
+
+void SoundInit(struct SoundInfo *soundInfo)
+{
+ soundInfo->ident = 0;
+
+ if (REG_DMA1CNT & (DMA_REPEAT << 16))
+ REG_DMA1CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4;
+
+ if (REG_DMA2CNT & (DMA_REPEAT << 16))
+ REG_DMA2CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4;
+
+ REG_DMA1CNT_H = DMA_32BIT;
+ REG_DMA2CNT_H = DMA_32BIT;
+ REG_SOUNDCNT_X = SOUND_MASTER_ENABLE
+ | SOUND_4_ON
+ | SOUND_3_ON
+ | SOUND_2_ON
+ | SOUND_1_ON;
+ REG_SOUNDCNT_H = SOUND_B_FIFO_RESET | SOUND_B_TIMER_0 | SOUND_B_LEFT_OUTPUT
+ | SOUND_A_FIFO_RESET | SOUND_A_TIMER_0 | SOUND_A_RIGHT_OUTPUT
+ | SOUND_ALL_MIX_FULL;
+ REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | 0x40;
+
+ REG_DMA1SAD = (s32)soundInfo->pcmBuffer;
+ REG_DMA1DAD = (s32)&REG_FIFO_A;
+ REG_DMA2SAD = (s32)soundInfo->pcmBuffer + PCM_DMA_BUF_SIZE;
+ REG_DMA2DAD = (s32)&REG_FIFO_B;
+
+ SOUND_INFO_PTR = soundInfo;
+ CpuFill32(0, soundInfo, sizeof(struct SoundInfo));
+
+ soundInfo->maxChans = 8;
+ soundInfo->masterVolume = 15;
+ soundInfo->plynote = (u32)ply_note;
+ soundInfo->CgbSound = DummyFunc;
+ soundInfo->CgbOscOff = (void (*)(u8))DummyFunc;
+ soundInfo->MidiKeyToCgbFreq = (u32 (*)(u8, u8, u8))DummyFunc;
+ soundInfo->ExtVolPit = (u32)DummyFunc;
+
+ MPlayJumpTableCopy(gMPlayJumpTable);
+
+ soundInfo->MPlayJumpTable = (u32)gMPlayJumpTable;
+
+ SampleFreqSet(SOUND_MODE_FREQ_13379);
+
+ soundInfo->ident = ID_NUMBER;
+}
+
+void SampleFreqSet(u32 freq)
+{
+ struct SoundInfo *soundInfo = SOUND_INFO_PTR;
+
+ freq = (freq & 0xF0000) >> 16;
+ soundInfo->freq = freq;
+ soundInfo->pcmSamplesPerVBlank = gPcmSamplesPerVBlankTable[freq - 1];
+ soundInfo->pcmDmaPeriod = PCM_DMA_BUF_SIZE / soundInfo->pcmSamplesPerVBlank;
+
+ // LCD refresh rate 59.7275Hz
+ soundInfo->pcmFreq = (597275 * soundInfo->pcmSamplesPerVBlank + 5000) / 10000;
+
+ // CPU frequency 16.78Mhz
+ soundInfo->divFreq = (16777216 / soundInfo->pcmFreq + 1) >> 1;
+
+ // Turn off timer 0.
+ REG_TM0CNT_H = 0;
+
+ // cycles per LCD fresh 280896
+ REG_TM0CNT_L = -(280896 / soundInfo->pcmSamplesPerVBlank);
+
+ m4aSoundVSyncOn();
+
+ while (*(vu8 *)REG_ADDR_VCOUNT == 159)
+ ;
+
+ while (*(vu8 *)REG_ADDR_VCOUNT != 159)
+ ;
+
+ REG_TM0CNT_H = TIMER_ENABLE | TIMER_1CLK;
+}
+
+void m4aSoundMode(u32 mode)
+{
+ struct SoundInfo *soundInfo = SOUND_INFO_PTR;
+ u32 temp;
+
+ if (soundInfo->ident != ID_NUMBER)
+ return;
+
+ soundInfo->ident++;
+
+ temp = mode & (SOUND_MODE_REVERB_SET | SOUND_MODE_REVERB_VAL);
+
+ if (temp)
+ soundInfo->reverb = temp & SOUND_MODE_REVERB_VAL;
+
+ temp = mode & SOUND_MODE_MAXCHN;
+
+ if (temp)
+ {
+ struct SoundChannel *chan;
+
+ soundInfo->maxChans = temp >> SOUND_MODE_MAXCHN_SHIFT;
+
+ temp = MAX_DIRECTSOUND_CHANNELS;
+ chan = &soundInfo->chans[0];
+
+ while (temp != 0)
+ {
+ chan->status = 0;
+ temp--;
+ chan++;
+ }
+ }
+
+ temp = mode & SOUND_MODE_MASVOL;
+
+ if (temp)
+ soundInfo->masterVolume = temp >> SOUND_MODE_MASVOL_SHIFT;
+
+ temp = mode & SOUND_MODE_DA_BIT;
+
+ if (temp)
+ {
+ temp = (temp & 0x300000) >> 14;
+ REG_SOUNDBIAS_H = (REG_SOUNDBIAS_H & 0x3F) | temp;
+ }
+
+ temp = mode & SOUND_MODE_FREQ;
+
+ if (temp)
+ {
+ m4aSoundVSyncOff();
+ SampleFreqSet(temp);
+ }
+
+ soundInfo->ident = ID_NUMBER;
+}
+
+void SoundClear(void)
+{
+ struct SoundInfo *soundInfo = SOUND_INFO_PTR;
+ s32 i;
+ void *chan;
+
+ if (soundInfo->ident != ID_NUMBER)
+ return;
+
+ soundInfo->ident++;
+
+ i = MAX_DIRECTSOUND_CHANNELS;
+ chan = &soundInfo->chans[0];
+
+ while (i > 0)
+ {
+ ((struct SoundChannel *)chan)->status = 0;
+ i--;
+ chan = (void *)((s32)chan + sizeof(struct SoundChannel));
+ }
+
+ chan = soundInfo->cgbChans;
+
+ if (chan)
+ {
+ i = 1;
+
+ while (i <= 4)
+ {
+ soundInfo->CgbOscOff(i);
+ ((struct CgbChannel *)chan)->sf = 0;
+ i++;
+ chan = (void *)((s32)chan + sizeof(struct CgbChannel));
+ }
+ }
+
+ soundInfo->ident = ID_NUMBER;
+}
+
+void m4aSoundVSyncOff(void)
+{
+ struct SoundInfo *soundInfo = SOUND_INFO_PTR;
+
+ if (soundInfo->ident >= ID_NUMBER && soundInfo->ident <= ID_NUMBER + 1)
+ {
+ soundInfo->ident += 10;
+
+ if (REG_DMA1CNT & (DMA_REPEAT << 16))
+ REG_DMA1CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4;
+
+ if (REG_DMA2CNT & (DMA_REPEAT << 16))
+ REG_DMA2CNT = ((DMA_ENABLE | DMA_START_NOW | DMA_32BIT | DMA_SRC_INC | DMA_DEST_FIXED) << 16) | 4;
+
+ REG_DMA1CNT_H = DMA_32BIT;
+ REG_DMA2CNT_H = DMA_32BIT;
+
+ CpuFill32(0, soundInfo->pcmBuffer, sizeof(soundInfo->pcmBuffer));
+ }
+}
+
+void m4aSoundVSyncOn(void)
+{
+ struct SoundInfo *soundInfo = SOUND_INFO_PTR;
+ u32 ident = soundInfo->ident;
+
+ if (ident == ID_NUMBER)
+ return;
+
+ REG_DMA1CNT_H = DMA_ENABLE | DMA_START_SPECIAL | DMA_32BIT | DMA_REPEAT;
+ REG_DMA2CNT_H = DMA_ENABLE | DMA_START_SPECIAL | DMA_32BIT | DMA_REPEAT;
+
+ soundInfo->pcmDmaCounter = 0;
+ soundInfo->ident = ident - 10;
+}
+
+void MPlayOpen(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *tracks, u8 trackCount)
+{
+ struct SoundInfo *soundInfo;
+
+ if (trackCount == 0)
+ return;
+
+ if (trackCount > MAX_MUSICPLAYER_TRACKS)
+ trackCount = MAX_MUSICPLAYER_TRACKS;
+
+ soundInfo = SOUND_INFO_PTR;
+
+ if (soundInfo->ident != ID_NUMBER)
+ return;
+
+ soundInfo->ident++;
+
+ Clear64byte(mplayInfo);
+
+ mplayInfo->tracks = tracks;
+ mplayInfo->trackCount = trackCount;
+ mplayInfo->status = MUSICPLAYER_STATUS_PAUSE;
+
+ while (trackCount != 0)
+ {
+ tracks->flags = 0;
+ trackCount--;
+ tracks++;
+ }
+
+ if (soundInfo->func != 0)
+ {
+ mplayInfo->func = soundInfo->func;
+ mplayInfo->intp = soundInfo->intp;
+ soundInfo->func = 0;
+ }
+
+ soundInfo->intp = (u32)mplayInfo;
+ soundInfo->func = (u32)MPlayMain;
+ soundInfo->ident = ID_NUMBER;
+ mplayInfo->ident = ID_NUMBER;
+}
+
+void MPlayStart(struct MusicPlayerInfo *mplayInfo, struct SongHeader *songHeader)
+{
+ s32 i;
+ u8 unk_B;
+ struct MusicPlayerTrack *track;
+
+ if (mplayInfo->ident != ID_NUMBER)
+ return;
+
+ unk_B = mplayInfo->unk_B;
+
+ if (!unk_B
+ || ((!mplayInfo->songHeader || !(mplayInfo->tracks[0].flags & MPT_FLG_START))
+ && ((mplayInfo->status & MUSICPLAYER_STATUS_TRACK) == 0
+ || (mplayInfo->status & MUSICPLAYER_STATUS_PAUSE)))
+ || (mplayInfo->priority <= songHeader->priority))
+ {
+ mplayInfo->ident++;
+ mplayInfo->status = 0;
+ mplayInfo->songHeader = songHeader;
+ mplayInfo->tone = songHeader->tone;
+ mplayInfo->priority = songHeader->priority;
+ mplayInfo->clock = 0;
+ mplayInfo->tempoD = 150;
+ mplayInfo->tempoI = 150;
+ mplayInfo->tempoU = 0x100;
+ mplayInfo->tempoC = 0;
+ mplayInfo->fadeOI = 0;
+
+ i = 0;
+ track = mplayInfo->tracks;
+
+ while (i < songHeader->trackCount && i < mplayInfo->trackCount)
+ {
+ TrackStop(mplayInfo, track);
+ track->flags = MPT_FLG_EXIST | MPT_FLG_START;
+ track->chan = 0;
+ track->cmdPtr = songHeader->part[i];
+ i++;
+ track++;
+ }
+
+ while (i < mplayInfo->trackCount)
+ {
+ TrackStop(mplayInfo, track);
+ track->flags = 0;
+ i++;
+ track++;
+ }
+
+ if (songHeader->reverb & 0x80)
+ m4aSoundMode(songHeader->reverb);
+
+ mplayInfo->ident = ID_NUMBER;
+ }
+}
+
+void m4aMPlayStop(struct MusicPlayerInfo *mplayInfo)
+{
+ s32 i;
+ struct MusicPlayerTrack *track;
+
+ if (mplayInfo->ident != ID_NUMBER)
+ return;
+
+ mplayInfo->ident++;
+ mplayInfo->status |= MUSICPLAYER_STATUS_PAUSE;
+
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+
+ while (i > 0)
+ {
+ TrackStop(mplayInfo, track);
+ i--;
+ track++;
+ }
+
+ mplayInfo->ident = ID_NUMBER;
+}
+
+void FadeOutBody(struct MusicPlayerInfo *mplayInfo)
+{
+ s32 i;
+ struct MusicPlayerTrack *track;
+ u16 fadeOI = mplayInfo->fadeOI;
+ register u32 temp asm("r3");
+ register u16 mask asm("r2");
+
+ if (fadeOI == 0)
+ return;
+
+ mplayInfo->fadeOC--;
+
+ temp = 0xFFFF;
+ mask = temp;
+
+ if (mplayInfo->fadeOC != 0)
+ return;
+
+ mplayInfo->fadeOC = fadeOI;
+
+ if (mplayInfo->fadeOV & FADE_IN)
+ {
+ mplayInfo->fadeOV += (4 << FADE_VOL_SHIFT);
+
+ if ((u16)(mplayInfo->fadeOV & mask) >= (64 << FADE_VOL_SHIFT))
+ {
+ mplayInfo->fadeOV = (64 << FADE_VOL_SHIFT);
+ mplayInfo->fadeOI = 0;
+ }
+ }
+ else
+ {
+ mplayInfo->fadeOV -= (4 << FADE_VOL_SHIFT);
+
+ if ((s16)(mplayInfo->fadeOV & mask) <= 0)
+ {
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+
+ while (i > 0)
+ {
+ register u32 fadeOV asm("r7");
+ u32 val;
+
+ TrackStop(mplayInfo, track);
+
+ val = TEMPORARY_FADE;
+ fadeOV = mplayInfo->fadeOV;
+ val &= fadeOV;
+
+ if (!val)
+ track->flags = 0;
+
+ i--;
+ track++;
+ }
+
+ if (mplayInfo->fadeOV & TEMPORARY_FADE)
+ mplayInfo->status |= MUSICPLAYER_STATUS_PAUSE;
+ else
+ mplayInfo->status = MUSICPLAYER_STATUS_PAUSE;
+
+ mplayInfo->fadeOI = 0;
+ return;
+ }
+ }
+
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+
+ while (i > 0)
+ {
+ if (track->flags & MPT_FLG_EXIST)
+ {
+ track->volX = (mplayInfo->fadeOV >> FADE_VOL_SHIFT);
+ track->flags |= MPT_FLG_VOLCHG;
+ }
+
+ i--;
+ track++;
+ }
+}
+
+void TrkVolPitSet(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ if (track->flags & MPT_FLG_VOLSET)
+ {
+ s32 x;
+ s32 y;
+
+ x = (u32)(track->vol * track->volX) >> 5;
+
+ if (track->modT == 1)
+ x = (u32)(x * (track->modM + 128)) >> 7;
+
+ y = 2 * track->pan + track->panX;
+
+ if (track->modT == 2)
+ y += track->modM;
+
+ if (y < -128)
+ y = -128;
+ else if (y > 127)
+ y = 127;
+
+ track->volMR = (u32)((y + 128) * x) >> 8;
+ track->volML = (u32)((127 - y) * x) >> 8;
+ }
+
+ if (track->flags & MPT_FLG_PITSET)
+ {
+ s32 bend = track->bend * track->bendRange;
+ register s32 x asm("r1") = track->tune;
+ x += bend;
+ x *= 4;
+ x += (track->keyShift << 8);
+ x += (track->keyShiftX << 8);
+ x += track->pitX;
+
+ if (track->modT == 0)
+ x += 16 * track->modM;
+
+ track->keyM = x >> 8;
+ track->pitM = x;
+ }
+
+ track->flags &= ~(MPT_FLG_PITSET | MPT_FLG_VOLSET);
+}
+
+u32 MidiKeyToCgbFreq(u8 chanNum, u8 key, u8 fineAdjust)
+{
+ if (chanNum == 4)
+ {
+ if (key <= 20)
+ {
+ key = 0;
+ }
+ else
+ {
+ key -= 21;
+ if (key > 59)
+ key = 59;
+ }
+
+ return gNoiseTable[key];
+ }
+ else
+ {
+ s32 val1;
+ s32 val2;
+
+ if (key <= 35)
+ {
+ fineAdjust = 0;
+ key = 0;
+ }
+ else
+ {
+ key -= 36;
+ if (key > 130)
+ {
+ key = 130;
+ fineAdjust = 255;
+ }
+ }
+
+ val1 = gCgbScaleTable[key];
+ val1 = gCgbFreqTable[val1 & 0xF] >> (val1 >> 4);
+
+ val2 = gCgbScaleTable[key + 1];
+ val2 = gCgbFreqTable[val2 & 0xF] >> (val2 >> 4);
+
+ return val1 + ((fineAdjust * (val2 - val1)) >> 8) + 2048;
+ }
+}
+
+void CgbOscOff(u8 chanNum)
+{
+ switch (chanNum)
+ {
+ case 1:
+ REG_NR12 = 8;
+ REG_NR14 = 0x80;
+ break;
+ case 2:
+ REG_NR22 = 8;
+ REG_NR24 = 0x80;
+ break;
+ case 3:
+ REG_NR30 = 0;
+ break;
+ default:
+ REG_NR42 = 8;
+ REG_NR44 = 0x80;
+ }
+}
+
+static inline int CgbPan(struct CgbChannel *chan)
+{
+ u32 rightVolume = chan->rightVolume;
+ u32 leftVolume = chan->leftVolume;
+
+ if ((rightVolume = (u8)rightVolume) >= (leftVolume = (u8)leftVolume))
+ {
+ if (rightVolume / 2 >= leftVolume)
+ {
+ chan->pan = 0x0F;
+ return 1;
+ }
+ }
+ else
+ {
+ if (leftVolume / 2 >= rightVolume)
+ {
+ chan->pan = 0xF0;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+#ifndef NONMATCHING
+NAKED
+#endif
+void CgbModVol(struct CgbChannel *chan)
+{
+#ifdef NONMATCHING
+ struct SoundInfo *soundInfo = SOUND_INFO_PTR;
+
+ if ((soundInfo->mode & 1) || !CgbPan(chan))
+ {
+ chan->pan = 0xFF;
+ chan->eg = (u32)(chan->rightVolume + chan->leftVolume) >> 4;
+ }
+ else
+ {
+ // Force chan->rightVolume and chan->leftVolume to be read from memory again,
+ // even though there is no reason to do so.
+ // The command line option "-fno-gcse" achieves the same result as this.
+ asm("" : : : "memory");
+
+ chan->eg = (u32)(chan->rightVolume + chan->leftVolume) >> 4;
+ if (chan->eg > 15)
+ chan->eg = 15;
+ }
+
+ chan->sg = (chan->eg * chan->su + 15) >> 4;
+ chan->pan &= chan->panMask;
+#else
+ asm_unified("\tpush {r4,lr}\n"
+ "\tadds r1, r0, 0\n"
+ "\tldrb r0, [r1, 0x2]\n"
+ "\tlsls r2, r0, 24\n"
+ "\tlsrs r4, r2, 24\n"
+ "\tldrb r3, [r1, 0x3]\n"
+ "\tlsls r0, r3, 24\n"
+ "\tlsrs r3, r0, 24\n"
+ "\tcmp r4, r3\n"
+ "\tbcc _080AFA94\n"
+ "\tlsrs r0, r2, 25\n"
+ "\tcmp r0, r3\n"
+ "\tbcc _080AFAA0\n"
+ "\tmovs r0, 0xF\n"
+ "\tstrb r0, [r1, 0x1B]\n"
+ "\tb _080AFAAE\n"
+ "_080AFA94:\n"
+ "\tlsrs r0, 25\n"
+ "\tcmp r0, r4\n"
+ "\tbcc _080AFAA0\n"
+ "\tmovs r0, 0xF0\n"
+ "\tstrb r0, [r1, 0x1B]\n"
+ "\tb _080AFAAE\n"
+ "_080AFAA0:\n"
+ "\tmovs r0, 0xFF\n"
+ "\tstrb r0, [r1, 0x1B]\n"
+ "\tldrb r2, [r1, 0x3]\n"
+ "\tldrb r3, [r1, 0x2]\n"
+ "\tadds r0, r2, r3\n"
+ "\tlsrs r0, 4\n"
+ "\tb _080AFABE\n"
+ "_080AFAAE:\n"
+ "\tldrb r2, [r1, 0x3]\n"
+ "\tldrb r3, [r1, 0x2]\n"
+ "\tadds r0, r2, r3\n"
+ "\tlsrs r0, 4\n"
+ "\tstrb r0, [r1, 0xA]\n"
+ "\tcmp r0, 0xF\n"
+ "\tbls _080AFAC0\n"
+ "\tmovs r0, 0xF\n"
+ "_080AFABE:\n"
+ "\tstrb r0, [r1, 0xA]\n"
+ "_080AFAC0:\n"
+ "\tldrb r2, [r1, 0x6]\n"
+ "\tldrb r3, [r1, 0xA]\n"
+ "\tadds r0, r2, 0\n"
+ "\tmuls r0, r3\n"
+ "\tadds r0, 0xF\n"
+ "\tasrs r0, 4\n"
+ "\tstrb r0, [r1, 0x19]\n"
+ "\tldrb r0, [r1, 0x1C]\n"
+ "\tldrb r2, [r1, 0x1B]\n"
+ "\tands r0, r2\n"
+ "\tstrb r0, [r1, 0x1B]\n"
+ "\tpop {r4}\n"
+ "\tpop {r0}\n"
+ "\tbx r0\n");
+#endif
+} \ No newline at end of file
diff --git a/src/m4a_4.c b/src/m4a_4.c
new file mode 100644
index 0000000..595ea5a
--- /dev/null
+++ b/src/m4a_4.c
@@ -0,0 +1,384 @@
+#include "gba/m4a_internal.h"
+
+void m4aMPlayTempoControl(struct MusicPlayerInfo *mplayInfo, u16 tempo)
+{
+ if (mplayInfo->ident == ID_NUMBER)
+ {
+ mplayInfo->ident++;
+ mplayInfo->tempoU = tempo;
+ mplayInfo->tempoI = (mplayInfo->tempoD * mplayInfo->tempoU) >> 8;
+ mplayInfo->ident = ID_NUMBER;
+ }
+}
+
+void m4aMPlayVolumeControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u16 volume)
+{
+ s32 i;
+ u32 bit;
+ struct MusicPlayerTrack *track;
+
+ if (mplayInfo->ident != ID_NUMBER)
+ return;
+
+ mplayInfo->ident++;
+
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+ bit = 1;
+
+ while (i > 0)
+ {
+ if (trackBits & bit)
+ {
+ if (track->flags & MPT_FLG_EXIST)
+ {
+ track->volX = volume / 4;
+ track->flags |= MPT_FLG_VOLCHG;
+ }
+ }
+
+ i--;
+ track++;
+ bit <<= 1;
+ }
+
+ mplayInfo->ident = ID_NUMBER;
+}
+
+void m4aMPlayPitchControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s16 pitch)
+{
+ s32 i;
+ u32 bit;
+ struct MusicPlayerTrack *track;
+
+ if (mplayInfo->ident != ID_NUMBER)
+ return;
+
+ mplayInfo->ident++;
+
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+ bit = 1;
+
+ while (i > 0)
+ {
+ if (trackBits & bit)
+ {
+ if (track->flags & MPT_FLG_EXIST)
+ {
+ track->keyShiftX = pitch >> 8;
+ track->pitX = pitch;
+ track->flags |= MPT_FLG_PITCHG;
+ }
+ }
+
+ i--;
+ track++;
+ bit <<= 1;
+ }
+
+ mplayInfo->ident = ID_NUMBER;
+}
+
+void m4aMPlayPanpotControl(struct MusicPlayerInfo *mplayInfo, u16 trackBits, s8 pan)
+{
+ s32 i;
+ u32 bit;
+ struct MusicPlayerTrack *track;
+
+ if (mplayInfo->ident != ID_NUMBER)
+ return;
+
+ mplayInfo->ident++;
+
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+ bit = 1;
+
+ while (i > 0)
+ {
+ if (trackBits & bit)
+ {
+ if (track->flags & MPT_FLG_EXIST)
+ {
+ track->panX = pan;
+ track->flags |= MPT_FLG_VOLCHG;
+ }
+ }
+
+ i--;
+ track++;
+ bit <<= 1;
+ }
+
+ mplayInfo->ident = ID_NUMBER;
+}
+
+void ClearModM(struct MusicPlayerTrack *track)
+{
+ track->lfoSpeedC = 0;
+ track->modM = 0;
+
+ if (track->modT == 0)
+ track->flags |= MPT_FLG_PITCHG;
+ else
+ track->flags |= MPT_FLG_VOLCHG;
+}
+
+void m4aMPlayModDepthSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 modDepth)
+{
+ s32 i;
+ u32 bit;
+ struct MusicPlayerTrack *track;
+
+ if (mplayInfo->ident != ID_NUMBER)
+ return;
+
+ mplayInfo->ident++;
+
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+ bit = 1;
+
+ while (i > 0)
+ {
+ if (trackBits & bit)
+ {
+ if (track->flags & MPT_FLG_EXIST)
+ {
+ track->mod = modDepth;
+
+ if (!track->mod)
+ ClearModM(track);
+ }
+ }
+
+ i--;
+ track++;
+ bit <<= 1;
+ }
+
+ mplayInfo->ident = ID_NUMBER;
+}
+
+void m4aMPlayLFOSpeedSet(struct MusicPlayerInfo *mplayInfo, u16 trackBits, u8 lfoSpeed)
+{
+ s32 i;
+ u32 bit;
+ struct MusicPlayerTrack *track;
+
+ if (mplayInfo->ident != ID_NUMBER)
+ return;
+
+ mplayInfo->ident++;
+
+ i = mplayInfo->trackCount;
+ track = mplayInfo->tracks;
+ bit = 1;
+
+ while (i > 0)
+ {
+ if (trackBits & bit)
+ {
+ if (track->flags & MPT_FLG_EXIST)
+ {
+ track->lfoSpeed = lfoSpeed;
+
+ if (!track->lfoSpeed)
+ ClearModM(track);
+ }
+ }
+
+ i--;
+ track++;
+ bit <<= 1;
+ }
+
+ mplayInfo->ident = ID_NUMBER;
+}
+
+#define MEMACC_COND_JUMP(cond) \
+if (cond) \
+ goto cond_true; \
+else \
+ goto cond_false; \
+
+void ply_memacc(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ u32 op;
+ u8 *addr;
+ u8 data;
+
+ op = *track->cmdPtr;
+ track->cmdPtr++;
+
+ addr = mplayInfo->memAccArea + *track->cmdPtr;
+ track->cmdPtr++;
+
+ data = *track->cmdPtr;
+ track->cmdPtr++;
+
+ switch (op)
+ {
+ case 0:
+ *addr = data;
+ return;
+ case 1:
+ *addr += data;
+ return;
+ case 2:
+ *addr -= data;
+ return;
+ case 3:
+ *addr = mplayInfo->memAccArea[data];
+ return;
+ case 4:
+ *addr += mplayInfo->memAccArea[data];
+ return;
+ case 5:
+ *addr -= mplayInfo->memAccArea[data];
+ return;
+ case 6:
+ MEMACC_COND_JUMP(*addr == data)
+ return;
+ case 7:
+ MEMACC_COND_JUMP(*addr != data)
+ return;
+ case 8:
+ MEMACC_COND_JUMP(*addr > data)
+ return;
+ case 9:
+ MEMACC_COND_JUMP(*addr >= data)
+ return;
+ case 10:
+ MEMACC_COND_JUMP(*addr <= data)
+ return;
+ case 11:
+ MEMACC_COND_JUMP(*addr < data)
+ return;
+ case 12:
+ MEMACC_COND_JUMP(*addr == mplayInfo->memAccArea[data])
+ return;
+ case 13:
+ MEMACC_COND_JUMP(*addr != mplayInfo->memAccArea[data])
+ return;
+ case 14:
+ MEMACC_COND_JUMP(*addr > mplayInfo->memAccArea[data])
+ return;
+ case 15:
+ MEMACC_COND_JUMP(*addr >= mplayInfo->memAccArea[data])
+ return;
+ case 16:
+ MEMACC_COND_JUMP(*addr <= mplayInfo->memAccArea[data])
+ return;
+ case 17:
+ MEMACC_COND_JUMP(*addr < mplayInfo->memAccArea[data])
+ return;
+ default:
+ return;
+ }
+
+cond_true:
+ {
+ void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[1]);
+ func(mplayInfo, track);
+ return;
+ }
+
+cond_false:
+ track->cmdPtr += 4;
+}
+
+void ply_xcmd(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ u32 n = *track->cmdPtr;
+ track->cmdPtr++;
+
+ gXcmdTable[n](mplayInfo, track);
+}
+
+void ply_xxx(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ void (*func)(struct MusicPlayerInfo *, struct MusicPlayerTrack *) = *(&gMPlayJumpTable[0]);
+ func(mplayInfo, track);
+}
+
+#define READ_XCMD_BYTE(var, n) \
+{ \
+ u32 byte = track->cmdPtr[(n)]; \
+ byte <<= n * 8; \
+ (var) &= ~(0xFF << (n * 8)); \
+ (var) |= byte; \
+}
+
+void ply_xwave(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ u32 wav;
+
+ READ_XCMD_BYTE(wav, 0) // UB: uninitialized variable
+ READ_XCMD_BYTE(wav, 1)
+ READ_XCMD_BYTE(wav, 2)
+ READ_XCMD_BYTE(wav, 3)
+
+ track->tone.wav = (struct WaveData *)wav;
+ track->cmdPtr += 4;
+}
+
+void ply_xtype(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->tone.type = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xatta(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->tone.attack = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xdeca(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->tone.decay = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xsust(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->tone.sustain = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xrele(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->tone.release = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xiecv(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->echoVolume = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xiecl(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->echoLength = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xleng(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->tone.length = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void ply_xswee(struct MusicPlayerInfo *mplayInfo, struct MusicPlayerTrack *track)
+{
+ track->tone.pan_sweep = *track->cmdPtr;
+ track->cmdPtr++;
+}
+
+void DummyFunc()
+{
+ ;
+}
diff --git a/src/m4a_tables.c b/src/m4a_tables.c
new file mode 100644
index 0000000..fd289a6
--- /dev/null
+++ b/src/m4a_tables.c
@@ -0,0 +1,223 @@
+#include "gba/m4a_internal.h"
+
+// Some of these functions have different signatures, so we need to make this
+// an array of void pointers or a struct. It's simpler to just make it an array
+// for now.
+void * const gMPlayJumpTableTemplate[] =
+{
+ ply_fine,
+ ply_goto,
+ ply_patt,
+ ply_pend,
+ ply_rept,
+ ply_fine,
+ ply_fine,
+ ply_fine,
+ ply_fine,
+ ply_prio,
+ ply_tempo,
+ ply_keysh,
+ ply_voice,
+ ply_vol,
+ ply_pan,
+ ply_bend,
+ ply_bendr,
+ ply_lfos,
+ ply_lfodl,
+ ply_mod,
+ ply_modt,
+ ply_fine,
+ ply_fine,
+ ply_tune,
+ ply_fine,
+ ply_fine,
+ ply_fine,
+ ply_port,
+ ply_fine,
+ ply_endtie,
+ SampleFreqSet,
+ TrackStop,
+ FadeOutBody,
+ TrkVolPitSet,
+ RealClearChain,
+ SoundMainBTM,
+};
+
+const u8 gScaleTable[] =
+{
+ 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB,
+ 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
+ 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB,
+ 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+};
+
+const u32 gFreqTable[] =
+{
+ 2147483648u,
+ 2275179671u,
+ 2410468894u,
+ 2553802834u,
+ 2705659852u,
+ 2866546760u,
+ 3037000500u,
+ 3217589947u,
+ 3408917802u,
+ 3611622603u,
+ 3826380858u,
+ 4053909305u,
+};
+
+const u16 gPcmSamplesPerVBlankTable[] =
+{
+ 96,
+ 132,
+ 176,
+ 224,
+ 264,
+ 304,
+ 352,
+ 448,
+ 528,
+ 608,
+ 672,
+ 704,
+};
+
+const u8 gCgbScaleTable[] =
+{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B,
+ 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB,
+};
+
+const s16 gCgbFreqTable[] =
+{
+ -2004,
+ -1891,
+ -1785,
+ -1685,
+ -1591,
+ -1501,
+ -1417,
+ -1337,
+ -1262,
+ -1192,
+ -1125,
+ -1062,
+};
+
+const u8 gNoiseTable[] =
+{
+ 0xD7, 0xD6, 0xD5, 0xD4,
+ 0xC7, 0xC6, 0xC5, 0xC4,
+ 0xB7, 0xB6, 0xB5, 0xB4,
+ 0xA7, 0xA6, 0xA5, 0xA4,
+ 0x97, 0x96, 0x95, 0x94,
+ 0x87, 0x86, 0x85, 0x84,
+ 0x77, 0x76, 0x75, 0x74,
+ 0x67, 0x66, 0x65, 0x64,
+ 0x57, 0x56, 0x55, 0x54,
+ 0x47, 0x46, 0x45, 0x44,
+ 0x37, 0x36, 0x35, 0x34,
+ 0x27, 0x26, 0x25, 0x24,
+ 0x17, 0x16, 0x15, 0x14,
+ 0x07, 0x06, 0x05, 0x04,
+ 0x03, 0x02, 0x01, 0x00,
+};
+
+const u8 gCgb3Vol[] =
+{
+ 0x00, 0x00,
+ 0x60, 0x60, 0x60, 0x60,
+ 0x40, 0x40, 0x40, 0x40,
+ 0x80, 0x80, 0x80, 0x80,
+ 0x20, 0x20,
+};
+
+const u8 gClockTable[] =
+{
+ 0x00,
+ 0x01,
+ 0x02,
+ 0x03,
+ 0x04,
+ 0x05,
+ 0x06,
+ 0x07,
+ 0x08,
+ 0x09,
+ 0x0A,
+ 0x0B,
+ 0x0C,
+ 0x0D,
+ 0x0E,
+ 0x0F,
+ 0x10,
+ 0x11,
+ 0x12,
+ 0x13,
+ 0x14,
+ 0x15,
+ 0x16,
+ 0x17,
+ 0x18,
+ 0x1C,
+ 0x1E,
+ 0x20,
+ 0x24,
+ 0x28,
+ 0x2A,
+ 0x2C,
+ 0x30,
+ 0x34,
+ 0x36,
+ 0x38,
+ 0x3C,
+ 0x40,
+ 0x42,
+ 0x44,
+ 0x48,
+ 0x4C,
+ 0x4E,
+ 0x50,
+ 0x54,
+ 0x58,
+ 0x5A,
+ 0x5C,
+ 0x60,
+};
+
+const XcmdFunc gXcmdTable[] =
+{
+ ply_xxx,
+ ply_xwave,
+ ply_xtype,
+ ply_xxx,
+ ply_xatta,
+ ply_xdeca,
+ ply_xsust,
+ ply_xrele,
+ ply_xiecv,
+ ply_xiecl,
+ ply_xleng,
+ ply_xswee
+};
diff --git a/src/memory.c b/src/memory.c
new file mode 100644
index 0000000..05c89a2
--- /dev/null
+++ b/src/memory.c
@@ -0,0 +1,145 @@
+#include "global.h"
+#include "memory.h"
+
+extern struct HeapFreeListElement gMainHeapFreeList[32];
+extern u8 gMainHeap[HEAP_SIZE];
+extern u32 gHeapCount;
+extern struct HeapDescriptor gMainHeapDescriptor;
+extern struct HeapDescriptor *gHeapDescriptorList[8];
+
+extern void CpuClear(u32 *dest, s32 size);
+
+void InitHeapInternal(void);
+
+void InitHeap(void)
+{
+ InitHeapInternal();
+}
+
+void MemoryClear8(u8 *dest, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 1;
+ *dest++ = 0;
+ }
+}
+
+void MemoryClear16(u16 *dest, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 2;
+ *dest++ = 0;
+ }
+}
+void MemoryClear32(u32 *dest, s32 size)
+{
+ CpuClear(dest, size);
+}
+
+void MemoryFill8(u8 *dest, u8 value, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 1;
+ *dest++ = value;
+ }
+}
+
+void MemoryFill16(u16 *dest, u16 value, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 2;
+ *dest++ = value;
+ }
+}
+
+void MemoryFill32(u32 *dest, u32 value, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 4;
+ *dest++ = value;
+ }
+}
+
+void MemoryCopy8(u8 *dest, u8 *src, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 1;
+ *dest++ = *src++;
+ }
+}
+
+void MemoryCopy16(u16 *dest, u16 *src, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 2;
+ *dest++ = *src++;
+ }
+}
+
+void MemoryCopy32(u32 *dest, u32 *src, s32 size)
+{
+ while (size > 0)
+ {
+ size -= 4;
+ *dest++ = *src++;
+ }
+}
+
+void InitHeapInternal(void)
+{
+ struct HeapSettings settings;
+
+ settings.start = gMainHeap;
+ settings.size = HEAP_SIZE;
+ gHeapCount = 0;
+ DoInitHeap(&gMainHeapDescriptor, &settings, gMainHeapFreeList, sizeof(gMainHeapFreeList) / sizeof(struct HeapFreeListElement));
+}
+
+void DoInitHeap(struct HeapDescriptor *descriptor, struct HeapSettings *settings, struct HeapFreeListElement *freeList, u32 freeListLength)
+{
+ u32 aligned_size;
+
+ aligned_size = settings->size & 0xFFFFFFFC;
+
+ gHeapDescriptorList[gHeapCount++] = descriptor;
+
+ descriptor->start = settings->start;
+ descriptor->size = aligned_size;
+ descriptor->unk0 = 2;
+ descriptor->parentHeap = NULL;
+ descriptor->freeList = freeList;
+ descriptor->freeCount = 1;
+ descriptor->freeListLength = freeListLength;
+
+ freeList->unk_atb = 0;
+ freeList->atb = 0;
+ freeList->block.start = descriptor->start;
+ freeList->block.size = aligned_size;
+ freeList->block.allocatedSize = 0;
+ freeList->grp = 0;
+}
+
+void InitSubHeap(struct HeapDescriptor *parentHeap, struct HeapMemoryBlock *block, u32 freeListMax)
+{
+ u32 freeListSize;
+ u32 aligned_size;
+ u32 alignment;
+ struct HeapFreeListElement *freeList;
+ struct HeapSettings settings;
+
+ freeListSize = freeListMax * 3;
+ alignment = ~3;
+ freeListSize *= 8;
+ aligned_size = (block->size - freeListSize) & alignment;
+ freeList = (struct HeapFreeListElement *)block->start;
+ settings.start = &((u8 *)block->start)[freeListSize];
+ settings.size = aligned_size;
+ DoInitHeap(parentHeap, &settings, freeList, freeListMax);
+}
diff --git a/src/save.c b/src/save.c
new file mode 100644
index 0000000..5d39bfe
--- /dev/null
+++ b/src/save.c
@@ -0,0 +1,64 @@
+#include "global.h"
+
+extern u32 gUnknown_203B17C;
+extern u32 gUnknown_203B180;
+extern u32 *gUnknown_203B184;
+extern u32 gUnknown_202DE28;
+
+
+u32 sub_8011C1C(void)
+{
+ return gUnknown_203B17C;
+}
+
+void sub_8011C28(u32 in)
+{
+ gUnknown_203B17C = in;
+}
+
+u32 sub_8011C34(void)
+{
+ return gUnknown_202DE28;
+}
+
+void sub_8011C40(u32 in)
+{
+ gUnknown_202DE28 = in;
+}
+
+u32 sub_8011C4C(void)
+{
+ return gUnknown_203B180;
+}
+
+void CalculateChecksum(u8 *out, u32 size)
+{
+ u32 checksum = 0;
+ s32 i = size / 4;
+ if (i > 1)
+ {
+ u32 *ptr = (u32 *)&out[4];
+ --i;
+ do
+ checksum += *ptr++;
+ while (--i);
+ }
+ *(u32 *)out = checksum;
+}
+
+bool8 ValidateChecksum(u8 *in, u32 size)
+{
+ u32 checksum = 0;
+ s32 i = size / 4;
+ if (i > 1)
+ {
+ u32 *ptr = (u32 *)&in[4];
+ --i;
+ do
+ checksum += *ptr++;
+ while (--i);
+ }
+ if (*(u32 *)in != checksum)
+ return TRUE;
+ return FALSE;
+}
diff --git a/src/save1.c b/src/save1.c
new file mode 100644
index 0000000..b7de6c6
--- /dev/null
+++ b/src/save1.c
@@ -0,0 +1,13 @@
+#include "global.h"
+
+extern void MemoryFree(void *);
+
+extern u8 *gUnknown_203B194;
+
+void sub_80129FC()
+{
+ if (gUnknown_203B194) {
+ MemoryFree(gUnknown_203B194);
+ gUnknown_203B194 = NULL;
+ }
+}
diff --git a/src/sprite.c b/src/sprite.c
new file mode 100644
index 0000000..d741fce
--- /dev/null
+++ b/src/sprite.c
@@ -0,0 +1,10 @@
+#include "global.h"
+
+void ResetSprites(bool32);
+void SetSavingIconCoords(u32);
+
+void InitSprites(void)
+{
+ ResetSprites(1);
+ SetSavingIconCoords(0);
+}
diff --git a/src/text.c b/src/text.c
new file mode 100644
index 0000000..9de996a
--- /dev/null
+++ b/src/text.c
@@ -0,0 +1,198 @@
+#include "global.h"
+#include "file_system.h"
+#include "code_800558C.h"
+#include "code_800B540.h"
+
+struct UnkTextStruct1 {
+ u8 fill00[4];
+ u16 unk04;
+ u8 fill06[2];
+ u16 unk08;
+ u8 fill04[0x3c];
+ u8 unk46;
+};
+
+struct UnkTextStruct2 {
+ u8 fill00[0x0c];
+ s16 unk0c;
+ u8 fill0e[2];
+ s16 unk10;
+ u8 fill12[0x06];
+};
+
+extern char gUnknown_3000E94[];
+
+EWRAM_DATA struct UnkTextStruct1 gUnknown_2027370[4];
+EWRAM_DATA u8 *gKanji[2];
+EWRAM_DATA u16 gUnknown_2027498;
+EWRAM_DATA u8 gUnknown_20274A5;
+EWRAM_DATA u32 gUnknown_20274AC;
+EWRAM_DATA vu32 gUnknown_20274B0;
+EWRAM_DATA u8 gUnknown_20274B4[0x3b00];
+EWRAM_DATA struct OpenedFile *gKanjiFiles[2];
+EWRAM_DATA struct UnkTextStruct2 gUnknown_202AFC0[4];
+EWRAM_DATA u32 gUnknown_202B020;
+EWRAM_DATA u32 gUnknown_202B024;
+EWRAM_DATA u32 gUnknown_202B028[2];
+EWRAM_DATA u32 gUnknown_202B030;
+EWRAM_DATA u8 gUnknown_202B034;
+EWRAM_DATA u16 gUnknown_202B038[2][32][32];
+
+u32 xxx_update_some_bg_tiles(u32 a0);
+void sub_8006438(const struct UnkTextStruct2 *a0, u8 a1, u8 a2, u32 *a3);
+void sub_8006554(void *a0, void *a1, void *a2, void *a3, u32 a4, const struct UnkTextStruct2 *a5, u8 a6, u32 a7, u32 *a8, u32 a9);
+void sub_800898C(void);
+void sub_80089AC(const struct UnkTextStruct2 *a0, void *a1);
+void sub_8009388(void);
+
+extern const struct UnkTextStruct2 gUnknown_80B857C[4];
+extern const char gUnknown_80B87B4[];
+extern const char gUnknown_80B87BC[];
+extern const struct FileArchive gUnknown_8300500;
+extern const u32 gUnknown_80B87C4[8];
+extern const u32 gUnknown_80B87E4[8];
+extern const u32 gUnknown_80B8804[4];
+
+void sub_8006218(void)
+{
+ int i;
+ int j;
+ int k;
+
+ gUnknown_20274AC = 0;
+ gKanjiFiles[0] = OpenFileAndGetFileDataPtr(gUnknown_80B87B4, &gUnknown_8300500);
+ gKanjiFiles[1] = OpenFileAndGetFileDataPtr(gUnknown_80B87BC, &gUnknown_8300500);
+ gKanji[0] = gKanjiFiles[0]->data;
+ gKanji[1] = gKanjiFiles[1]->data;
+ gUnknown_202B028[0] = 11;
+ gUnknown_202B028[1] = 12;
+ for (k = 0; k < 4; k++)
+ {
+ gUnknown_2027370[k].unk04 = 0;
+ gUnknown_2027370[k].unk08 = 0;
+ gUnknown_2027370[k].unk46 = 0;
+ }
+ gUnknown_2027498 = 0;
+ for (i = 0; i < 20; i++)
+ {
+ gUnknown_202B038[0][i][0] = 0xf279;
+ gUnknown_202B038[1][i][0] = 0xf27a;
+ for (j = 1; j < 32; j++)
+ {
+ gUnknown_202B038[0][i][j] = 0;
+ gUnknown_202B038[1][i][j] = 0xf27a;
+ }
+ }
+ gUnknown_202B034 = 1;
+ gUnknown_202B030 = 0x88888888;
+ gUnknown_203B078 = NULL;
+ gUnknown_20274A5 = 0;
+ gUnknown_202B020 = 1;
+ gUnknown_202B024 = 20;
+ xxx_update_some_bg_tiles(0);
+}
+
+u32 xxx_update_some_bg_tiles(u32 a0)
+{
+ u32 r5 = gUnknown_20274B0;
+ u32 *r4 = (u32 *)(VRAM + 0x4f40);
+ const u32 *r2;
+ gUnknown_20274B0 = a0;
+ if (a0 == 0 || a0 == 2)
+ {
+ sub_800CDA8(2);
+ r2 = gUnknown_80B87C4;
+ }
+ else
+ {
+ sub_800CDA8(1);
+ r2 = gUnknown_80B87E4;
+ }
+ gUnknown_202B030 = 0x88888888;
+ *r4++ = *r2++;
+ *r4++ = *r2++;
+ *r4++ = *r2++;
+ *r4++ = *r2++;
+ *r4++ = *r2++;
+ *r4++ = *r2++;
+ *r4++ = *r2++;
+ *r4++ = *r2++;
+ return r5;
+}
+
+u32 sub_80063B0(void)
+{
+ return gUnknown_20274B0;
+}
+
+u8 sub_80063BC(u8 a0)
+{
+ u8 retval = gUnknown_202B034;
+ gUnknown_202B034 = a0;
+ return retval;
+}
+
+void sub_80063CC(u32 a0)
+{
+ gUnknown_20274AC = a0;
+}
+
+void sub_80063D8(int a0)
+{
+ u32 retval;
+ if (a0 == 0)
+ {
+ gUnknown_20274B0;
+ retval = 0x88888888;
+ }
+ else
+ {
+ retval = (a0 & 0xf) | ((a0 & 0xf) << 4);
+ retval |= ((a0 & 0xf) << 8);
+ retval |= ((a0 & 0xf) << 12);
+ retval |= ((a0 & 0xf) << 16);
+ retval |= ((a0 & 0xf) << 20);
+ retval |= ((a0 & 0xf) << 24);
+ retval |= ((a0 & 0xf) << 28);
+ }
+ gUnknown_202B030 = retval;
+}
+
+void sub_800641C(void *a0, u8 a1, u8 a2)
+{
+ u32 r3 = 0;
+ sub_8006438(a0, a1, a2, &r3);
+}
+
+void sub_8006438(const struct UnkTextStruct2 *a0, u8 a1, u8 a2, u32 *a3)
+{
+ int i;
+ u32 r9 = 2;
+
+ if (a0 == NULL)
+ a0 = gUnknown_80B857C;
+ if (a2)
+ sub_8009388();
+ sub_800898C();
+ for (i = 0; i < 4; i++)
+ {
+ gUnknown_202AFC0[i] = a0[i];
+ if (a0[i].unk0c)
+ {
+ sub_8006554(gUnknown_2027370, (void *)VRAM, gUnknown_20274B4, gUnknown_202B038, gUnknown_80B8804[i], a0 + i, a1, r9, a3, 0);
+ sub_80089AC(a0 + i, a3);
+ r9 += a0[i].unk0c * a0[i].unk10;
+ }
+ }
+#ifdef NONMATCHING
+ gUnknown_203B078 = gUnknown_3000E94;
+ gUnknown_20274A5 = 1;
+#else
+ asm_unified("\tldr r2, =gUnknown_203B078\n"
+ "\tldr r0, =gUnknown_3000E94\n"
+ "\tldr r1, =gUnknown_20274A5\n"
+ "\tstr r0, [r2]\n"
+ "\tmovs r0, 0x1\n"
+ "\tstrb r0, [r1]");
+#endif
+}