diff --git a/include/musyx/musyx_priv.h b/include/musyx/musyx_priv.h index d2f1f6ce..815afa12 100644 --- a/include/musyx/musyx_priv.h +++ b/include/musyx/musyx_priv.h @@ -16,16 +16,34 @@ typedef struct _SynthInfo { u8 studios; } SynthInfo; +typedef struct DSPVoice { + char data1[0x18]; + u32 _18; + u32 priority; + u32 _20; + u32 flags[5]; + char data2[0x70 - 0x38]; + u16 sampleId; + u16 _72; + char data3[0x90 - 0x74]; + u32 sampleType; + char data4[0xec - 0x94]; + u8 active; + char data5[0xf0 - 0xed]; + u32 itdFlags; +} DSPVoice; + +extern DSPVoice* dspVoice; typedef s32 (*SND_COMPARE)(u16*, u8*); -void dataInit(u32, s32); /* extern */ -void dataInitStack(); /* extern */ -s32 hwInit(s32*, u8, u8, s32); /* extern */ -void s3dInit(s32); /* extern */ -void seqInit(); /* extern */ -void streamInit(); /* extern */ -void synthInit(u32, u8); /* extern */ -void vsInit(); /* extern */ +void dataInit(u32, s32); /* extern */ +void dataInitStack(); /* extern */ +s32 hwInit(u32* rate, u8 numVoices, u8 numStudios, u32 flags); /* extern */ +void s3dInit(s32); /* extern */ +void seqInit(); /* extern */ +void streamInit(); /* extern */ +void synthInit(u32, u8); /* extern */ +void vsInit(); /* extern */ void hwExit(); void dataExit(); void s3dExit(); @@ -39,10 +57,16 @@ void sndConvertTicks(u32* out, u32 seconds); u32 sndConvert2Ms(u32 time); void hwDeactivateStudio(u8); -u32 hwIsActive(s32); +bool hwIsActive(s32); extern SND_HOOKS salHooks; +extern u8 sndActive; +extern s8 synthIdleWaitActive; +extern SynthInfo synthInfo; +typedef s32 (*SND_MESSAGE_CALLBACK)(s32, u32); +typedef void (*SND_SOME_CALLBACK)(); +extern SND_MESSAGE_CALLBACK salMessageCallback; /* Math */ void salApplyMatrix(const SND_FMATRIX* a, const SND_FVECTOR* b, SND_FVECTOR* out); float salNormalizeVector(SND_FVECTOR* vec); @@ -50,6 +74,11 @@ void salCrossProduct(SND_FVECTOR* out, const SND_FVECTOR* a, const SND_FVECTOR* void salInvertMatrix(SND_FMATRIX* out, const SND_FMATRIX* in); /* hardware */ +u32 salInitAi(SND_SOME_CALLBACK, u32, u32*); +u32 salInitDsp(u32); +u32 salInitDspCtrl(u32, u32, u16); +u32 salStartAi(); + /* TODO: Figure out what `unk` is */ bool hwAddInput(u8 studio, void* unk); bool hwRemoveInput(u8 studio, void* unk); diff --git a/src/musyx/hardware.c b/src/musyx/hardware.c new file mode 100644 index 00000000..607413d3 --- /dev/null +++ b/src/musyx/hardware.c @@ -0,0 +1,90 @@ +#include "musyx/musyx_priv.h" + +u8 salFrame; +u8 salAuxFrame; +u8 salNumVoices; +u8 salMaxStudioNum; +SND_HOOKS salHooks; +u8 salTimeOffset; + +void snd_handle_irq() { + s32 i; + if (sndActive == 0) { + return; + } + + streamCorrectLoops(); + hwIRQEnterCriticalSection(); + salCtrlDsp(salAiGetDest()); + hwIRQLeaveCriticalSection(); + hwIRQEnterCriticalSection(); + salHandleAuxProcessing(); + hwIRQLeaveCriticalSection(); + hwIRQEnterCriticalSection(); + salFrame ^= 1; + salAuxFrame = (salAuxFrame + 1) % 3; +} +s32 hwInit(u32* rate, u8 numVoices, u8 numStudios, u32 flags) { + hwInitIrq(); + salFrame = 0; + salAuxFrame = 0; + salMessageCallback = NULL; + if (salInitAi(snd_handle_irq, flags, rate) == 0) { + // OSReport("Could not initialize AI.\n"); + } else { + // OSReport("salInitAi() is done.\n\n"); + if (salInitDspCtrl(numVoices, numStudios, flags & 1) == 0) { + // OSReport("Could not initialize DSP control logic.\n"); + } else { + // OSReport("salInitDspCtrl() is done.\n\n"); + if (salInitDsp(flags)) { + // OSReport("salInitDsp() is done.\n\n"); + hwEnableIrq(); + // OSReport("Starting AI DMA...\n\n"); + salStartAi(); + // OSReport("hwInit() done.\n\n"); + return 0; + } + // OSReport("Could not initialize DSP.\n"); + } + } + return -1; +} + +void hwExit() { + hwDisableIrq(); + salExitDsp(); + salExitDspCtrl(); + salExitAi(); + hwEnableIrq(); + hwExitIrq(); +} + +void hwSetTimeOffset(s8 offset) { salTimeOffset = offset; } + +u8 hwGetTimeOffset() { return salTimeOffset; } + +bool hwIsActive(s32 idx) { return dspVoice[idx].active != 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) { + u8 i; + s32 flags; + s32 tmpFlags; + flags = 0; + for (i = 0; i <= salTimeOffset; ++i) { + tmpFlags = dspVoice[vid].flags[i]; + dspVoice[vid].flags[i] = 0; + flags |= tmpFlags & 0x20; + } + + dspVoice[vid].flags[0] = flags; + dspVoice[vid].priority = priority; + dspVoice[vid]._18 = param_6; + dspVoice[vid].itdFlags = 0; + dspVoice[vid].sampleId = sampleId; +} diff --git a/src/musyx/reverb.c b/src/musyx/reverb.c new file mode 100644 index 00000000..96dc57f4 --- /dev/null +++ b/src/musyx/reverb.c @@ -0,0 +1,96 @@ +#include "math.h" +#include "musyx/musyx_priv.h" + +static void DLsetdelay(_SND_REVHI_DELAYLINE* delayline, s32 len) { + delayline->outPoint = delayline->inPoint - (len * sizeof(f32)); + while (delayline->outPoint < 0) { + delayline->outPoint += delayline->length; + } +} + +static void DLcreate(_SND_REVHI_DELAYLINE* delayline, s32 length) { + delayline->length = length * sizeof(f32); + delayline->inputs = (f32*)salMalloc(length * sizeof(f32)); + memset(delayline->inputs, 0, length * sizeof(length)); + delayline->lastOutput = 0.f; + DLsetdelay(delayline, length * sizeof(f32)); + delayline->inPoint = 0; + delayline->outPoint = 0; +} + +static void DLdelete(_SND_REVHI_DELAYLINE* delayline) { salFree(delayline->inputs); } +bool ReverbHICreate(_SND_REVHI_WORK* rev, f32 coloration, f32 time, f32 mix, f32 damping, + f32 preDelay, f32 crosstalk) { + static int lens[] = {1789, 1999, 2333, 433, 149, 47, 73, 67}; + u8 i; + u8 j; + if (coloration < 0.f || coloration > 1.f || time < 0.01f || time > 10.f || mix < 0.f || + mix > 1.f || crosstalk < 0.f || crosstalk > 1.f || damping < 0.f || damping > 1.f || + preDelay < 0.f || preDelay > 0.1f) { + return FALSE; + } + + memset(rev, 0, sizeof(_SND_REVHI_WORK)); + + for (i = 0; i < 3; ++i) { + for (j = 0; j < 3; ++j) { + DLcreate(&rev->C[i], lens[j] + 2); + DLsetdelay(&rev->C[i], lens[j]); + rev->combCoef[j + i * 3] = pow(10.f, (lens[j] * -3) / (32000.f * time)); + } + + for (j = 0; j < 2; ++j) { + DLcreate(&rev->AP[i], lens[j + 3] + 2); + DLsetdelay(&rev->AP[i], lens[j + 3]); + } + DLcreate(&rev->AP[i], lens[i + 5] + 2); + DLsetdelay(&rev->AP[i], lens[i + 5]); + rev->lpLastout[i] = 0.f; + } + + rev->allPassCoeff = coloration; + rev->level = mix; + rev->crosstalk = crosstalk; + rev->damping = damping; + if (rev->damping < 0.05f) { + rev->damping = 0.05f; + } + + rev->damping = 1.f - ((rev->damping * 0.8f) + 0.5f); + if (preDelay != 0.f) { + rev->preDelayTime = preDelay * 32000.f; + for (i = 0; i < 3; ++i) { + rev->preDelayLine[i] = (f32*)salMalloc(rev->preDelayTime * sizeof(f32)); + memset(rev->preDelayLine[i], 0, rev->preDelayTime * sizeof(f32)); + rev->preDelayPtr[i] = rev->preDelayLine[i]; + } + } else { + rev->preDelayTime = 0; + for (i = 0; i < 3; ++i) { + rev->preDelayPtr[i] = NULL; + rev->preDelayLine[i] = NULL; + } + } + + return TRUE; +} +void DoCrossTalk() {} + +void HandleReverb_0() {} + +void ReverbHICallback() {} + +void ReverbHIFree(_SND_REVHI_WORK* rv) { + u8 i; + for (i = 0; i < 9; ++i) { + DLdelete(&rv->AP[i]); + } + for (i = 0; i < 9; ++i) { + DLdelete(&rv->C[i]); + } + if (rv->preDelayTime != 0) { + for (i = 0; i < 3; ++i) { + salFree(rv->preDelayLine[i]); + } + } +} diff --git a/src/musyx/snd_init.c b/src/musyx/snd_init.c index 13ca05cc..76a67a8d 100644 --- a/src/musyx/snd_init.c +++ b/src/musyx/snd_init.c @@ -5,9 +5,7 @@ extern "C" { #endif /* TODO: Move these to a more approprate location */ -extern s8 sndActive; -extern s8 synthIdleWaitActive; -extern SynthInfo synthInfo; + s32 DoInit(u32 rate, u32 aramSize, u8 voices, u32 flags) { dataInitStack(); @@ -24,7 +22,7 @@ s32 DoInit(u32 rate, u32 aramSize, u8 voices, u32 flags) { } s32 sndInit(u8 voices, u8 music, u8 sfx, u8 studios, u32 flags, u32 aramSize) { - s32 rate; + u32 rate; s32 ret; sndActive = 0;