summaryrefslogtreecommitdiff
path: root/arm9/lib/src
diff options
context:
space:
mode:
authorMichael Panzlaff <michael.panzlaff@fau.de>2020-05-20 00:59:30 +0200
committerMichael Panzlaff <michael.panzlaff@fau.de>2020-05-29 19:24:16 +0200
commit34d432730cdae249d7b21cba2278b2cb1cb2f342 (patch)
tree3ca2a3440eac118db299131611212081a654a114 /arm9/lib/src
parent501072dd9fb699087cecb5404e0c363b63cfa9c6 (diff)
decompile SND_* files
Diffstat (limited to 'arm9/lib/src')
-rw-r--r--arm9/lib/src/SND_alarm.c39
-rw-r--r--arm9/lib/src/SND_bank.c175
-rw-r--r--arm9/lib/src/SND_command.c333
-rw-r--r--arm9/lib/src/SND_interface.c172
-rw-r--r--arm9/lib/src/SND_main.c28
-rw-r--r--arm9/lib/src/SND_util.c238
-rw-r--r--arm9/lib/src/SND_work.c115
7 files changed, 1100 insertions, 0 deletions
diff --git a/arm9/lib/src/SND_alarm.c b/arm9/lib/src/SND_alarm.c
new file mode 100644
index 00000000..b6178c8d
--- /dev/null
+++ b/arm9/lib/src/SND_alarm.c
@@ -0,0 +1,39 @@
+#include "SND_alarm.h"
+
+struct AlarmCallback {
+ SNDAlarmCallback cb;
+ void *data;
+ u8 id;
+};
+
+static struct AlarmCallback sCallbackTable[SND_ALARM_COUNT];
+
+ARM_FUNC void SND_AlarmInit(void) {
+ for (s32 i = 0; i < SND_ALARM_COUNT; i++) {
+ sCallbackTable[i].cb = NULL;
+ sCallbackTable[i].data = NULL;
+ sCallbackTable[i].id = 0;
+ }
+}
+
+ARM_FUNC void SNDi_IncAlarmId(u32 idx) {
+ struct AlarmCallback *ac = &sCallbackTable[idx];
+ ac->id++;
+}
+
+ARM_FUNC u8 SNDi_SetAlarmHandler(u32 idx, SNDAlarmCallback cb, void *data) {
+ struct AlarmCallback *ac = &sCallbackTable[idx];
+ ac->cb = cb;
+ ac->data = data;
+ ac->id++;
+ return ac->id;
+}
+
+ARM_FUNC void SNDi_CallAlarmHandler(s32 idx) {
+ struct AlarmCallback *ac = &sCallbackTable[idx & 0xFF];
+ if (((idx >> 8) & 0xFF) != ac->id)
+ return;
+ if (ac->cb == NULL)
+ return;
+ ac->cb(ac->data);
+}
diff --git a/arm9/lib/src/SND_bank.c b/arm9/lib/src/SND_bank.c
new file mode 100644
index 00000000..bc339234
--- /dev/null
+++ b/arm9/lib/src/SND_bank.c
@@ -0,0 +1,175 @@
+#include "SND_bank.h"
+#include "OS_mutex.h"
+
+void OS_LockMutex(struct OSMutex *);
+void OS_UnlockMutex(struct OSMutex *);
+void DC_StoreRange(const void *, u32);
+
+/*
+ * WaveArc linking seems to work like the following:
+ *
+ * Each SNDBankData can have up to 4 WaveArcs assigned.
+ * To avoid loading the same WaveArc by multiple banks,
+ * a linked list using WaveArcLinks is chained through all banks
+ * which use a WaveArc.
+ *
+ * That WaveArc has a head pointer, which points to the first
+ * WaveArcLink in that chain of banks.
+ */
+
+/*
+ * Set bank's wavearc link at index to specified wavearc
+ */
+ARM_FUNC void SND_AssignWaveArc(struct SNDBankData *bankData, s32 index, struct SNDWaveArc *waveArc) {
+ SNDi_LockMutex();
+ struct SNDWaveArc *selectedWaveArc = bankData->waveArcLinks[index].waveArc;
+ if (selectedWaveArc != NULL) {
+ if (waveArc == selectedWaveArc) {
+ SNDi_UnlockMutex();
+ return;
+ }
+
+ if (&bankData->waveArcLinks[index] == selectedWaveArc->waveArcLLHead) {
+ selectedWaveArc->waveArcLLHead = bankData->waveArcLinks[index].waveArcLLnext;
+ DC_StoreRange(bankData->waveArcLinks[index].waveArc, sizeof(struct SNDWaveArc));
+ } else {
+ struct SNDWaveArcLink *cur;
+ for (cur = selectedWaveArc->waveArcLLHead; cur != NULL; cur = cur->waveArcLLnext) {
+ if (&bankData->waveArcLinks[index] == cur->waveArcLLnext)
+ break;
+ }
+ cur->waveArcLLnext = bankData->waveArcLinks[index].waveArcLLnext;
+ DC_StoreRange(cur, sizeof(*cur));
+ }
+ }
+ struct SNDWaveArcLink *oldHead = waveArc->waveArcLLHead;
+ waveArc->waveArcLLHead = &bankData->waveArcLinks[index];
+ bankData->waveArcLinks[index].waveArcLLnext = oldHead;
+ bankData->waveArcLinks[index].waveArc = waveArc;
+ // BUG: Shouldn't the mutex unlock be after writing to cache?
+ SNDi_UnlockMutex();
+ DC_StoreRange(bankData, sizeof(*bankData));
+ DC_StoreRange(waveArc, sizeof(*waveArc));
+}
+
+ARM_FUNC void SND_DestroyBank(struct SNDBankData *bankData) {
+ SNDi_LockMutex();
+
+ for (s32 i = 0; i < SND_BANK_MAX_WAVEARC; i++) {
+ struct SNDWaveArcLink *curWaveArcLink = &bankData->waveArcLinks[i];
+ struct SNDWaveArc *curWaveArc = bankData->waveArcLinks[i].waveArc;
+
+ if (curWaveArc == NULL)
+ continue;
+
+ if (curWaveArcLink == curWaveArc->waveArcLLHead) {
+ curWaveArc->waveArcLLHead = bankData->waveArcLinks[i].waveArcLLnext;
+ DC_StoreRange(curWaveArc, sizeof(*curWaveArc));
+ } else {
+ struct SNDWaveArcLink *cur;
+ for (cur = curWaveArc->waveArcLLHead; cur != NULL; cur = cur->waveArcLLnext) {
+ if (&bankData->waveArcLinks[i] == cur->waveArcLLnext)
+ break;
+ }
+ cur->waveArcLLnext = bankData->waveArcLinks[i].waveArcLLnext;
+ DC_StoreRange(cur, sizeof(*cur));
+ }
+ }
+
+ SNDi_UnlockMutex();
+}
+
+ARM_FUNC void SND_DestroyWaveArc(struct SNDWaveArc *waveArc) {
+ SNDi_LockMutex();
+ struct SNDWaveArcLink *cur = waveArc->waveArcLLHead;
+
+ while (cur != NULL) {
+ struct SNDWaveArcLink *newCur = cur->waveArcLLnext;
+ cur->waveArc = NULL;
+ cur->waveArcLLnext = NULL;
+ DC_StoreRange(cur, sizeof(*cur));
+ cur = newCur;
+ }
+
+ SNDi_UnlockMutex();
+}
+
+ARM_FUNC struct SNDInstPos SND_GetFirstInstDataPos(const struct SNDBankData *bankData) {
+ struct SNDInstPos retval;
+ retval.program = 0;
+ retval.index = 0;
+ return retval;
+}
+
+ARM_FUNC static inline struct SNDDrumSet *test(const struct SNDBankData *bank, u32 off) {
+ return (struct SNDDrumSet *)((u8 *)bank + (off >> 8));
+}
+
+ARM_FUNC BOOL SND_GetNextInstData(const struct SNDBankData *bankData, struct SNDInstData *instData, struct SNDInstPos *instPos) {
+ while (instPos->program < bankData->instCount) {
+ struct SNDDrumSet *drums;
+ struct SNDKeySplit *keySplit;
+
+ u32 instOffset = bankData->instOffsets[instPos->program];
+ instData->type = SND_INST_OFFSET_TYPE(instOffset);
+
+ switch (instData->type) {
+ case SND_INST_PCM:
+ case SND_INST_PSG:
+ case SND_INST_NOISE:
+ case SND_INST_DIRECTPCM:
+ case SND_INST_DUMMY:
+ instData->param = *SND_INST_OFFSET_NORMAL(bankData, instOffset);
+ instPos->program++;
+ return TRUE;
+ case SND_INST_DRUM_TABLE:
+ drums = SND_INST_OFFSET_DRUMS(bankData, instOffset);
+ // silly programming 101: put a loop in a place that never loops
+ for (; instPos->index < drums->maxKey - drums->minKey + 1;) {
+ *instData = drums->instruments[instPos->index];
+ instPos->index++;
+ return TRUE;
+ }
+ break;
+ case SND_INST_KEY_SPLIT:
+ keySplit = SND_INST_OFFSET_KEYSPL(bankData, instOffset);
+ for (; instPos->index < SND_INST_MAX_KEYSPLIT;) {
+ if (keySplit->key[instPos->index] == 0)
+ break;
+ *instData = keySplit->instruments[instPos->index];
+ instPos->index++;
+ return TRUE;
+ }
+ break;
+ }
+
+ instPos->program++;
+ instPos->index = 0;
+ }
+ return FALSE;
+}
+
+ARM_FUNC u32 SND_GetWaveDataCount(const struct SNDWaveArc *waveArc) {
+ return waveArc->waveCount;
+}
+
+ARM_FUNC void SND_SetWaveDataAddress(struct SNDWaveArc *waveArc, s32 index, const struct SNDWaveData *waveData) {
+ SNDi_LockMutex();
+ waveArc->waveOffsets[index] = (u32)waveData;
+ DC_StoreRange(&waveArc->waveOffsets[index], sizeof(u32));
+ SNDi_UnlockMutex();
+}
+
+ARM_FUNC const struct SNDWaveData *SND_GetWaveDataAddress(const struct SNDWaveArc *waveArc, s32 index) {
+ SNDi_LockMutex();
+ u32 retval = waveArc->waveOffsets[index];
+ if (retval != 0) {
+ // < 0x2000000 aka, not a pointer to main RAM
+ if (retval < 0x2000000)
+ retval = (u32)&((u8 *)waveArc)[retval];
+ } else {
+ retval = 0;
+ }
+ SNDi_UnlockMutex();
+ return (struct SNDWaveData *)retval;
+}
diff --git a/arm9/lib/src/SND_command.c b/arm9/lib/src/SND_command.c
new file mode 100644
index 00000000..4a867ce3
--- /dev/null
+++ b/arm9/lib/src/SND_command.c
@@ -0,0 +1,333 @@
+#include "SND_command.h"
+#include "SND_work.h"
+#include "OS_system.h"
+
+#define SND_CMD_WAIT_QUEUE_COUNT 8
+
+static struct SNDCommand sCommandArray[SND_CMD_COUNT];
+static struct SNDSharedWork sSharedWork;
+static struct SNDCommand *sWaitingCommandListQueue[SND_CMD_WAIT_QUEUE_COUNT + 1]; // not sure why this is one element to large
+static struct SNDCommand *sReserveList;
+static struct SNDCommand *sReserveListEnd;
+static struct SNDCommand *sFreeListEnd;
+static s32 sWaitingCommandListQueueRead;
+static s32 sWaitingCommandListQueueWrite;
+static s32 sWaitingCommandListCount;
+static u32 sCurrentTag;
+static u32 sFinishedTag;
+static struct SNDCommand *sFreeList;
+
+// TODO remove these function declarations once they are in the headers
+extern s32 PXI_SendWordByFifo(u32, u32, u32);
+extern void PXI_SetFifoRecvCallback(u32, void (*)(s32, s32));
+extern BOOL PXI_IsCallbackReady(u32, u32);
+
+static void InitPXI(void);
+static void RequestCommandProc(void);
+static struct SNDCommand *AllocCommand(void);
+static BOOL IsCommandAvailable(void);
+
+ARM_FUNC void SND_CommandInit(void) {
+ InitPXI();
+ sFreeList = sCommandArray;
+ for (int i = 0; i < SND_CMD_COUNT - 1; i++) {
+ sCommandArray[i].llNext = &sCommandArray[i+1];
+ }
+ sCommandArray[SND_CMD_COUNT - 1].llNext = NULL;
+ sFreeListEnd = &sCommandArray[SND_CMD_COUNT - 1];
+ sReserveList = NULL;
+ sReserveListEnd = NULL;
+ sWaitingCommandListCount = 0;
+ sWaitingCommandListQueueRead = 0;
+ sWaitingCommandListQueueWrite = 0;
+ sCurrentTag = 1;
+ sFinishedTag = 0;
+ SNDi_SharedWork = &sSharedWork;
+ SNDi_InitSharedWork(SNDi_SharedWork);
+
+ struct SNDCommand *cmd = SND_AllocCommand(SND_CMD_FLAG_BLOCK);
+ if (cmd == NULL)
+ return;
+
+ cmd->id = SND_CMD_SET_SHARED_WORK;
+ cmd->arg[0] = (u32)SNDi_SharedWork;
+ SND_PushCommand(cmd);
+ SND_FlushCommand(SND_CMD_FLAG_BLOCK);
+}
+
+ARM_FUNC const struct SNDCommand *SND_RecvCommandReply(u32 flags) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+
+ if (flags & SND_CMD_FLAG_BLOCK) {
+ u32 tag = SNDi_GetFinishedCommandTag();
+ while (sFinishedTag == tag) {
+ OS_RestoreInterrupts(oldirq);
+ OS_SpinWait(100);
+ oldirq = OS_DisableInterrupts();
+ tag = SNDi_GetFinishedCommandTag();
+ }
+ } else {
+ u32 tag = SNDi_GetFinishedCommandTag();
+ if (sFinishedTag == tag) {
+ OS_RestoreInterrupts(oldirq);
+ return NULL;
+ }
+ }
+
+ struct SNDCommand *queueRead = sWaitingCommandListQueue[sWaitingCommandListQueueRead];
+
+ if (++sWaitingCommandListQueueRead > SND_CMD_WAIT_QUEUE_COUNT)
+ sWaitingCommandListQueueRead = 0;
+
+ struct SNDCommand *cur = queueRead;
+ while (cur->llNext != NULL)
+ cur = cur->llNext;
+
+ if (sFreeListEnd != NULL) {
+ sFreeListEnd->llNext = queueRead;
+ } else {
+ sFreeList = queueRead;
+ }
+
+ sFreeListEnd = cur;
+ sWaitingCommandListCount--;
+ sFinishedTag++;
+
+ OS_RestoreInterrupts(oldirq);
+ return queueRead;
+}
+
+ARM_FUNC struct SNDCommand *SND_AllocCommand(u32 flags) {
+ struct SNDCommand *cmd;
+ if (!IsCommandAvailable())
+ return NULL;
+
+ cmd = AllocCommand();
+ if (cmd != NULL)
+ return cmd;
+
+ if ((flags & SND_CMD_FLAG_BLOCK) == 0)
+ return NULL;
+
+ if (SND_CountWaitingCommand() > 0) {
+ while (SND_RecvCommandReply(SND_CMD_FLAG_NOBLOCK) != NULL) { }
+
+ cmd = AllocCommand();
+ if (cmd != NULL)
+ return cmd;
+ } else {
+ SND_FlushCommand(SND_CMD_FLAG_BLOCK);
+ }
+
+ RequestCommandProc();
+
+ do {
+ SND_RecvCommandReply(SND_CMD_FLAG_BLOCK);
+ cmd = AllocCommand();
+ } while (cmd == NULL);
+ return cmd;
+}
+
+ARM_FUNC void SND_PushCommand(struct SNDCommand *cmd) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+
+ struct SNDCommand *newend = cmd;
+ if (sReserveListEnd == NULL) {
+ sReserveList = cmd;
+ sReserveListEnd = cmd;
+ } else {
+ sReserveListEnd->llNext = cmd;
+ sReserveListEnd = cmd;
+ }
+
+ cmd->llNext = NULL;
+
+ OS_RestoreInterrupts(oldirq);
+}
+
+ARM_FUNC BOOL SND_FlushCommand(u32 flags) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+
+ if (sReserveList == NULL) {
+ OS_RestoreInterrupts(oldirq);
+ return TRUE;
+ }
+
+ if (sWaitingCommandListCount >= SND_CMD_WAIT_QUEUE_COUNT) {
+ if ((flags & SND_CMD_FLAG_BLOCK) == 0) {
+ OS_RestoreInterrupts(oldirq);
+ return FALSE;
+ }
+
+ do {
+ SND_RecvCommandReply(SND_CMD_FLAG_BLOCK);
+ } while (sWaitingCommandListCount >= SND_CMD_WAIT_QUEUE_COUNT);
+ }
+
+ DC_FlushRange(sCommandArray, sizeof(sCommandArray));
+
+ s32 result = PXI_SendWordByFifo(7, (u32)sReserveList, 0);
+ if (result < 0) {
+ if ((flags & SND_CMD_FLAG_BLOCK) == 0) {
+ OS_RestoreInterrupts(oldirq);
+ return FALSE;
+ }
+
+ result = PXI_SendWordByFifo(7, (u32)sReserveList, 0);
+ while (result < 0) {
+ OS_RestoreInterrupts(oldirq);
+ OS_SpinWait(100);
+ oldirq = OS_DisableInterrupts();
+ result = PXI_SendWordByFifo(7, (u32)sReserveList, 0);
+ }
+ }
+
+ if ((flags & SND_CMD_FLAG_IMMEDIATE) != 0) {
+ RequestCommandProc();
+ }
+
+ sWaitingCommandListQueue[sWaitingCommandListQueueWrite] = sReserveList;
+
+ if (++sWaitingCommandListQueueWrite > SND_CMD_WAIT_QUEUE_COUNT) {
+ sWaitingCommandListQueueWrite = 0;
+ }
+
+ sReserveList = NULL;
+ sReserveListEnd = NULL;
+ sWaitingCommandListCount++;
+ sCurrentTag++;
+
+ OS_RestoreInterrupts(oldirq);
+ return TRUE;
+}
+
+ARM_FUNC void SND_WaitForCommandProc(u32 tag) {
+ if (SND_IsFinishedCommandTag(tag))
+ return;
+
+ while (SND_RecvCommandReply(SND_CMD_FLAG_NOBLOCK) != NULL) { }
+
+ if (SND_IsFinishedCommandTag(tag))
+ return;
+
+ RequestCommandProc();
+
+ if (SND_IsFinishedCommandTag(tag))
+ return;
+
+ do {
+ SND_RecvCommandReply(SND_CMD_FLAG_BLOCK);
+ } while (SND_IsFinishedCommandTag(tag) == 0);
+}
+
+ARM_FUNC u32 SND_GetCurrentCommandTag(void) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+
+ u32 retval;
+ if (sReserveList == NULL)
+ retval = sFinishedTag;
+ else
+ retval = sCurrentTag;
+
+ OS_RestoreInterrupts(oldirq);
+ return retval;
+}
+
+ARM_FUNC BOOL SND_IsFinishedCommandTag(u32 tag) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+
+ BOOL result;
+ if (tag > sFinishedTag) {
+ if (tag - sFinishedTag < 0x80000000)
+ result = FALSE;
+ else
+ result = TRUE;
+ } else {
+ if (sFinishedTag - tag < 0x80000000)
+ result = TRUE;
+ else
+ result = FALSE;
+ }
+
+ OS_RestoreInterrupts(oldirq);
+ return result;
+}
+
+ARM_FUNC s32 SND_CountFreeCommand(void) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+
+ s32 count = 0;
+ for (struct SNDCommand *cmd = sFreeList; cmd != NULL; cmd = cmd->llNext)
+ count++;
+
+ OS_RestoreInterrupts(oldirq);
+ return count;
+}
+
+ARM_FUNC s32 SND_CountReservedCommand(void) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+
+ s32 count = 0;
+ for (struct SNDCommand *cmd = sReserveList; cmd != NULL; cmd = cmd->llNext)
+ count++;
+
+ OS_RestoreInterrupts(oldirq);
+ return count;
+}
+
+ARM_FUNC s32 SND_CountWaitingCommand(void) {
+ return SND_CMD_COUNT - SND_CountFreeCommand() - SND_CountReservedCommand();
+}
+
+ARM_FUNC static void PxiFifoCallback(s32 a, s32 b) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+ SNDi_CallAlarmHandler(b);
+ OS_RestoreInterrupts(oldirq);
+}
+
+ARM_FUNC static void InitPXI(void) {
+ PXI_SetFifoRecvCallback(7, PxiFifoCallback);
+
+ if (!IsCommandAvailable())
+ return;
+
+ if (PXI_IsCallbackReady(7, 1))
+ return;
+
+ do {
+ OS_SpinWait(100);
+ } while (!PXI_IsCallbackReady(7, 1));
+}
+
+ARM_FUNC static void RequestCommandProc(void) {
+ while (PXI_SendWordByFifo(7, 0, 0) < 0) { }
+}
+
+ARM_FUNC static struct SNDCommand *AllocCommand(void) {
+ OSIntrMode oldirq = OS_DisableInterrupts();
+ if (sFreeList == NULL) {
+ OS_RestoreInterrupts(oldirq);
+ return NULL;
+ }
+
+ struct SNDCommand *retval = sFreeList;
+
+ sFreeList = sFreeList->llNext;
+ if (sFreeList == NULL)
+ sFreeListEnd = NULL;
+ OS_RestoreInterrupts(oldirq);
+ return retval;
+}
+
+ARM_FUNC static BOOL IsCommandAvailable(void) {
+ if (!OS_IsRunOnEmulator())
+ return TRUE;
+
+ OSIntrMode oldirq = OS_DisableInterrupts();
+ // TODO use proper register names here
+ // is this some kind of debug or ensata register?
+ *(vu32 *)0x4FFF200 = 0x10;
+ u32 resp = *(vu32 *)0x4FFF200;
+ OS_RestoreInterrupts(oldirq);
+ return resp != 0;
+}
diff --git a/arm9/lib/src/SND_interface.c b/arm9/lib/src/SND_interface.c
new file mode 100644
index 00000000..e8369477
--- /dev/null
+++ b/arm9/lib/src/SND_interface.c
@@ -0,0 +1,172 @@
+#include "SND_interface.h"
+#include "SND_command.h"
+
+static void PushCommand_impl(s32 id, u32 par1, u32 par2, u32 par3, u32 par4);
+#define PushCmd1(id, a) PushCommand_impl(id, (u32)(a), 0, 0, 0)
+#define PushCmd2(id, a, b) PushCommand_impl(id, (u32)(a), (u32)(b), 0, 0)
+#define PushCmd3(id, a, b, c) PushCommand_impl(id, (u32)(a), (u32)(b), (u32)(c), 0)
+#define PushCmd4(id, a, b, c, d) PushCommand_impl(id, (u32)(a), (u32)(b), (u32)(c), (u32)(d))
+
+// TODO fill in "random" constants with macros
+
+// ARM_FUNC void SND_StartSeq(s32 player, const void *seqBasePtr, u32 seqOffset, struct SNDBankData *bankData) { }
+
+ARM_FUNC void SND_StopSeq(s32 player) {
+ PushCmd1(SND_CMD_STOP_SEQ, player);
+}
+
+ARM_FUNC void SND_PrepareSeq(s32 player, const void *seqBasePtr, u32 seqOffset, struct SNDBankData *bankData) {
+ PushCmd4(SND_CMD_PREPARE_SEQ, player, seqBasePtr, seqOffset, bankData);
+}
+
+ARM_FUNC void SND_StartPreparedSeq(s32 player) {
+ PushCmd1(SND_CMD_START_PREPARED_SEQ, player);
+}
+
+ARM_FUNC void SND_PauseSeq(s32 player, BOOL flag) {
+ PushCmd2(SND_CMD_PAUSE_SEQ, player, flag);
+}
+
+// ARM_FUNC void SND_SetPlayerTempoRatio(s32 player, s32 ratio) { }
+
+ARM_FUNC void SND_SetPlayerVolume(s32 player, s32 volume) {
+ SNDi_SetPlayerParam(player, 6, volume, 2);
+}
+
+ARM_FUNC void SND_SetPlayerChannelPriority(s32 player, s32 prio) {
+ SNDi_SetPlayerParam(player, 4, prio, 1);
+}
+
+// ARM_FUNC void SND_SetPlayerLocalVariable(s32 player, s32 varNo, s16 var) { }
+
+// ARM_FUNC void SND_SetPlayerGlobalVariable(s32 varNo, s16 var) { }
+
+// ARM_FUNC void SND_SetTrackVolume(s32 player, u32 trackBitMask, s32 volume) { }
+
+ARM_FUNC void SND_SetTrackPitch(s32 player, u32 trackBitMask, s32 pitch) {
+ SNDi_SetTrackParam(player, trackBitMask, 12, pitch, 2);
+}
+
+ARM_FUNC void SND_SetTrackPan(s32 player, u32 trackBitMask, s32 pan) {
+ SNDi_SetTrackParam(player, trackBitMask, 9, pan, 1);
+}
+
+ARM_FUNC void SND_SetTrackAllocatableChannel(s32 player, u32 trackBitMask, u32 chnBitMask) {
+ PushCmd3(SND_CMD_ALLOCATABLE_CHANNEL, player, trackBitMask, chnBitMask);
+}
+
+ARM_FUNC void SND_StartTimer(u32 chnBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags) {
+ PushCmd4(SND_CMD_START_TIMER, chnBitMask, capBitMask, alarmBitMask, flags);
+}
+
+ARM_FUNC void SND_StopTimer(u32 chnBitMask, u32 capBitMask, u32 alarmBitMask, u32 flags) {
+ s32 i = 0;
+ u32 tmpMask = alarmBitMask;
+
+ while (i < SND_ALARM_COUNT && tmpMask != 0) {
+ if (tmpMask & 1)
+ SNDi_IncAlarmId(i);
+ i++;
+ tmpMask >>= 1;
+ }
+
+ PushCmd4(SND_CMD_STOP_TIMER, chnBitMask, capBitMask, alarmBitMask, flags);
+}
+
+ARM_FUNC void SND_SetupCapture(s32 capture, s32 format, void *bufferPtr, u32 length, BOOL loopFlag, s32 in, s32 out) {
+ PushCmd3(SND_CMD_SETUP_CAPTURE, bufferPtr, length,
+ (capture << 31) | (format << 30) | (loopFlag << 29) | (in << 28) | (out << 27));
+}
+
+ARM_FUNC void SND_SetupAlarm(s32 alarm, u32 tick, u32 period, SNDAlarmCallback cb, void *userData) {
+ PushCmd4(SND_CMD_SETUP_ALARM, alarm, tick, period, SNDi_SetAlarmHandler(alarm, cb, userData));
+}
+
+// ARM_FUNC void SND_SetTrackMute(s32 player, u32 trackBitMask, BOOL flag) { }
+
+// ARM_FUNC void SND_StopUnlockedChannel(u32 chnBitMask, u32 flags) { }
+
+ARM_FUNC void SND_LockChannel(u32 chnBitMask, u32 flags) {
+ PushCmd2(SND_CMD_LOCK_CHANNEL, chnBitMask, flags);
+}
+
+ARM_FUNC void SND_UnlockChannel(u32 chnBitMask, u32 flags) {
+ PushCmd2(SND_CMD_UNLOCK_CHANNEL, chnBitMask, flags);
+}
+
+ARM_FUNC void SND_SetChannelTimer(u32 chnBitMask, s32 timer) {
+ PushCmd2(SND_CMD_CHANNEL_TIMER, chnBitMask, timer);
+}
+
+ARM_FUNC void SND_SetChannelVolume(u32 chnBitMask, s32 volume, s32 chnDataShift) {
+ PushCmd3(SND_CMD_CHANNEL_VOLUME, chnBitMask, volume, chnDataShift);
+}
+
+ARM_FUNC void SND_SetChannelPan(u32 chnBitMask, s32 pan) {
+ PushCmd2(SND_CMD_CHANNEL_PAN, chnBitMask, pan);
+}
+
+ARM_FUNC void SND_SetupChannelPcm(s32 chn, s32 waveFormat, const void *dataAddr, s32 loopMode, s32 loopStart, s32 dataLen, s32 volume, s32 chnDataShift, s32 timer, s32 pan) {
+ PushCmd4(SND_CMD_SETUP_CHANNEL_PCM,
+ chn | (timer << 16),
+ dataAddr,
+ (volume << 24) | (chnDataShift << 22) | dataLen,
+ (loopMode << 26) | (waveFormat << 24) | (pan << 16) | loopStart);
+}
+
+// ARM_FUNC void SND_SetupChannelPsg(s32 chn, s32 sndDuty, s32 volume, s32 chnDataShift, s32 timer, s32 pan) { }
+
+// ARM_FUNC void SND_SetupChannelNoise(s32 chn, s32 volume, s32 chnDataShift, s32 timer, s32 pan) { }
+
+ARM_FUNC void SND_InvalidateSeqData(const void *start, const void *end) {
+ PushCmd2(SND_CMD_INVALIDATE_SEQ, start, end);
+}
+
+ARM_FUNC void SND_InvalidateBankData(const void *start, const void *end) {
+ PushCmd2(SND_CMD_INVALIDATE_BANK, start, end);
+}
+
+ARM_FUNC void SND_InvalidateWaveData(const void *start, const void *end) {
+ PushCmd2(SND_CMD_INVALIDATE_WAVE, start, end);
+}
+
+// ARM_FUNC void SND_SetMasterVolume(s32 volume) { }
+
+ARM_FUNC void SND_SetOutputSelector(s32 left, s32 right, s32 channel1, s32 channel3) {
+ PushCmd4(SND_CMD_OUTPUT_SELECTOR, left, right, channel1, channel3);
+}
+
+ARM_FUNC void SND_SetMasterPan(s32 pan) {
+ PushCmd1(SND_CMD_MASTER_PAN, pan);
+}
+
+ARM_FUNC void SND_ResetMasterPan(void) {
+ PushCmd1(SND_CMD_MASTER_PAN, -1);
+}
+
+// ARM_FUNC void SND_ReadDriverInfo(struct SNDDriverInfo *info) { }
+
+ARM_FUNC void SNDi_SetPlayerParam(s32 player, u32 offset, u32 data, s32 size) {
+ PushCmd4(SND_CMD_PLAYER_PARAM, player, offset, data, size);
+}
+
+ARM_FUNC void SNDi_SetTrackParam(s32 player, u32 trackBitMask, u32 offset, u32 data, s32 size) {
+ PushCmd4(SND_CMD_TRACK_PARAM, player | (size << 24), trackBitMask, offset, data);
+}
+
+// ARM_FUNC void SNDi_SetSurroundDecay(s32 decay) { }
+
+// ARM_FUNC void SNDi_SkipSeq(s32 player, u32 tick) { }
+
+ARM_FUNC static void PushCommand_impl(s32 id, u32 par1, u32 par2, u32 par3, u32 par4) {
+ struct SNDCommand *cmd = SND_AllocCommand(SND_CMD_FLAG_BLOCK);
+ if (cmd == NULL)
+ return;
+
+ cmd->id = id;
+ cmd->arg[0] = par1;
+ cmd->arg[1] = par2;
+ cmd->arg[2] = par3;
+ cmd->arg[3] = par4;
+ SND_PushCommand(cmd);
+}
diff --git a/arm9/lib/src/SND_main.c b/arm9/lib/src/SND_main.c
new file mode 100644
index 00000000..f533b87c
--- /dev/null
+++ b/arm9/lib/src/SND_main.c
@@ -0,0 +1,28 @@
+#include "SND_main.h"
+
+#include "global.h"
+#include "OS_mutex.h"
+
+static struct OSMutex sSndMutex;
+static s32 sSndInitialized;
+
+// TODO remove these declarations once we have the functions in the headers
+void OS_UnlockMutex(struct OSMutex *);
+void OS_LockMutex(struct OSMutex *);
+
+ARM_FUNC void SND_Init(void) {
+ if (sSndInitialized)
+ return;
+ sSndInitialized = 1;
+ OS_InitMutex(&sSndMutex);
+ SND_CommandInit();
+ SND_AlarmInit();
+}
+
+ARM_FUNC void SNDi_LockMutex(void) {
+ OS_LockMutex(&sSndMutex);
+}
+
+ARM_FUNC void SNDi_UnlockMutex(void) {
+ OS_UnlockMutex(&sSndMutex);
+}
diff --git a/arm9/lib/src/SND_util.c b/arm9/lib/src/SND_util.c
new file mode 100644
index 00000000..6ff8cb14
--- /dev/null
+++ b/arm9/lib/src/SND_util.c
@@ -0,0 +1,238 @@
+#include "SND_util.h"
+
+// not used in pokediamond
+//static const u16 sPitchTable[0x600] = {
+// 0x0000, 0x003B, 0x0076, 0x00B2, 0x00ED, 0x0128, 0x0164, 0x019f,
+// 0x01DB, 0x0217, 0x0252, 0x028E, 0x02CA, 0x0305, 0x0341, 0x037D,
+// 0x03B9, 0x03F5, 0x0431, 0x046E, 0x04AA, 0x04E6, 0x0522, 0x055F,
+// 0x059B, 0x05D8, 0x0614, 0x0651, 0x068D, 0x06CA, 0x0707, 0x0743,
+// 0x0780, 0x07BD, 0x07FA, 0x0837, 0x0874, 0x08B1, 0x08EF, 0x092C,
+// 0x0969, 0x09A7, 0x09E4, 0x0A21, 0x0A5F, 0x0A9C, 0x0ADA, 0x0B18,
+// 0x0B56, 0x0B93, 0x0BD1, 0x0C0F, 0x0C4D, 0x0C8B, 0x0CC9, 0x0D07,
+// 0x0D45, 0x0D84, 0x0DC2, 0x0E00, 0x0E3F, 0x0E7D, 0x0EBC, 0x0EFA,
+// 0x0F39, 0x0F78, 0x0FB6, 0x0FF5, 0x1034, 0x1073, 0x10B2, 0x10F1,
+// 0x1130, 0x116F, 0x11AE, 0x11EE, 0x122D, 0x126C, 0x12AC, 0x12EB,
+// 0x132B, 0x136B, 0x13AA, 0x13EA, 0x142A, 0x146A, 0x14A9, 0x14E9,
+// 0x1529, 0x1569, 0x15AA, 0x15EA, 0x162A, 0x166A, 0x16AB, 0x16EB,
+// 0x172C, 0x176C, 0x17AD, 0x17ED, 0x182E, 0x186F, 0x18B0, 0x18F0,
+// 0x1931, 0x1972, 0x19B3, 0x19F5, 0x1A36, 0x1A77, 0x1AB8, 0x1AFA,
+// 0x1B3B, 0x1B7D, 0x1BBE, 0x1C00, 0x1C41, 0x1C83, 0x1CC5, 0x1D07,
+// 0x1D48, 0x1D8A, 0x1DCC, 0x1E0E, 0x1E51, 0x1E93, 0x1ED5, 0x1F17,
+// 0x1F5A, 0x1F9C, 0x1FDF, 0x2021, 0x2064, 0x20A6, 0x20E9, 0x212C,
+// 0x216F, 0x21B2, 0x21F5, 0x2238, 0x227B, 0x22BE, 0x2301, 0x2344,
+// 0x2388, 0x23CB, 0x240E, 0x2452, 0x2496, 0x24D9, 0x251D, 0x2561,
+// 0x25A4, 0x25E8, 0x262C, 0x2670, 0x26B4, 0x26F8, 0x273D, 0x2781,
+// 0x27C5, 0x280A, 0x284E, 0x2892, 0x28D7, 0x291C, 0x2960, 0x29A5,
+// 0x29EA, 0x2A2F, 0x2A74, 0x2AB9, 0x2AFE, 0x2B43, 0x2B88, 0x2BCD,
+// 0x2C13, 0x2C58, 0x2C9D, 0x2CE3, 0x2D28, 0x2D6E, 0x2DB4, 0x2DF9,
+// 0x2E3F, 0x2E85, 0x2ECB, 0x2F11, 0x2F57, 0x2F9D, 0x2FE3, 0x302A,
+// 0x3070, 0x30B6, 0x30FD, 0x3143, 0x318A, 0x31D0, 0x3217, 0x325E,
+// 0x32A5, 0x32EC, 0x3332, 0x3379, 0x33C1, 0x3408, 0x344F, 0x3496,
+// 0x34DD, 0x3525, 0x356C, 0x35B4, 0x35FB, 0x3643, 0x368B, 0x36D3,
+// 0x371A, 0x3762, 0x37AA, 0x37F2, 0x383A, 0x3883, 0x38CB, 0x3913,
+// 0x395C, 0x39A4, 0x39ED, 0x3A35, 0x3A7E, 0x3AC6, 0x3B0F, 0x3B58,
+// 0x3BA1, 0x3BEA, 0x3C33, 0x3C7C, 0x3CC5, 0x3D0E, 0x3D58, 0x3DA1,
+// 0x3DEA, 0x3E34, 0x3E7D, 0x3EC7, 0x3F11, 0x3F5A, 0x3FA4, 0x3FEE,
+// 0x4038, 0x4082, 0x40CC, 0x4116, 0x4161, 0x41AB, 0x41F5, 0x4240,
+// 0x428A, 0x42D5, 0x431F, 0x436A, 0x43B5, 0x4400, 0x444B, 0x4495,
+// 0x44E1, 0x452C, 0x4577, 0x45C2, 0x460D, 0x4659, 0x46A4, 0x46F0,
+// 0x473B, 0x4787, 0x47D3, 0x481E, 0x486A, 0x48B6, 0x4902, 0x494E,
+// 0x499A, 0x49E6, 0x4A33, 0x4A7F, 0x4ACB, 0x4B18, 0x4B64, 0x4BB1,
+// 0x4BFE, 0x4C4A, 0x4C97, 0x4CE4, 0x4D31, 0x4D7E, 0x4DCB, 0x4E18,
+// 0x4E66, 0x4EB3, 0x4F00, 0x4F4E, 0x4F9B, 0x4FE9, 0x5036, 0x5084,
+// 0x50D2, 0x5120, 0x516E, 0x51BC, 0x520A, 0x5258, 0x52A6, 0x52F4,
+// 0x5343, 0x5391, 0x53E0, 0x542E, 0x547D, 0x54CC, 0x551A, 0x5569,
+// 0x55B8, 0x5607, 0x5656, 0x56A5, 0x56F4, 0x5744, 0x5793, 0x57E2,
+// 0x5832, 0x5882, 0x58D1, 0x5921, 0x5971, 0x59C1, 0x5A10, 0x5A60,
+// 0x5AB0, 0x5B01, 0x5B51, 0x5BA1, 0x5BF1, 0x5C42, 0x5C92, 0x5CE3,
+// 0x5D34, 0x5D84, 0x5DD5, 0x5E26, 0x5E77, 0x5EC8, 0x5F19, 0x5F6A,
+// 0x5FBB, 0x600D, 0x605E, 0x60B0, 0x6101, 0x6153, 0x61A4, 0x61F6,
+// 0x6248, 0x629A, 0x62EC, 0x633E, 0x6390, 0x63E2, 0x6434, 0x6487,
+// 0x64D9, 0x652C, 0x657E, 0x65D1, 0x6624, 0x6676, 0x66C9, 0x671C,
+// 0x676F, 0x67C2, 0x6815, 0x6869, 0x68BC, 0x690F, 0x6963, 0x69B6,
+// 0x6A0A, 0x6A5E, 0x6AB1, 0x6B05, 0x6B59, 0x6BAD, 0x6C01, 0x6C55,
+// 0x6CAA, 0x6CFE, 0x6D52, 0x6DA7, 0x6DFB, 0x6E50, 0x6EA4, 0x6EF9,
+// 0x6F4E, 0x6FA3, 0x6FF8, 0x704D, 0x70A2, 0x70F7, 0x714D, 0x71A2,
+// 0x71F7, 0x724D, 0x72A2, 0x72F8, 0x734E, 0x73A4, 0x73FA, 0x7450,
+// 0x74A6, 0x74FC, 0x7552, 0x75A8, 0x75FF, 0x7655, 0x76AC, 0x7702,
+// 0x7759, 0x77B0, 0x7807, 0x785E, 0x78B4, 0x790C, 0x7963, 0x79BA,
+// 0x7A11, 0x7A69, 0x7AC0, 0x7B18, 0x7B6F, 0x7BC7, 0x7C1F, 0x7C77,
+// 0x7CCF, 0x7D27, 0x7D7F, 0x7DD7, 0x7E2F, 0x7E88, 0x7EE0, 0x7F38,
+// 0x7F91, 0x7FEA, 0x8042, 0x809B, 0x80F4, 0x814D, 0x81A6, 0x81FF,
+// 0x8259, 0x82B2, 0x830B, 0x8365, 0x83BE, 0x8418, 0x8472, 0x84CB,
+// 0x8525, 0x857F, 0x85D9, 0x8633, 0x868E, 0x86E8, 0x8742, 0x879D,
+// 0x87F7, 0x8852, 0x88AC, 0x8907, 0x8962, 0x89BD, 0x8A18, 0x8A73,
+// 0x8ACE, 0x8B2A, 0x8B85, 0x8BE0, 0x8C3C, 0x8C97, 0x8CF3, 0x8D4F,
+// 0x8DAB, 0x8E07, 0x8E63, 0x8EBF, 0x8F1B, 0x8F77, 0x8FD4, 0x9030,
+// 0x908C, 0x90E9, 0x9146, 0x91A2, 0x91FF, 0x925C, 0x92B9, 0x9316,
+// 0x9373, 0x93D1, 0x942E, 0x948C, 0x94E9, 0x9547, 0x95A4, 0x9602,
+// 0x9660, 0x96BE, 0x971C, 0x977A, 0x97D8, 0x9836, 0x9895, 0x98F3,
+// 0x9952, 0x99B0, 0x9A0F, 0x9A6E, 0x9ACD, 0x9B2C, 0x9B8B, 0x9BEA,
+// 0x9C49, 0x9CA8, 0x9D08, 0x9D67, 0x9DC7, 0x9E26, 0x9E86, 0x9EE6,
+// 0x9F46, 0x9FA6, 0xA006, 0xA066, 0xA0C6, 0xA127, 0xA187, 0xA1E8,
+// 0xA248, 0xA2A9, 0xA30A, 0xA36B, 0xA3CC, 0xA42D, 0xA48E, 0xA4EF,
+// 0xA550, 0xA5B2, 0xA613, 0xA675, 0xA6D6, 0xA738, 0xA79A, 0xA7FC,
+// 0xA85E, 0xA8C0, 0xA922, 0xA984, 0xA9E7, 0xAA49, 0xAAAC, 0xAB0E,
+// 0xAB71, 0xABD4, 0xAC37, 0xAC9A, 0xACFD, 0xAD60, 0xADC3, 0xAE27,
+// 0xAE8A, 0xAEED, 0xAF51, 0xAFB5, 0xB019, 0xB07C, 0xB0E0, 0xB145,
+// 0xB1A9, 0xB20D, 0xB271, 0xB2D6, 0xB33A, 0xB39F, 0xB403, 0xB468,
+// 0xB4CD, 0xB532, 0xB597, 0xB5FC, 0xB662, 0xB6C7, 0xB72C, 0xB792,
+// 0xB7F7, 0xB85D, 0xB8C3, 0xB929, 0xB98F, 0xB9F5, 0xBA5B, 0xBAC1,
+// 0xBB28, 0xBB8E, 0xBBF5, 0xBC5B, 0xBCC2, 0xBD29, 0xBD90, 0xBDF7,
+// 0xBE5E, 0xBEC5, 0xBF2C, 0xBF94, 0xBFFB, 0xC063, 0xC0CA, 0xC132,
+// 0xC19A, 0xC202, 0xC26A, 0xC2D2, 0xC33A, 0xC3A2, 0xC40B, 0xC473,
+// 0xC4DC, 0xC544, 0xC5AD, 0xC616, 0xC67F, 0xC6E8, 0xC751, 0xC7BB,
+// 0xC824, 0xC88D, 0xC8F7, 0xC960, 0xC9CA, 0xCA34, 0xCA9E, 0xCB08,
+// 0xCB72, 0xCBDC, 0xCC47, 0xCCB1, 0xCD1B, 0xCD86, 0xCDF1, 0xCE5B,
+// 0xCEC6, 0xCF31, 0xCF9C, 0xD008, 0xD073, 0xD0DE, 0xD14A, 0xD1B5,
+// 0xD221, 0xD28D, 0xD2F8, 0xD364, 0xD3D0, 0xD43D, 0xD4A9, 0xD515,
+// 0xD582, 0xD5EE, 0xD65B, 0xD6C7, 0xD734, 0xD7A1, 0xD80E, 0xD87B,
+// 0xD8E9, 0xD956, 0xD9C3, 0xDA31, 0xDA9E, 0xDB0C, 0xDB7A, 0xDBE8,
+// 0xDC56, 0xDCC4, 0xDD32, 0xDDA0, 0xDE0F, 0xDE7D, 0xDEEC, 0xDF5B,
+// 0xDFC9, 0xE038, 0xE0A7, 0xE116, 0xE186, 0xE1F5, 0xE264, 0xE2D4,
+// 0xE343, 0xE3B3, 0xE423, 0xE493, 0xE503, 0xE573, 0xE5E3, 0xE654,
+// 0xE6C4, 0xE735, 0xE7A5, 0xE816, 0xE887, 0xE8F8, 0xE969, 0xE9DA,
+// 0xEA4B, 0xEABC, 0xEB2E, 0xEB9F, 0xEC11, 0xEC83, 0xECF5, 0xED66,
+// 0xEDD9, 0xEE4B, 0xEEBD, 0xEF2F, 0xEFA2, 0xF014, 0xF087, 0xF0FA,
+// 0xF16D, 0xF1E0, 0xF253, 0xF2C6, 0xF339, 0xF3AD, 0xF420, 0xF494,
+// 0xF507, 0xF57B, 0xF5EF, 0xF663, 0xF6D7, 0xF74C, 0xF7C0, 0xF834,
+// 0xF8A9, 0xF91E, 0xF992, 0xFA07, 0xFA7C, 0xFAF1, 0xFB66, 0xFBDC,
+// 0xFC51, 0xFCC7, 0xFD3C, 0xFDB2, 0xFE28, 0xFE9E, 0xFF14, 0xFF8A,
+//};
+
+static const u8 sVolumeTable[724] = {
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xA, 0xB,
+ 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xB, 0xC, 0xC, 0xC, 0xC,
+ 0xC, 0xC, 0xC, 0xC, 0xD, 0xD, 0xD, 0xD, 0xD, 0xD, 0xE,
+ 0xE, 0xE, 0xE, 0xE, 0xE, 0xE, 0xF, 0xF, 0xF, 0xF, 0xF,
+ 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11,
+ 0x11, 0x11, 0x12, 0x12, 0x12, 0x12, 0x12, 0x13, 0x13,
+ 0x13, 0x13, 0x14, 0x14, 0x14, 0x14, 0x14, 0x15, 0x15,
+ 0x15, 0x15, 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17,
+ 0x18, 0x18, 0x18, 0x18, 0x19, 0x19, 0x19, 0x19, 0x1A,
+ 0x1A, 0x1A, 0x1B, 0x1B, 0x1B, 0x1C, 0x1C, 0x1C, 0x1D,
+ 0x1D, 0x1D, 0x1E, 0x1E, 0x1E, 0x1F, 0x1F, 0x1F, 0x20,
+ 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x22, 0x23, 0x23,
+ 0x24, 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27,
+ 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B,
+ 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, 0x30,
+ 0x31, 0x31, 0x32, 0x32, 0x33, 0x33, 0x34, 0x35, 0x35,
+ 0x36, 0x36, 0x37, 0x38, 0x38, 0x39, 0x3A, 0x3A, 0x3B,
+ 0x3C, 0x3C, 0x3D, 0x3E, 0x3F, 0x3F, 0x40, 0x41, 0x42,
+ 0x42, 0x43, 0x44, 0x45, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4A, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51,
+ 0x52, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5A, 0x5B, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63,
+ 0x64, 0x65, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6D, 0x6E,
+ 0x6F, 0x71, 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A,
+ 0x7B, 0x7D, 0x7E, 0x7F, 0x20, 0x21, 0x21, 0x21, 0x22,
+ 0x22, 0x23, 0x23, 0x23, 0x24, 0x24, 0x25, 0x25, 0x26,
+ 0x26, 0x26, 0x27, 0x27, 0x28, 0x28, 0x29, 0x29, 0x2A,
+ 0x2A, 0x2B, 0x2B, 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E,
+ 0x2F, 0x2F, 0x30, 0x30, 0x31, 0x31, 0x32, 0x33, 0x33,
+ 0x34, 0x34, 0x35, 0x36, 0x36, 0x37, 0x37, 0x38, 0x39,
+ 0x39, 0x3A, 0x3B, 0x3B, 0x3C, 0x3D, 0x3E, 0x3E, 0x3F,
+ 0x40, 0x40, 0x41, 0x42, 0x43, 0x43, 0x44, 0x45, 0x46,
+ 0x47, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4D,
+ 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56,
+ 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
+ 0x60, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x69, 0x6A,
+ 0x6B, 0x6C, 0x6D, 0x6F, 0x70, 0x71, 0x73, 0x74, 0x75,
+ 0x77, 0x78, 0x79, 0x7B, 0x7C, 0x7E, 0x7E, 0x40, 0x41,
+ 0x42, 0x43, 0x43, 0x44, 0x45, 0x46, 0x47, 0x47, 0x48,
+ 0x49, 0x4A, 0x4B, 0x4C, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
+ 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62,
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6B, 0x6C, 0x6D,
+ 0x6E, 0x70, 0x71, 0x72, 0x74, 0x75, 0x76, 0x78, 0x79,
+ 0x7B, 0x7C, 0x7D, 0x7E, 0x40, 0x41, 0x42, 0x42, 0x43,
+ 0x44, 0x45, 0x46, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
+ 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53,
+ 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C,
+ 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x65, 0x66,
+ 0x67, 0x68, 0x69, 0x6A, 0x6C, 0x6D, 0x6E, 0x6F, 0x71,
+ 0x72, 0x73, 0x75, 0x76, 0x77, 0x79, 0x7A, 0x7C, 0x7D,
+ 0x7E, 0x7F,
+};
+
+const s16 SNDi_DecibelTable[0x80] = {
+ -32768,-421,-361, -325, -300, -281, -265, -252,
+ -240, -230, -221, -212, -205, -198, -192, -186,
+ -180, -175, -170, -165, -161, -156, -152, -148,
+ -145, -141, -138, -134, -131, -128, -125, -122,
+ -120, -117, -114, -112, -110, -107, -105, -103,
+ -100, -98, -96, -94, -92, -90, -88, -86,
+ -85, -83, -81, -79, -78, -76, -74, -73,
+ -71, -70, -68, -67, -65, -64, -62, -61,
+ -60, -58, -57, -56, -54, -53, -52, -51,
+ -49, -48, -47, -46, -45, -43, -42, -41,
+ -40, -39, -38, -37, -36, -35, -34, -33,
+ -32, -31, -30, -29, -28, -27, -26, -25,
+ -24, -23, -23, -22, -21, -20, -19, -18,
+ -17, -17, -16, -15, -14, -13, -12, -12,
+ -11, -10, -9, -9, -8, -7, -6, -6,
+ -5, -4, -3, -3, -2, -1, -1, 0,
+};
+
+// not used in pokediamond
+//const s16 SNDi_DecibelSquareTable[0x80] = {
+// -32768,-722,-721, -651, -601, -562, -530, -503,
+// -480, -460, -442, -425, -410, -396, -383, -371,
+// -360, -349, -339, -330, -321, -313, -305, -297,
+// -289, -282, -276, -269, -263, -257, -251, -245,
+// -239, -234, -229, -224, -219, -214, -210, -205,
+// -201, -196, -192, -188, -184, -180, -176, -173,
+// -169, -165, -162, -158, -155, -152, -149, -145,
+// -142, -139, -136, -133, -130, -127, -125, -122,
+// -119, -116, -114, -111, -109, -106, -103, -101,
+// -99, -96, -94, -91, -89, -87, -85, -82,
+// -80, -78, -76, -74, -72, -70, -68, -66,
+// -64, -62, -60, -58, -56, -54, -52, -50,
+// -49, -47, -45, -43, -42, -40, -38, -36,
+// -35, -33, -31, -30, -28, -27, -25, -23,
+// -22, -20, -19, -17, -16, -14, -13, -11,
+// -10, -8, -7, -6, -4, -3, -1, 0,
+//};
+
+ARM_FUNC u16 SND_CalcChannelVolume(s32 x) {
+ // directly using s32 doesn't match
+ int decibels = (int)x;
+ if (decibels < -723)
+ decibels = -723;
+ else if (decibels > 0)
+ decibels = 0;
+
+ u32 resultLo = sVolumeTable[decibels + 723];
+ u32 resultHi;
+
+ if (decibels < -240) {
+ resultHi = 3;
+ } else {
+ if (decibels < -120) {
+ resultHi = 2;
+ } else {
+ if (decibels < -60) {
+ resultHi = 1;
+ } else {
+ resultHi = 0;
+ }
+ }
+ }
+
+ return (u16)((resultHi << 8u) | resultLo);
+}
diff --git a/arm9/lib/src/SND_work.c b/arm9/lib/src/SND_work.c
new file mode 100644
index 00000000..a0fb547d
--- /dev/null
+++ b/arm9/lib/src/SND_work.c
@@ -0,0 +1,115 @@
+#include "SND_work.h"
+#include "SND_alarm.h"
+#include "SND_main.h"
+
+struct SNDSharedWork *SNDi_SharedWork;
+
+void DC_InvalidateRange(void *mem, u32 size);
+void DC_FlushRange(void *mem, u32 size);
+
+u32 SND_GetPlayerStatus(void) {
+ DC_InvalidateRange(&SNDi_SharedWork->playerStatus, 4);
+ return SNDi_SharedWork->playerStatus;
+}
+
+u16 SND_GetChannelStatus(void) {
+ DC_InvalidateRange(&SNDi_SharedWork->channelStatus, 2);
+ return SNDi_SharedWork->channelStatus;
+}
+
+//u16 SND_GetCaptureStatus(void) {
+// DC_InvalidateRange(&SNDi_SharedWork->captureStatus, 2);
+// return SNDi_SharedWork->captureStatus;
+//}
+
+u32 SND_GetPlayerTickCounter(u32 playerId) {
+ DC_InvalidateRange(&SNDi_SharedWork->players[playerId].tickCounter, 4);
+ return SNDi_SharedWork->players[playerId].tickCounter;
+}
+
+//s16 SND_GetPlayerLocalVariable(u32 playerId, u32 var) {
+// DC_InvalidateRange(&SNDi_SharedWork->players[playerId].localVars[var], 2);
+// return SNDi_SharedWork->players[playerId].localVars[var];
+//}
+//
+//s16 SND_GetPlayerLocalVariable(u32 var) {
+// DC_InvalidateRange(&SNDi_SharedWork->globalVars[var], 2);
+// return SNDi_SharedWork->globalVars[var];
+//}
+//
+//BOOL SND_ReadChannelInfo(const SNDDriverInfo *driverInfo, s32 chnId, SNDChannelInfo *chnInfo) {
+// // T O D O, implement if it's actually used
+//}
+//
+//BOOL SND_ReadPlayerInfo(const SNDDriverInfo *driverInfo, s32 playerId, SNDPlayerInfo *playerInfo) {
+// if (playerId < 0 || playerId >= SND_PLAYER_COUNT)
+// return FALSE;
+// SNDPlayer *player = &driverInfo->work.players[playerId];
+// playerInfo->trackBitMask = 0;
+// for (s32 i = 0; i < SND_TRACK_COUNT; i++) {
+// if (player->tracks[i] != SND_INVALID_TRACK_INDEX) {
+// playerInfo->trackBitMask |= (1 << i);
+// }
+// }
+// playerInfo->flags.active = player->flags.active;
+// playerInfo->flags.paused = player->flags.paused;
+// playerInfo->tempo = player->tempo;
+// playerInfo->volume = player->volume;
+// return TRUE;
+//}
+//
+//
+//BOOL SND_ReadTrackInfo(const SNDDriverInfo *driverInfo s32 playerId, s32 trackId, SNDTrackInfo *trackInfo) {
+// if (playerId < 0 || playerId >= SND_PLAYER_COUNT)
+// return FALSE;
+// if (trackId < 0 || trackId >= SND_TRACK_COUNT)
+// return FALSE;
+// SNDPlayer *player = &driverInfo->work.players[playerId];
+// if (player->tracks[trackId] == SND_INVALID_TRACK_INDEX)
+// return FALSE;
+// SNDTrack *track = &driverInfo->work.tracks[trackId];
+// trackInfo->program = track->program;
+// trackInfo->volume = track->volume;
+// trackInfo->expression = track->expression;
+// trackInfo->pitchBend = track->pitchBend;
+// trackInfo->bendRange = track->bendRange;
+// trackInfo->pan = track->pan + 0x40; // 0x40 == MIDI center pan
+// trackInfo->transpose = track->transpose;
+// trackInfo->chnCount = 0;
+//
+// //#define LL_READ_PTR(ptr, basePtr, base) (ptr ? ((typeof(ptr))(s32)(ptr) - (s32)(basePtr) + (s32)&(base)) : NULL)
+// //for (SNDExChannel *exChn = LL_READ_PTR(track->channelLLHead, driverInfo->workPtr, driverInfo->work);
+// // exChn != NULL; exChn = LL_READ_PTR(exChn->channelLLNext, driverInfo->workPtr, driverInfo->work))
+// //{
+// // trackInfo->channel[trackInfo->chnCount] = exChn->id;
+// // trackInfo->chnCount++;
+// //}
+// //#undef LL_READ_PTR
+//
+// return TRUE;
+//}
+
+ARM_FUNC u32 SNDi_GetFinishedCommandTag(void) {
+ DC_InvalidateRange(&SNDi_SharedWork->finishedCommandTag, 4);
+ return SNDi_SharedWork->finishedCommandTag;
+}
+
+ARM_FUNC void SNDi_InitSharedWork(struct SNDSharedWork *sw) {
+ sw->playerStatus = 0;
+ sw->channelStatus = 0;
+ sw->captureStatus = 0;
+ sw->finishedCommandTag = 0;
+
+ for (s32 i = 0; i < SND_PLAYER_COUNT; i++) {
+ sw->players[i].tickCounter = 0;
+ for (s32 j = 0; j < 16; j++) {
+ sw->players[i].localVars[j] = -1;
+ }
+ }
+
+ for (s32 i = 0; i < 16; i++) {
+ sw->globalVars[i] = -1;
+ }
+
+ DC_FlushRange(sw, sizeof(*sw));
+}