mirror of https://github.com/PrimeDecomp/prime.git
696 lines
12 KiB
C
696 lines
12 KiB
C
/* ---------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---------------------------------------
|
|
*/
|
|
|
|
#include "musyx/assert.h"
|
|
#include "musyx/hardware.h"
|
|
#include "musyx/macros.h"
|
|
#include "musyx/s3d.h"
|
|
#include "musyx/seq.h"
|
|
#include "musyx/stream.h"
|
|
#include "musyx/synth.h"
|
|
|
|
#include <stdarg.h>
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
bool sndFXCtrl(SND_VOICEID vid, u8 ctrl, u8 value) {
|
|
bool ret;
|
|
MUSY_ASSERT_MSG(sndActive != 0, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
ret = synthFXSetCtrl(vid, ctrl, value);
|
|
hwEnableIrq();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
*/
|
|
bool sndFXCtrl14(SND_VOICEID vid, u8 ctrl, u16 value) {
|
|
bool ret;
|
|
MUSY_ASSERT_MSG(sndActive != 0, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
ret = synthFXSetCtrl14(vid, ctrl, value);
|
|
hwEnableIrq();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
*/
|
|
bool sndFXKeyOff(SND_VOICEID vid) {
|
|
bool ret;
|
|
MUSY_ASSERT_MSG(sndActive != 0, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
ret = synthSendKeyOff(vid);
|
|
hwEnableIrq();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
*/
|
|
SND_VOICEID sndFXStartEx(SND_FXID fid, u8 vol, u8 pan, u8 studio) {
|
|
SND_VOICEID v;
|
|
MUSY_ASSERT_MSG(sndActive != 0, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
v = synthFXStart(fid, vol, pan, studio, synthITDDefault[studio].sfx);
|
|
hwEnableIrq();
|
|
return v;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
SND_VOICEID sndFXStartPara(SND_FXID fid, u8 vol, u8 pan, u8 studio, u8 numPara, ...) {
|
|
u32 vid;
|
|
u8 i;
|
|
va_list args;
|
|
u32 value;
|
|
u8 ctrl;
|
|
|
|
MUSY_ASSERT_MSG(sndActive != 0, "Sound system is not initialized.");
|
|
|
|
hwDisableIrq();
|
|
|
|
if ((vid = synthFXStart(fid, vol, pan, studio, synthITDDefault[studio].sfx)) != -1 &&
|
|
numPara != 0) {
|
|
|
|
va_start(args, numPara);
|
|
|
|
for (i = 0; i < numPara; ++i) {
|
|
|
|
ctrl = va_arg(args, u32);
|
|
value = va_arg(args, u32);
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
if (ctrl < 0x40 || ctrl == 0x80 || ctrl == 0x84) {
|
|
MUSY_ASSERT_MSG(value <= 0x3fff, "Hires MIDI controller value out of range.");
|
|
|
|
synthFXSetCtrl14(vid, ctrl, (u16)value);
|
|
} else {
|
|
|
|
MUSY_ASSERT_MSG(value <= 0x7f, "Lores MIDI controller value out of range.");
|
|
synthFXSetCtrl(vid, ctrl, (u16)value);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
|
|
*/
|
|
hwEnableIrq();
|
|
return vid;
|
|
}
|
|
|
|
/*
|
|
|
|
*/
|
|
SND_VOICEID sndFXStartParaInfo(SND_FXID fid, u8 vol, u8 pan, u8 studio,
|
|
SND_PARAMETER_INFO* paraInfo) {
|
|
unsigned long vid; // r29
|
|
unsigned char i; // r28
|
|
SND_PARAMETER* pPtr; // r31
|
|
|
|
MUSY_ASSERT_MSG(sndActive != 0, "Sound system is not initialized.");
|
|
|
|
hwDisableIrq();
|
|
|
|
if ((vid = synthFXStart(fid, vol, pan, studio, synthITDDefault[studio].sfx)) != 0xFFFFFFFF) {
|
|
MUSY_ASSERT_MSG(paraInfo != NULL, "Parameter pointer must not be NULL.");
|
|
for (pPtr = paraInfo->paraArray, i = 0; i < paraInfo->numPara; ++pPtr, ++i) {
|
|
/*
|
|
|
|
*/
|
|
if (pPtr->ctrl < 0x40 || pPtr->ctrl == 0x80 || pPtr->ctrl == 0x84) {
|
|
MUSY_ASSERT_MSG(pPtr->paraData.value14 <= 0x3fff,
|
|
"Hires MIDI controller value out of range.");
|
|
|
|
synthFXSetCtrl14(vid, pPtr->ctrl, pPtr->paraData.value14);
|
|
} else {
|
|
|
|
MUSY_ASSERT_MSG(pPtr->paraData.value7 <= 0x7f, "Lores MIDI controller value out of range.");
|
|
synthFXSetCtrl(vid, pPtr->ctrl, pPtr->paraData.value7);
|
|
}
|
|
}
|
|
}
|
|
|
|
hwEnableIrq();
|
|
return vid;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
SND_VOICEID sndFXCheck(SND_VOICEID vid) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
return vidGetInternalId(vid) != -1 ? vid : -1;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
bool sndReadFlag(unsigned char num) {
|
|
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
return synthGlobalVariable[num & 0xf];
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
*/
|
|
long sndWriteFlag(unsigned char num, long value) {
|
|
long old; // r30
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
num &= 0xf;
|
|
|
|
hwDisableIrq();
|
|
old = synthGlobalVariable[num];
|
|
synthGlobalVariable[num] = value;
|
|
hwEnableIrq();
|
|
|
|
return old;
|
|
}
|
|
/*
|
|
|
|
|
|
|
|
|
|
*/
|
|
u32 sndSendMessage(u32 vid, s32 mesg) {
|
|
u32 ret; // r31
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
hwDisableIrq();
|
|
ret = macPostMessage(vid, mesg);
|
|
hwEnableIrq();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
*/
|
|
void sndSetReceiveMessageCallback(void (*callback)(unsigned long, long)) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
synthMessageCallback = callback;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
*/
|
|
void sndSilence() {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
hwDisableIrq();
|
|
seqKillAllInstances();
|
|
s3dKillAllEmitter();
|
|
synthKillAllVoices(0);
|
|
hwEnableIrq();
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
*/
|
|
u32 sndIsIdle() {
|
|
u32 i; // r31
|
|
u8 flag; // r30
|
|
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
flag = 0;
|
|
|
|
synthIdleWaitActive = TRUE;
|
|
if (!hwGlobalActivity()) {
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
flag |= hwIsActive(i);
|
|
}
|
|
} else {
|
|
|
|
flag = 1;
|
|
}
|
|
synthIdleWaitActive = FALSE;
|
|
return flag == 0;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
*/
|
|
u32 sndFXAssignVolGroup2FXId(SND_FXID fid, u8 vGroup) {
|
|
FX_TAB* fx; // r30
|
|
u32 ret; // r29
|
|
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
ret = 0;
|
|
|
|
hwDisableIrq();
|
|
//
|
|
//
|
|
//
|
|
if ((fx = dataGetFX(fid)) != NULL) {
|
|
/*
|
|
|
|
|
|
*/
|
|
if ((u8)vGroup != 0xFE) {
|
|
//
|
|
//
|
|
fx->vGroup = vGroup;
|
|
synthSetMusicVolumeType(vGroup, 3);
|
|
} else {
|
|
fx->vGroup = 0x1f;
|
|
}
|
|
ret = 1;
|
|
} else {
|
|
|
|
MUSY_DEBUG("FX ID=%d could not be found in FX table.", fid);
|
|
}
|
|
|
|
hwEnableIrq();
|
|
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
*/
|
|
void sndPauseVolume(u8 volume, u16 time, u8 vGroup) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
hwDisableIrq();
|
|
synthPauseVolume(volume, time, vGroup);
|
|
hwEnableIrq();
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
*/
|
|
void sndVolume(u8 volume, u16 time, u8 volgroup) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
hwDisableIrq();
|
|
synthVolume(volume, time, volgroup, 0, -1);
|
|
hwEnableIrq();
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
*/
|
|
void sndMasterVolume(u8 volume, u16 time, u8 music, u8 fx) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
if (music != 0)
|
|
synthVolume(volume, time, 0x15, 0, -1);
|
|
|
|
if (fx != 0)
|
|
synthVolume(volume, time, 0x16, 0, -1);
|
|
hwEnableIrq();
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
*/
|
|
void sndOutputMode(SND_OUTPUTMODE output) {
|
|
u32 i;
|
|
u32 oldFlags;
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
oldFlags = synthFlags;
|
|
|
|
switch (output) {
|
|
case SND_OUTPUTMODE_MONO:
|
|
|
|
synthFlags |= 1;
|
|
synthFlags &= ~2;
|
|
hwDisableHRTF();
|
|
|
|
break;
|
|
case SND_OUTPUTMODE_STEREO:
|
|
|
|
synthFlags &= ~1;
|
|
synthFlags &= ~2;
|
|
hwDisableHRTF();
|
|
|
|
break;
|
|
case SND_OUTPUTMODE_SURROUND:
|
|
|
|
synthFlags &= ~1;
|
|
synthFlags |= 2;
|
|
hwDisableHRTF();
|
|
|
|
break;
|
|
default:
|
|
#line 426
|
|
MUSY_ASSERT_MSG(FALSE, "Unsupported outputmode selected.");
|
|
#line 418
|
|
break;
|
|
}
|
|
|
|
if (oldFlags == synthFlags) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
synthVoice[i].cFlags |= 0x0000200000000000;
|
|
}
|
|
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
|
|
streamOutputModeChanged();
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
// clang-format off
|
|
void sndSetAuxProcessingCallbacks(u8 studio,
|
|
SND_AUX_CALLBACK auxA, void* userA, u8 midiA, SND_SEQID seqIDA,
|
|
SND_AUX_CALLBACK auxB, void* userB, u8 midiB, SND_SEQID seqIDB) {
|
|
// clang-format on
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
hwDisableIrq();
|
|
if (auxA != NULL) {
|
|
|
|
if ((synthAuxAMIDI[studio] = midiA) != 0xFF) {
|
|
synthAuxAMIDISet[studio] = seqGetPrivateId(seqIDA);
|
|
synthAuxACallback[studio] = auxA;
|
|
synthAuxAUser[studio] = userA;
|
|
}
|
|
} else {
|
|
synthAuxACallback[studio] = NULL;
|
|
synthAuxAMIDI[studio] = 0xff;
|
|
}
|
|
|
|
if (auxB != NULL) {
|
|
|
|
if ((synthAuxBMIDI[studio] = midiB) != 0xFF) {
|
|
synthAuxBMIDISet[studio] = seqGetPrivateId(seqIDB);
|
|
synthAuxBCallback[studio] = auxB;
|
|
synthAuxBUser[studio] = userB;
|
|
}
|
|
} else {
|
|
synthAuxBCallback[studio] = NULL;
|
|
synthAuxBMIDI[studio] = 0xff;
|
|
}
|
|
|
|
hwSetAUXProcessingCallbacks(studio, auxA, userA, auxB, userB);
|
|
hwEnableIrq();
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
void sndUpdateAuxParameter(unsigned char studio, unsigned short* para, unsigned char auxBus) {
|
|
struct SND_AUX_INFO info; // r1+0x14
|
|
unsigned long i; // r30
|
|
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
for (i = 0; i < 4; ++i) {
|
|
info.data.parameterUpdate.para[i] = para[i];
|
|
}
|
|
|
|
if (auxBus == 0) {
|
|
MUSY_ASSERT_MSG(synthAuxACallback[studio] != NULL, "No FX is defined for AuxA.");
|
|
|
|
synthAuxACallback[studio](1, &info, synthAuxAUser);
|
|
} else {
|
|
|
|
MUSY_ASSERT_MSG(synthAuxBCallback[studio] != NULL, "No FX is defined for AuxB.");
|
|
synthAuxBCallback[studio](1, &info, synthAuxBUser);
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
*/
|
|
void sndSetITDDefault(unsigned char studio, unsigned long musicITD, unsigned long sfxITD) {
|
|
synthITDDefault[studio].music = musicITD;
|
|
synthITDDefault[studio].sfx = sfxITD;
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
*/
|
|
void synthActivateStudio(u8 studio, u32 isMaster, SND_STUDIO_TYPE type) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
synthAuxACallback[studio] = NULL;
|
|
synthAuxBCallback[studio] = NULL;
|
|
synthAuxAMIDI[studio] = 0xFF;
|
|
synthAuxBMIDI[studio] = 0xFF;
|
|
synthITDDefault[studio].sfx = 0;
|
|
synthITDDefault[studio].music = 0;
|
|
hwActivateStudio(studio, isMaster, type);
|
|
hwEnableIrq();
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
*/
|
|
void sndActivateStudioEx(u8 studio, u32 isMaster, SND_STUDIO_TYPE type) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
MUSY_ASSERT_MSG(studio < synthInfo.studioNum, "Illegal studio index.");
|
|
if (studio != 0) {
|
|
hwDisableIrq();
|
|
synthActivateStudio(studio, isMaster, type);
|
|
hwEnableIrq();
|
|
} else {
|
|
MUSY_DEBUG("The default studio cannot be activated or deactivated.\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
void synthDeactivateStudio(u8 studio) {
|
|
u32 i;
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
|
|
if (studio == synthVoice[i].studio) {
|
|
if (synthVoice[i].id != 0xFFFFFFFF) {
|
|
voiceKillSound(synthVoice[i].vidList->vid);
|
|
} else if (hwIsActive(i)) {
|
|
hwOff(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
hwDisableIrq();
|
|
|
|
synthAuxACallback[studio] = 0;
|
|
synthAuxBCallback[studio] = 0;
|
|
synthAuxAMIDI[studio] = 0xFF;
|
|
synthAuxBMIDI[studio] = 0xFF;
|
|
|
|
hwEnableIrq();
|
|
|
|
hwDeactivateStudio(studio);
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
*/
|
|
void sndDeactivateStudio(u8 studio) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
MUSY_ASSERT_MSG(studio < synthInfo.studioNum, "Illegal studio index.");
|
|
if (studio != 0) {
|
|
hwDisableIrq();
|
|
synthDeactivateStudio(studio);
|
|
hwEnableIrq();
|
|
} else {
|
|
MUSY_DEBUG("The default studio cannot be activated or deactivated.\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
void synthChangeStudioMasterMix(u8 studio, u32 isMaster) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
hwChangeStudioMix(studio, isMaster);
|
|
}
|
|
|
|
//
|
|
|
|
void sndChangeStudioMasterMix(unsigned char studio, unsigned long isMaster) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
if (studio != 0) {
|
|
hwDisableIrq();
|
|
synthChangeStudioMasterMix(studio, isMaster);
|
|
hwEnableIrq();
|
|
} else {
|
|
MUSY_DEBUG("Default studio's master mix cannot be changed.\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
|
|
|
|
|
|
|
|
|
|
*/
|
|
u32 synthAddStudioInput(u8 studio, SND_STUDIO_INPUT* in_desc) {
|
|
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
|
|
return hwAddInput(studio, in_desc);
|
|
}
|
|
|
|
//
|
|
|
|
u32 sndAddStudioInput(u8 studio, struct SND_STUDIO_INPUT* in_desc) {
|
|
u32 ret;
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
ret = synthAddStudioInput(studio, in_desc);
|
|
hwEnableIrq();
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
|
|
*/
|
|
u32 synthRemoveStudioInput(u8 studio, SND_STUDIO_INPUT* in_desc) {
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
return hwRemoveInput(studio, in_desc);
|
|
}
|
|
|
|
/*
|
|
|
|
*/
|
|
u32 sndRemoveStudioInput(u8 studio, SND_STUDIO_INPUT* in_desc) {
|
|
u32 ret;
|
|
MUSY_ASSERT_MSG(sndActive != NULL, "Sound system is not initialized.");
|
|
hwDisableIrq();
|
|
ret = synthRemoveStudioInput(studio, in_desc);
|
|
hwEnableIrq();
|
|
return ret;
|
|
}
|
|
|
|
u8 sndDbgGetActiveVoices() {
|
|
u8 n; // r31
|
|
hwDisableIrq();
|
|
n = voiceFxRunning + voiceMusicRunning;
|
|
hwEnableIrq();
|
|
return n;
|
|
}
|