diff --git a/asm/musyx/hw_dspctrl.s b/asm/musyx/hw_dspctrl.s index ff31750e..010eb6a8 100644 --- a/asm/musyx/hw_dspctrl.s +++ b/asm/musyx/hw_dspctrl.s @@ -2,9 +2,6 @@ .section .bss .balign 8 -.global gs -gs: - .skip 0x600 .global dspStudio dspStudio: .skip 0x5E0 @@ -62,8 +59,7 @@ salMessageCallback: .section .data, "wa" .balign 8 -.global dspSRCCycles -dspSRCCycles: +.obj dspSRCCycles, global # ROM: 0x3F0FA8 .2byte 0x0BAE .2byte 0x0BAE @@ -74,40 +70,60 @@ dspSRCCycles: .2byte 0x0E74 .2byte 0x0E74 .2byte 0x045B - .balign 8 +.endobj dspSRCCycles .section .rodata .balign 8 -.global lbl_803D8A68 -lbl_803D8A68: +.obj dspMixerCycles, global # ROM: 0x3D5A68 - .4byte 0x05BE0B7C - .4byte 0x0B7C113A - .4byte 0x08B6116C - .4byte 0x116C1A22 - .4byte 0x09A6134C - .4byte 0x134C1CF2 - .4byte 0x0E971D2E - .4byte 0x1D2E2BC5 - .4byte 0x0B7C0D3A - .4byte 0x0B7C0D3A - .4byte 0x0B7C0D3A - .4byte 0x0B7C0D3A - .4byte 0x134C1637 - .4byte 0x134C1637 - .4byte 0x134C1637 - .4byte 0x134C1637 + .2byte 0x05BE + .2byte 0x0B7C + .2byte 0x0B7C + .2byte 0x113A + .2byte 0x08B6 + .2byte 0x116C + .2byte 0x116C + .2byte 0x1A22 + .2byte 0x09A6 + .2byte 0x134C + .2byte 0x134C + .2byte 0x1CF2 + .2byte 0x0E97 + .2byte 0x1D2E + .2byte 0x1D2E + .2byte 0x2BC5 + .2byte 0x0B7C + .2byte 0x0D3A + .2byte 0x0B7C + .2byte 0x0D3A + .2byte 0x0B7C + .2byte 0x0D3A + .2byte 0x0B7C + .2byte 0x0D3A + .2byte 0x134C + .2byte 0x1637 + .2byte 0x134C + .2byte 0x1637 + .2byte 0x134C + .2byte 0x1637 + .2byte 0x134C + .2byte 0x1637 -.global lbl_803D8AA8 -lbl_803D8AA8: +.endobj dspMixerCycles + +.obj "pbOffsets$455", global # ROM: 0x3D5AA8 - .4byte 0x000A000C - .4byte 0x0018000E - .4byte 0x0010001A - .4byte 0x00120014 - .4byte 0x00160000 - .4byte 0 + .2byte 0x000A + .2byte 0x000C + .2byte 0x0018 + .2byte 0x000E + .2byte 0x0010 + .2byte 0x001A + .2byte 0x0012 + .2byte 0x0014 + .2byte 0x0016 +.endobj "pbOffsets$455" .section .text, "ax" @@ -2433,9 +2449,9 @@ lbl_803ACE28: /* 803ACE30 003A9D90 7C 1F F2 2E */ lhzx r0, r31, r30 /* 803ACE34 003A9D94 28 00 00 00 */ cmplwi r0, 0 /* 803ACE38 003A9D98 41 82 00 64 */ beq lbl_803ACE9C -/* 803ACE3C 003A9D9C 3C A0 80 3E */ lis r5, lbl_803D8AA8@ha +/* 803ACE3C 003A9D9C 3C A0 80 3E */ lis r5, "pbOffsets$455"@ha /* 803ACE40 003A9DA0 38 7E 00 44 */ addi r3, r30, 0x44 -/* 803ACE44 003A9DA4 39 05 8A A8 */ addi r8, r5, lbl_803D8AA8@l +/* 803ACE44 003A9DA4 39 05 8A A8 */ addi r8, r5, "pbOffsets$455"@l /* 803ACE48 003A9DA8 38 A0 00 00 */ li r5, 0 /* 803ACE4C 003A9DAC 38 00 00 01 */ li r0, 1 /* 803ACE50 003A9DB0 38 E0 00 00 */ li r7, 0 @@ -2559,9 +2575,9 @@ lbl_803ACFF4: /* 803ACFF8 003A9F58 7C 83 B0 50 */ subf r4, r3, r22 /* 803ACFFC 003A9F5C 4B FD 1B 41 */ bl DCStoreRangeNoSync /* 803AD000 003A9F60 A0 13 00 0C */ lhz r0, 0xc(r19) -/* 803AD004 003A9F64 3C 60 80 3E */ lis r3, lbl_803D8A68@ha +/* 803AD004 003A9F64 3C 60 80 3E */ lis r3, dspMixerCycles@ha /* 803AD008 003A9F68 A0 93 00 A6 */ lhz r4, 0xa6(r19) -/* 803AD00C 003A9F6C 38 63 8A 68 */ addi r3, r3, lbl_803D8A68@l +/* 803AD00C 003A9F6C 38 63 8A 68 */ addi r3, r3, dspMixerCycles@l /* 803AD010 003A9F70 54 00 08 3C */ slwi r0, r0, 1 /* 803AD014 003A9F74 7C 03 02 2E */ lhzx r0, r3, r0 /* 803AD018 003A9F78 2C 04 00 02 */ cmpwi r4, 2 diff --git a/asm/musyx/s_data.s b/asm/musyx/s_data.s index 9e0ea797..02b59966 100644 --- a/asm/musyx/s_data.s +++ b/asm/musyx/s_data.s @@ -6,6 +6,13 @@ sp: .skip 0x8 +.section .bss +.balign 8 + +.global gs +gs: + .skip 0x600 + .section .text, "ax" .global vsUpdateBuffer diff --git a/configure.py b/configure.py index b0472ac6..2121276c 100755 --- a/configure.py +++ b/configure.py @@ -936,7 +936,7 @@ LIBS = [ ["musyx/synth_vsamples", False], ["musyx/synth_dbtab", True], "musyx/s_data", - "musyx/hw_dspctrl", + ["musyx/hw_dspctrl", False], ["musyx/hw_volconv", False], ["musyx/snd3d", False], ["musyx/snd_init", True], diff --git a/include/musyx/musyx_priv.h b/include/musyx/musyx_priv.h index 7865a8fa..5c04e92b 100644 --- a/include/musyx/musyx_priv.h +++ b/include/musyx/musyx_priv.h @@ -490,18 +490,18 @@ typedef struct SAL_VOLINFO { typedef struct SAL_PANINFO { // total size: 0x30 - u32 pan_i; // offset 0x0, size 0x4 - u32 pan_im; // offset 0x4, size 0x4 - u32 span_i; // offset 0x8, size 0x4 - u32 span_im; // offset 0xC, size 0x4 - u32 rpan_i; // offset 0x10, size 0x4 - u32 rpan_im; // offset 0x14, size 0x4 - float pan_f; // offset 0x18, size 0x4 - float pan_fm; // offset 0x1C, size 0x4 - float span_f; // offset 0x20, size 0x4 - float span_fm; // offset 0x24, size 0x4 - float rpan_f; // offset 0x28, size 0x4 - float rpan_fm; // offset 0x2C, size 0x4 + u32 pan_i; // offset 0x0, size 0x4 + u32 pan_im; // offset 0x4, size 0x4 + u32 span_i; // offset 0x8, size 0x4 + u32 span_im; // offset 0xC, size 0x4 + u32 rpan_i; // offset 0x10, size 0x4 + u32 rpan_im; // offset 0x14, size 0x4 + float pan_f; // offset 0x18, size 0x4 + float pan_fm; // offset 0x1C, size 0x4 + float span_f; // offset 0x20, size 0x4 + float span_fm; // offset 0x24, size 0x4 + float rpan_f; // offset 0x28, size 0x4 + float rpan_fm; // offset 0x2C, size 0x4 } SAL_PANINFO; typedef struct _SPB { @@ -613,7 +613,7 @@ extern SND_HOOKS salHooks; extern u8 sndActive; extern s8 synthIdleWaitActive; extern SynthInfo synthInfo; -typedef s32 (*SND_MESSAGE_CALLBACK)(s32, u32); +typedef s32 (*SND_MESSAGE_CALLBACK)(u32, u32); typedef void (*SND_SOME_CALLBACK)(); extern SND_MESSAGE_CALLBACK salMessageCallback; @@ -626,8 +626,11 @@ 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); +bool salInitDspCtrl(u8 numVoices, u8 numStudios, u32 defaultStudioDPL2); u32 salStartAi(); +void salInitHRTFBuffer(); +void salActivateVoice(DSPvoice* dsp_vptr, u8 studio); +void salDeactivateVoice(DSPvoice* dsp_vptr); void salActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type); void salDeactivateStudio(unsigned char studio); void salActivateVoice(DSPvoice* dsp_vptr, u8 studio); @@ -637,6 +640,9 @@ void salReconnectVoice(DSPvoice* dsp_vptr, u8 studio); void* salMalloc(u32 len); void salFree(void* addr); +#define SAL_MAX_STUDIONUM 8 +extern u8 salMaxStudioNum; +extern u8 salNumVoices; extern float dspDLSVolTab[128]; /* Stream */ @@ -666,9 +672,9 @@ bool hwRemoveInput(u8 studio, SND_STUDIO_INPUT* in_desc); void hwChangeStudio(u32 v, u8 studio); void hwDisableHRTF(); -extern bool dspHRTFOn; +extern u32 dspHRTFOn; -extern u32 dspCmdList; +extern u16* dspCmdList; extern u16 dspCmdFirstSize; extern u8 dspScale2IndexTab[1024]; @@ -680,7 +686,7 @@ void aramUploadData(void* mram, unsigned long aram, unsigned long len, unsigned void (*callback)(unsigned long), unsigned long user); void aramFreeStreamBuffer(u8 id); void* aramStoreData(void* src, unsigned long len); -void aramRemoveData(void * aram, unsigned long len); +void aramRemoveData(void* aram, unsigned long len); #ifdef __cplusplus } #endif diff --git a/src/musyx/hardware.c b/src/musyx/hardware.c index 98804764..4b377a23 100644 --- a/src/musyx/hardware.c +++ b/src/musyx/hardware.c @@ -496,7 +496,7 @@ void hwInitSampleMem(u32 baseAddr, u32 length) { aramInit(length); } void hwExitSampleMem() { aramExit(); } -u32 convert_length(u32 len, u8 type) { +static u32 convert_length(u32 len, u8 type) { switch (type) { case 0: case 1: diff --git a/src/musyx/hw_dolphin.c b/src/musyx/hw_dolphin.c index 84a63ca2..3eabebb5 100644 --- a/src/musyx/hw_dolphin.c +++ b/src/musyx/hw_dolphin.c @@ -131,7 +131,7 @@ u32 salExitDsp() { return TRUE; } -void salStartDsp(u32 cmdList) { +void salStartDsp(u16* cmdList) { salDspIsDone = FALSE; PPCSync(); ASSERT(((u32)cmdList & 0x1F)==0); @@ -139,7 +139,7 @@ void salStartDsp(u32 cmdList) { while (DSPCheckMailToDSP()) ; - DSPSendMailToDSP(cmdList); + DSPSendMailToDSP((u32)cmdList); while (DSPCheckMailToDSP()) ; } diff --git a/src/musyx/hw_dspctrl.c b/src/musyx/hw_dspctrl.c new file mode 100644 index 00000000..1028da8c --- /dev/null +++ b/src/musyx/hw_dspctrl.c @@ -0,0 +1,454 @@ +#include "musyx/assert.h" +#include "musyx/musyx_priv.h" + +u16 dspSRCCycles[3][3] = { + {2990, 2990, 1115}, + {3300, 3300, 1115}, + {3700, 3700, 1115}, +}; + +static const u16 dspMixerCycles[32] = { + 1470, 2940, 2940, 4410, 2230, 4460, 4460, 6690, 2470, 4940, 4940, 7410, 3735, 7470, 7470, 11205, + 2940, 3386, 2940, 3386, 2940, 3386, 2940, 3386, 4940, 5687, 4940, 5687, 4940, 5687, 4940, 5687, +}; + +DSPstudioinfo dspStudio[8]; +static u32 dspARAMZeroBuffer = 0; +u16* dspCmdLastLoad = NULL; +u16* dspCmdLastBase = NULL; +u16* dspCmdList = NULL; +u16 dspCmdLastSize = 0; +u16* dspCmdCurBase = NULL; +u16* dspCmdMaxPtr = NULL; +u16* dspCmdPtr = NULL; +u16 dspCmdFirstSize = 0; +u32 dspHRTFOn = FALSE; +s16* dspHrtfHistoryBuffer = NULL; +long* dspSurround = NULL; +s16* dspITDBuffer = NULL; +DSPvoice* dspVoice = NULL; +SND_MESSAGE_CALLBACK salMessageCallback = NULL; + +bool salInitDspCtrl(u8 numVoices, u8 numStudios, u32 defaultStudioDPL2) { + u32 i; // r31 + u32 j; // r27 + u32 itdPtr; // r28 + + salNumVoices = numVoices; + salMaxStudioNum = numStudios; + ASSERT(salMaxStudioNum <= SAL_MAX_STUDIONUM); + dspARAMZeroBuffer = aramGetZeroBuffer(); + dspCmdList = salMalloc(1024 * sizeof(u16)); + if (dspCmdList != NULL) { + // OSReport("Allocated dspCmdList.\n\n"); + dspSurround = salMalloc(160 * sizeof(long)); + if (dspSurround != NULL) { + // OSReport("Allocated surround buffer.\n\n"); + memset(dspSurround, 0, 160 * sizeof(long)); + DCFlushRange(dspSurround, 160 * sizeof(long)); + dspVoice = salMalloc(salNumVoices * sizeof(DSPvoice)); + if (dspVoice != NULL) { + // OSReport("Allocated HW voice array.\n\n"); + dspITDBuffer = salMalloc(salNumVoices * 64); + if (dspITDBuffer != NULL) { + // OSReport("Allocated ITD buffers for voice array.\n\n"); + DCInvalidateRange(dspITDBuffer, salNumVoices * 64); + itdPtr = (u32)dspITDBuffer; + for (i = 0; i < salNumVoices; ++i) { + // OSReport("Initializing voice %d...\n", i); + dspVoice[i].state = 0; + dspVoice[i].postBreak = 0; + dspVoice[i].startupBreak = 0; + dspVoice[i].lastUpdate.pitch = 0xff; + dspVoice[i].lastUpdate.vol = 0xff; + dspVoice[i].lastUpdate.volA = 0xff; + dspVoice[i].lastUpdate.volB = 0xff; + dspVoice[i].pb = salMalloc(sizeof(_PB)); + memset(dspVoice[i].pb, 0, sizeof(_PB)); + dspVoice[i].patchData = salMalloc(0x80); + dspVoice[i].pb->currHi = ((u32)dspVoice[i].pb >> 16); + dspVoice[i].pb->currLo = (u16)dspVoice[i].pb; + dspVoice[i].pb->update.dataHi = ((u32)dspVoice[i].patchData >> 16); + dspVoice[i].pb->update.dataLo = ((u16)dspVoice[i].patchData); + dspVoice[i].pb->itd.bufferHi = ((u32)itdPtr >> 16); + dspVoice[i].pb->itd.bufferLo = ((u16)itdPtr); + dspVoice[i].itdBuffer = (void*)itdPtr; + itdPtr += 0x40; + dspVoice[i].virtualSampleID = 0xFFFFFFFF; + DCStoreRangeNoSync(dspVoice[i].pb, sizeof(_PB)); + + for (j = 0; j < 5; ++j) { + dspVoice[i].changed[j] = 0; + } + } + + // OSReport("All voices initialized.\n\n"); + + for (i = 0; i < salMaxStudioNum; ++i) { + // OSReport("Initializing studio %d...\n", i); + dspStudio[i].state = 0; + itdPtr = (u32)salMalloc(sizeof(_SPB)); + dspStudio[i].spb = (void*)itdPtr; + if ((void*)itdPtr == NULL) { + return FALSE; + } + + itdPtr = (u32)salMalloc(0x3c00); + dspStudio[i].main[0] = (void*)itdPtr; + if ((void*)itdPtr == NULL) { + return FALSE; + } + + memset(dspStudio[i].main[0], 0, 0x3c00); + DCFlushRangeNoSync(dspStudio[i].main[0], 0x3c00); + dspStudio[i].main[1] = dspStudio[i].main[0] + 0x1e0; + dspStudio[i].auxA[0] = dspStudio[i].main[1] + 0x1e0; + dspStudio[i].auxA[1] = dspStudio[i].auxA[0] + 0x1e0; + dspStudio[i].auxA[2] = dspStudio[i].auxA[1] + 0x1e0; + dspStudio[i].auxB[0] = dspStudio[i].auxA[2] + 0x1e0; + dspStudio[i].auxB[1] = dspStudio[i].auxB[0] + 0x1e0; + dspStudio[i].auxB[2] = dspStudio[i].auxB[1] + 0x1e0; + memset(dspStudio[i].spb, 0, sizeof(_SPB)); + dspStudio[i].hostDPopSum.s = 0; + dspStudio[i].hostDPopSum.r = 0; + dspStudio[i].hostDPopSum.l = 0; + dspStudio[i].hostDPopSum.sA = 0; + dspStudio[i].hostDPopSum.rA = 0; + dspStudio[i].hostDPopSum.lA = 0; + dspStudio[i].hostDPopSum.sB = 0; + dspStudio[i].hostDPopSum.rB = 0; + dspStudio[i].hostDPopSum.lB = 0; + DCFlushRangeNoSync(dspStudio[i].spb, sizeof(_SPB)); + } + // OSReport("All studios are initialized.\n\n"); + salActivateStudio(0, 1, defaultStudioDPL2 != FALSE); + // OSReport("Default studio is active.\n\n"); + dspHrtfHistoryBuffer = salMalloc(0x100); + if (dspHrtfHistoryBuffer == NULL) { + return FALSE; + } + + salInitHRTFBuffer(); + return TRUE; + } + } + } + } + + return FALSE; +} + +void salInitHRTFBuffer() { + memset(dspHrtfHistoryBuffer, 0, 0x100); + DCFlushRangeNoSync(dspHrtfHistoryBuffer, 0x100); +} + +u32 salExitDspCtrl() { + u8 i; // r31 + salFree(dspHrtfHistoryBuffer); + + for (i = 0; i < salNumVoices; ++i) { + salFree(dspVoice[i].pb); + salFree(dspVoice[i].patchData); + } + + for (i = 0; i < salMaxStudioNum; ++i) { + salFree(dspStudio[i].spb); + salFree(dspStudio[i].main[0]); + } + + salFree(dspITDBuffer); + salFree(dspVoice); + salFree(dspSurround); + salFree(dspCmdList); + return TRUE; +} + +void salActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type) { + memset(dspStudio[studio].main[0], 0, 0x3c00); + DCFlushRangeNoSync(dspStudio[studio].main[0], 0x3c00); + memset(dspStudio[studio].spb, 0, sizeof(_SPB)); + dspStudio[studio].hostDPopSum.s = 0; + dspStudio[studio].hostDPopSum.r = 0; + dspStudio[studio].hostDPopSum.l = 0; + dspStudio[studio].hostDPopSum.sA = 0; + dspStudio[studio].hostDPopSum.rA = 0; + dspStudio[studio].hostDPopSum.lA = 0; + dspStudio[studio].hostDPopSum.sB = 0; + dspStudio[studio].hostDPopSum.rB = 0; + dspStudio[studio].hostDPopSum.lB = 0; + DCFlushRangeNoSync(dspStudio[studio].spb, sizeof(_SPB)); + memset(dspStudio[studio].auxA[0], 0, 0x780); + DCFlushRangeNoSync(dspStudio[studio].auxA[0], 0x780); + memset(dspStudio[studio].auxB[0], 0, 0x780); + DCFlushRangeNoSync(dspStudio[studio].auxB[0], 0x780); + dspStudio[studio].voiceRoot = NULL; + dspStudio[studio].alienVoiceRoot = NULL; + dspStudio[studio].state = 1; + dspStudio[studio].isMaster = isMaster; + dspStudio[studio].numInputs = 0; + dspStudio[studio].type = type; + dspStudio[studio].auxBHandler = NULL; + dspStudio[studio].auxAHandler = NULL; +} + +void salDeactivateStudio(u8 studio) { dspStudio[studio].state = 0; } + +u32 salCheckVolErrorAndResetDelta(u16* dsp_vol, u16* dsp_delta, u16* last_vol, u16 targetVol, + u16* resetFlags, u16 resetMask) { + s16 d; // r31 + s16 x; // r30 + + if (targetVol != *last_vol) { + d = (s16)targetVol - (s16)*last_vol; + if (d >= 32 && d < 160) { + d = d >> 5; + if (d < 5) { + resetFlags[d] |= resetMask; + } + + *dsp_delta = 1; + *last_vol = *last_vol + (d * 32); + return 1; + } + + if (-32 >= d && -160 < d) { + d = -d >> 5; + if (d < 5) { + resetFlags[d] |= resetMask; + } + *dsp_delta = 0xFFFF; + *last_vol -= d * 32; + return 1; + } + + if (targetVol == 0 && d > -32) { + *last_vol = 0; + *dsp_vol = 0; + } + } + + *dsp_delta = 0; + return 0; +} + +void sal_setup_dspvol(u16* dsp_delta, u16* last_vol, u16 vol) { + *dsp_delta = ((s16)vol - (s16)*last_vol) / 160; + *last_vol += (s16)*dsp_delta * 160; +} + +void sal_update_hostplayinfo(DSPvoice* dsp_vptr) { + u32 old_lo; // r30 + u32 pitch; // r31 + + if (dsp_vptr->smp_info.loopLength != 0) { + return; + } + if (dsp_vptr->pb->srcSelect != 2) { + pitch = dsp_vptr->playInfo.pitch << 5; + + } else { + pitch = 0x200000; + } + + old_lo = dsp_vptr->playInfo.posLo; + dsp_vptr->playInfo.posLo += pitch * 0x10000; + + if (old_lo > dsp_vptr->playInfo.posLo) { + dsp_vptr->playInfo.posHi += (pitch >> 16) + 1; + } else { + dsp_vptr->playInfo.posHi += (pitch >> 16); + } +} + +void AddDpop(long* sum, s16 delta) { + *sum += (int)delta; + *sum = (*sum > 0x7fffff) ? 0x7fffff : (*sum < -0x7fffff ? -0x7fffff : *sum); +} + +void DoDepopFade(long* dspStart, s16* dspDelta, long* hostSum) { + if (*hostSum <= -160) { + *dspDelta = (*hostSum <= -3200) ? 0x14 : (s16)(-*hostSum / 160); + } else if (*hostSum >= 160) { + *dspDelta = (*hostSum >= 3200) ? -0x14 : (s16)(-*hostSum / 160); + } else { + *dspDelta = 0; + } + + *dspStart = *hostSum; + *hostSum += *dspDelta * 160; +} + +void HandleDepopVoice(DSPstudioinfo* stp, DSPvoice* dsp_vptr) { + _PB* pb; // r31 + dsp_vptr->postBreak = 0; + dsp_vptr->pb->state = 0; + pb = dsp_vptr->pb; + AddDpop(&stp->hostDPopSum.l, pb->dpop.aL); + AddDpop(&stp->hostDPopSum.r, pb->dpop.aR); + + if ((pb->mixerCtrl & 0x04) != 0) { + AddDpop(&stp->hostDPopSum.s, pb->dpop.aS); + } + + if ((pb->mixerCtrl & 0x01) != 0) { + AddDpop(&stp->hostDPopSum.lA, pb->dpop.aAuxAL); + AddDpop(&stp->hostDPopSum.rA, pb->dpop.aAuxAR); + + if ((pb->mixerCtrl & 0x14) != 0) { + AddDpop(&stp->hostDPopSum.sA, pb->dpop.aAuxAS); + } + } + + if ((pb->mixerCtrl & 0x12) != 0) { + AddDpop(&stp->hostDPopSum.lB, pb->dpop.aAuxBL); + AddDpop(&stp->hostDPopSum.rB, pb->dpop.aAuxBR); + + if ((pb->mixerCtrl & 0x4) != 0) { + AddDpop(&stp->hostDPopSum.sB, pb->dpop.aAuxBS); + } + } +} + +void SortVoices(DSPvoice** voices, long l, long r) { + long i; // r28 + long last; // r29 + DSPvoice* tmp; // r27 + + if (l >= r) { + return; + } + + tmp = voices[l]; + last = (l + r) / 2; + voices[l] = voices[last]; + voices[last] = tmp; + i = l + 1; + last = l; + for (; i <= r; ++i) { + if (voices[i]->prio < voices[l]->prio) { + last += 1; + tmp = voices[last]; + voices[last] = voices[i]; + voices[i] = tmp; + } + } + + tmp = voices[l]; + voices[l] = voices[last]; + voices[last] = tmp; + SortVoices(voices, l, last - 1); + SortVoices(voices, last + 1, r); +} + +void salBuildCommandList(signed short* dest, unsigned long nsDelay) { + static const u16 pbOffsets[9] = {10, 12, 24, 13, 16, 26, 18, 20, 22}; +} + +u32 salSynthSendMessage(DSPvoice* dsp_vptr, u32 mesg) { + return salMessageCallback == NULL ? FALSE + : salMessageCallback(mesg, dsp_vptr->mesgCallBackUserValue); +} + +void salActivateVoice(DSPvoice* dsp_vptr, u8 studio) { + DSPvoice* tmp; + if (dsp_vptr->state != 0) { + salDeactivateVoice(dsp_vptr); + dsp_vptr->changed[0] |= 0x20; + } + + dsp_vptr->postBreak = 0; + tmp = dspStudio[studio].voiceRoot; + dsp_vptr->next = tmp; + if (tmp != NULL) { + dsp_vptr->next->prev = dsp_vptr; + } + + dsp_vptr->prev = NULL; + dspStudio[studio].voiceRoot = dsp_vptr; + dsp_vptr->startupBreak = 0; + dsp_vptr->state = 1; + dsp_vptr->studio = studio; +} + +void salDeactivateVoice(DSPvoice* dsp_vptr) { + if (dsp_vptr->state == 0) { + return; + } + + if (dsp_vptr->prev != NULL) { + dsp_vptr->prev->next = dsp_vptr->next; + } else { + dspStudio[dsp_vptr->studio].voiceRoot = dsp_vptr->next; + } + + if (dsp_vptr->next != NULL) { + dsp_vptr->next->prev = dsp_vptr->prev; + } + + dsp_vptr->state = 0; +} + +void salReconnectVoice(DSPvoice* dsp_vptr, u8 studio) { + DSPvoice* tmp; + if (dsp_vptr->state != 0) { + if (dsp_vptr->prev != NULL) { + dsp_vptr->prev->next = dsp_vptr->next; + } else { + dspStudio[dsp_vptr->studio].voiceRoot = dsp_vptr->next; + } + + if (dsp_vptr->next != NULL) { + dsp_vptr->next->prev = dsp_vptr->prev; + } + + tmp = dspStudio[studio].voiceRoot; + dsp_vptr->next = tmp; + if (tmp != NULL) { + dsp_vptr->next->prev = dsp_vptr; + } + + dsp_vptr->prev = NULL; + dspStudio[studio].voiceRoot = dsp_vptr; + if (dsp_vptr->state == 2) { + dsp_vptr->nextAlien = dspStudio[dsp_vptr->studio].alienVoiceRoot; + dspStudio[dsp_vptr->studio].alienVoiceRoot = dsp_vptr; + } + } + + dsp_vptr->studio = studio; +} + +u32 salAddStudioInput(DSPstudioinfo* stp, SND_STUDIO_INPUT* desc) { + if (stp->numInputs < 7) { + stp->in[stp->numInputs].studio = desc->srcStudio; + stp->in[stp->numInputs].vol = ((u16)desc->vol << 8) | ((u16)desc->vol << 1); + stp->in[stp->numInputs].volA = ((u16)desc->volA << 8) | ((u16)desc->volA << 1); + stp->in[stp->numInputs].volB = ((u16)desc->volB << 8) | ((u16)desc->volB << 1); + stp->in[stp->numInputs].desc = desc; + ++stp->numInputs; + return 1; + } + + return 0; +} + +unsigned long salRemoveStudioInput(DSPstudioinfo* stp, SND_STUDIO_INPUT* desc) { + long i; // r31 + + i = 0; + while(i <= stp->numInputs) { + if (stp->in[i].desc == desc) { + break; + } + ++i; + } + + while (i <= stp->numInputs - 2) { + stp->in[i] = stp->in[i + 1]; + ++i; + } + + --stp->numInputs; + return 1; +}