diff --git a/.vscode/settings.json b/.vscode/settings.json index ed5ab366..d54e5da1 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -42,7 +42,9 @@ "stdlib.h": "c", "musyx_priv.h": "c", "gxenum.h": "c", - "trees.h": "c" + "trees.h": "c", + "musyx.h": "c", + "dsp_import.h": "c" }, "files.autoSave": "onFocusChange", "files.insertFinalNewline": true, diff --git a/configure.py b/configure.py index eea7906d..a582997d 100755 --- a/configure.py +++ b/configure.py @@ -945,7 +945,7 @@ LIBS = [ ["musyx/hardware", False], "musyx/hw_aramdma", ["musyx/dsp_import", True], - "musyx/hw_dolphin", + ["musyx/hw_dolphin", True], ["musyx/hw_memory", True], ["musyx/creverb_fx", True], "musyx/creverb", diff --git a/include/musyx/dsp_import.h b/include/musyx/dsp_import.h index 8e2df96e..f48fb7ec 100644 --- a/include/musyx/dsp_import.h +++ b/include/musyx/dsp_import.h @@ -7,8 +7,8 @@ extern "C" { #endif -char dspSlave[]; -short dspSlaveLength; +extern char dspSlave[]; +extern ushort dspSlaveLength; #ifdef __cplusplus } diff --git a/include/musyx/musyx_priv.h b/include/musyx/musyx_priv.h index 9116894d..68b5c7ea 100644 --- a/include/musyx/musyx_priv.h +++ b/include/musyx/musyx_priv.h @@ -9,7 +9,8 @@ extern "C" { typedef struct _SynthInfo { u32 freq; - u8 unk[0x20c]; + u32 _4; + u8 unk[0x208]; u8 voices; u8 music; u8 sfx; @@ -25,11 +26,47 @@ typedef struct DSPVoice { char data2[0x70 - 0x38]; u16 sampleId; u16 _72; - char data3[0x90 - 0x74]; + u32 _74; + u32 _78; + u32 _7c; + u32 _80; + u32 _84; + u32 _88; + u32 _8c; u32 sampleType; - char data4[0xec - 0x94]; - u8 active; - char data5[0xf0 - 0xed]; + u32 _94; + u32 _98; + u32 _9c; + u32 _a0; + u8 _a4; + u8 _a5; + u8 _a6; + u8 _a7; + u32 _a8; + u32 _ac; + u32 _b0; + u32 _b4; + u32 _b8; + u32 _bc; + u16 _c0; + u16 _c2; + u32 _c4; + u32 _c8; + u32 _cc; + u32 _d0; + u32 _d4; + u32 _d8; + u32 _dc; + u32 _e0; + u8 _e4; + u8 _e5; + u8 _e6; + u8 _e7; + u32 _e8; + u8 status; + u8 _ed; + u8 breakSet; + u8 _ef; u32 itdFlags; } DSPVoice; @@ -39,6 +76,8 @@ typedef s32 (*SND_COMPARE)(u16*, u8*); void dataInit(u32, s32); /* extern */ void dataInitStack(); /* extern */ s32 hwInit(u32* rate, u8 numVoices, u8 numStudios, u32 flags); /* extern */ +void hwEnableIrq(); +void hwDisableIrq(); void s3dInit(s32); /* extern */ void seqInit(); /* extern */ void streamInit(); /* extern */ @@ -79,6 +118,9 @@ u32 salInitDsp(u32); u32 salInitDspCtrl(u32, u32, u16); u32 salStartAi(); +void* salMalloc(u32 len); +void salFree(void* addr); + /* Stream */ typedef s32 (*SND_STREAM_UPDATE_CALLBACK)(void * buffer1, u32 len1, void * buffer2, u32 len2, void* user); typedef struct SND_STREAM_INFO { @@ -98,6 +140,9 @@ typedef struct SND_STREAM_INFO { /* TODO: Figure out what `unk` is */ bool hwAddInput(u8 studio, void* unk); bool hwRemoveInput(u8 studio, void* unk); + +extern u32 dspCmdList; +extern u16 dspCmdFirstSize; #ifdef __cplusplus } #endif diff --git a/src/musyx/dsp_import.c b/src/musyx/dsp_import.c index 16e153d0..25713456 100644 --- a/src/musyx/dsp_import.c +++ b/src/musyx/dsp_import.c @@ -421,7 +421,7 @@ char dspSlave[0x19E0] ATTRIBUTE_ALIGN(32) = { 0x80, 0x00, 0x02, 0x9C, 0x0C, 0xE6, 0x02, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; -short dspSlaveLength = sizeof(dspSlave); +ushort dspSlaveLength = sizeof(dspSlave); #ifdef __cplusplus } diff --git a/src/musyx/hardware.c b/src/musyx/hardware.c index 607413d3..a20600b8 100644 --- a/src/musyx/hardware.c +++ b/src/musyx/hardware.c @@ -6,24 +6,54 @@ u8 salNumVoices; u8 salMaxStudioNum; SND_HOOKS salHooks; u8 salTimeOffset; +void hwSetTimeOffset(u8 offset); void snd_handle_irq() { - s32 i; + u8 i; + u8 j; if (sndActive == 0) { return; } streamCorrectLoops(); - hwIRQEnterCriticalSection(); + hwIRQEnterCritical(); salCtrlDsp(salAiGetDest()); - hwIRQLeaveCriticalSection(); - hwIRQEnterCriticalSection(); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); salHandleAuxProcessing(); - hwIRQLeaveCriticalSection(); - hwIRQEnterCriticalSection(); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); salFrame ^= 1; salAuxFrame = (salAuxFrame + 1) % 3; + + for (i = 0; i < salNumVoices; ++i) { + for (j = 0; j < 5; ++j) { + dspVoice[i].flags[j] = 0; + } + } + + hwIRQLeaveCritical(); + + for (i = 0; i < 5; ++i) { + hwIRQEnterCritical(); + hwSetTimeOffset(i); + seqHandle(256); + synthHandle(256); + hwIRQLeaveCritical(); + } + + hwIRQEnterCritical(); + hwSetTimeOffset(0); + s3dHandle(); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); + streamHandle(); + hwIRQLeaveCritical(); + hwIRQEnterCritical(); + vsSampleUpdates(); + hwIRQLeaveCritical(); } + s32 hwInit(u32* rate, u8 numVoices, u8 numStudios, u32 flags) { hwInitIrq(); salFrame = 0; @@ -60,21 +90,26 @@ void hwExit() { hwExitIrq(); } -void hwSetTimeOffset(s8 offset) { salTimeOffset = offset; } +void hwSetTimeOffset(u8 offset) { salTimeOffset = offset; } u8 hwGetTimeOffset() { return salTimeOffset; } -bool hwIsActive(s32 idx) { return dspVoice[idx].active != 0; } +bool hwIsActive(s32 idx) { return dspVoice[idx].status != 0; } void hwSetMesgCallback(SND_MESSAGE_CALLBACK callback) { salMessageCallback = callback; } void hwSetPriority(s32 idx, s32 priority) { dspVoice[idx].priority = priority; } -void hwInitSamplePlayback(s32 vid, u16 sampleId, u32* param_3, int param_4, u32 priority, - u32 param_6, int param_7, u32 itdMode) { +void hwInitSamplePlayback(s32 vid, u16 sampleId, u32* param_3, u32 param_4, u32 priority, + u32 param_6, u32 param_7, u32 itdMode) { u8 i; + u32 j; + u32 k; s32 flags; s32 tmpFlags; + u32* tmp; + u32 tmp2; + u32 tmp3; flags = 0; for (i = 0; i <= salTimeOffset; ++i) { tmpFlags = dspVoice[vid].flags[i]; @@ -87,4 +122,46 @@ void hwInitSamplePlayback(s32 vid, u16 sampleId, u32* param_3, int param_4, u32 dspVoice[vid]._18 = param_6; dspVoice[vid].itdFlags = 0; dspVoice[vid].sampleId = sampleId; + tmp = &dspVoice[vid]._74; + for (j = 4; j > 0; --j) { + tmp[0] = param_3[0]; + tmp[1] = param_3[1]; + tmp += 2; + param_3 += 2; + } + + if (param_4 != 0) { + dspVoice[vid]._a4 = 0; + dspVoice[vid]._b8 = 0; + dspVoice[vid]._bc = 0; + dspVoice[vid]._c0 = 0x7FFF; + dspVoice[vid]._c4 = 0; + } + + dspVoice[vid]._e4 = 0xff; + dspVoice[vid]._e5 = 0xff; + dspVoice[vid]._e6 = 0xff; + dspVoice[vid]._e7 = 0xff; + + if (param_7 != 0) { + hwSetSRCType(vid, 0); + hwSetPolyPhaseFilter(vid, 1); + } + + hwSetITDMode(vid, itdMode); +} + +void hwBreak(s32 vid) { + if (dspVoice[vid].status == 1 && salTimeOffset == 0) { + dspVoice[vid].breakSet = 1; + } + + dspVoice[vid].flags[salTimeOffset] |= 0x20; +} + +void hwSetADSR(s32 vid, u32 *param_2, u8 param_3) { +} + +void hwOff(s32 vid) { + salDeactivateVoice(&dspVoice[vid]); } diff --git a/src/musyx/hw_dolphin.c b/src/musyx/hw_dolphin.c new file mode 100644 index 00000000..923e1a68 --- /dev/null +++ b/src/musyx/hw_dolphin.c @@ -0,0 +1,175 @@ +#include "musyx/musyx_priv.h" + +#include "dolphin/dsp.h" +#include "musyx/dsp_import.h" + +/* Is this actually what factor 5 did? They specify 0x2000 for the dram size, but the next TU winds + * up incorrectly aligned */ +static u8 dram_image[0x2008] ATTRIBUTE_ALIGN(32); +static DSPTaskInfo dsp_task; + +static volatile u32 oldState = 0; +static volatile u16 hwIrqLevel = 0; +static volatile u32 salDspInitIsDone = 0; +static volatile OSTick salLastTick = 0; +static volatile u32 salLogicActive = 0; +static volatile u32 salLogicIsWaiting = 0; +static volatile u32 salDspIsDone = 0; +static void* salAIBufferBase = NULL; +static u8 salAIBufferIndex = 0; +SND_SOME_CALLBACK userCallback = NULL; + +#define DMA_BUFFER_LEN 0x280 + +u32 salGetStartDelay(); + +void callUserCallback() { + if (salLogicActive) { + return; + } + salLogicActive = 1; + OSEnableInterrupts(); + userCallback(); + OSDisableInterrupts(); + salLogicActive = 0; +} + +void salCallback() { + salAIBufferIndex = (salAIBufferIndex + 1) % 4; + AIInitDMA((((u32)salAIBufferBase - 0x80000000) + (salAIBufferIndex * DMA_BUFFER_LEN)), + DMA_BUFFER_LEN); + salLastTick = OSGetTick(); + if (salDspIsDone) { + callUserCallback(); + } else { + salLogicIsWaiting = 1; + } +} + +void dspInitCallback() { + salDspIsDone = TRUE; + salDspInitIsDone = TRUE; +} + +void dspResumeCallback() { + salDspIsDone = TRUE; + if (salLogicIsWaiting) { + salLogicIsWaiting = FALSE; + if (salLogicActive == FALSE) { + salLogicActive = TRUE; + OSEnableInterrupts(); + userCallback(); + OSDisableInterrupts(); + salLogicActive = FALSE; + } + } +} + +u32 salInitAi(SND_SOME_CALLBACK callback, u32 unk, u32* outFreq) { + salAIBufferBase = salMalloc(DMA_BUFFER_LEN * 4); + if (salAIBufferBase != NULL) { + memset(salAIBufferBase, 0, DMA_BUFFER_LEN * 4); + DCFlushRange(salAIBufferBase, DMA_BUFFER_LEN * 4); + salAIBufferIndex = TRUE; + salLogicIsWaiting = FALSE; + salDspIsDone = TRUE; + salLogicActive = FALSE; + userCallback = callback; + AIRegisterDMACallback(salCallback); + AIInitDMA(OSCachedToPhysical((u32)salAIBufferBase) + (salAIBufferIndex * 0x280), 0x280); + synthInfo._4 = 0x20; + *outFreq = 32000; + return TRUE; + } + + return FALSE; +} + +u32 salStartAi() { AIStartDMA(); } + +u32 salExitAi() { + AIRegisterDMACallback(NULL); + AIStopDMA(); + salFree(salAIBufferBase); + return TRUE; +} + +void* salAiGetDest() { + return (void*)((u32)salAIBufferBase + (u8)((salAIBufferIndex + 2) % 4) * DMA_BUFFER_LEN); +} + +u32 salInitDsp() { + dsp_task.iram_mmem_addr = (u16*)dspSlave; + dsp_task.iram_length = dspSlaveLength; + dsp_task.iram_addr = 0; + dsp_task.dram_mmem_addr = (u16*)dram_image; + dsp_task.dram_length = 0x2000; + dsp_task.dram_addr = 0; + dsp_task.dsp_init_vector = 0x10; + dsp_task.dsp_resume_vector = 0x30; + dsp_task.init_cb = dspInitCallback; + dsp_task.res_cb = dspResumeCallback; + dsp_task.done_cb = NULL; + dsp_task.req_cb = NULL; + dsp_task.priority = 0; + DSPInit(); + DSPAddTask(&dsp_task); + salDspInitIsDone = FALSE; + hwEnableIrq(); + while (!salDspInitIsDone) + ; + hwDisableIrq(); + return TRUE; +} + +u32 salExitDsp() { + DSPHalt(); + while (DSPGetDMAStatus()) + ; + DSPReset(); + + return TRUE; +} + +void salStartDsp(u32 cmdList) { + salDspIsDone = FALSE; + PPCSync(); + // "Failed assertion ((u32)cmdList & 0x1F)==0" + DSPSendMailToDSP(dspCmdFirstSize | 0xbabe0000); + + while (DSPCheckMailToDSP()) + ; + DSPSendMailToDSP(cmdList); + while (DSPCheckMailToDSP()) + ; +} + +void salCtrlDsp(u32 unk) { + salBuildCommandList(unk, salGetStartDelay()); + salStartDsp(dspCmdList); +} + +u32 salGetStartDelay() { return OSTicksToMicroseconds(OSGetTick() - salLastTick); } + +void hwInitIrq() { + oldState = OSDisableInterrupts(); + hwIrqLevel = 1; +} + +void hwExitIrq() {} + +void hwEnableIrq() { + if (--hwIrqLevel == 0) { + OSRestoreInterrupts(oldState); + } +} + +void hwDisableIrq() { + if ((hwIrqLevel++) == 0) { + oldState = OSDisableInterrupts(); + } +} + +void hwIRQEnterCritical() { OSDisableInterrupts(); } + +void hwIRQLeaveCritical() { OSEnableInterrupts(); }