mirror of https://github.com/PrimeDecomp/prime.git
530 lines
11 KiB
C
530 lines
11 KiB
C
|
|
#include "musyx/musyx_priv.h"
|
|
|
|
void voiceResetLastStarted(SYNTH_VOICE* svoice);
|
|
|
|
static VID_LIST vidList[128];
|
|
static u8 synth_last_started[8][16];
|
|
static u8 synth_last_fxstarted[64];
|
|
SYNTH_VOICELIST voiceList[64];
|
|
SYNTH_ROOTLIST voicePrioSortRootList[256];
|
|
u8 voicePrioSortVoicesRoot[256];
|
|
SYNTH_VOICELIST voicePrioSortVoices[64];
|
|
static VID_LIST* vidFree = NULL;
|
|
static VID_LIST* vidRoot = NULL;
|
|
static u32 vidCurrentId = 0;
|
|
u16 voicePrioSortRootListRoot = 0;
|
|
u8 voiceMusicRunning = 0;
|
|
u8 voiceFxRunning = 0;
|
|
u8 voiceListInsert = 0;
|
|
u8 voiceListRoot = 0;
|
|
|
|
void vidInit() {
|
|
int i;
|
|
VID_LIST* lvl;
|
|
vidCurrentId = 0;
|
|
vidRoot = NULL;
|
|
vidFree = vidList;
|
|
for (lvl = NULL, i = 0; i < 128; lvl = &vidList[i], ++i) {
|
|
vidList[i].prev = lvl;
|
|
if (lvl != NULL) {
|
|
lvl->next = &vidList[i];
|
|
}
|
|
}
|
|
lvl->next = NULL;
|
|
}
|
|
|
|
static VID_LIST* get_vidlist(u32 vid) {
|
|
VID_LIST* vl = vidRoot;
|
|
while (vl != NULL) {
|
|
if (vl->vid == vid) {
|
|
return vl;
|
|
}
|
|
if (vl->vid > vid) {
|
|
break;
|
|
}
|
|
vl = vl->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static u32 get_newvid() {
|
|
u32 vid; // r31
|
|
do {
|
|
vid = vidCurrentId++;
|
|
} while (vid == 0xFFFFFFFF);
|
|
|
|
return vid;
|
|
}
|
|
|
|
static void vidRemove(VID_LIST** vidList) {
|
|
if ((*vidList)->prev != NULL) {
|
|
(*vidList)->prev->next = (*vidList)->next;
|
|
} else {
|
|
vidRoot = (*vidList)->next;
|
|
}
|
|
|
|
if ((*vidList)->next != NULL) {
|
|
(*vidList)->next->prev = (*vidList)->prev;
|
|
}
|
|
|
|
(*vidList)->next = vidFree;
|
|
|
|
if (vidFree != NULL) {
|
|
vidFree->prev = *vidList;
|
|
}
|
|
|
|
(*vidList)->prev = NULL;
|
|
vidFree = *vidList;
|
|
*vidList = NULL;
|
|
}
|
|
|
|
void vidRemoveVoiceReferences(SYNTH_VOICE* svoice) {
|
|
if (svoice->id == 0xFFFFFFFF) {
|
|
return;
|
|
}
|
|
|
|
voiceResetLastStarted(svoice);
|
|
if (svoice->parent != 0xFFFFFFFF) {
|
|
synthVoice[svoice->parent & 0xFF].child = svoice->child;
|
|
if (svoice->child != 0xFFFFFFFF) {
|
|
synthVoice[svoice->child & 0xFF].parent = svoice->parent;
|
|
}
|
|
|
|
vidRemove(&svoice->vidList);
|
|
} else if (svoice->child != 0xFFFFFFFF) {
|
|
svoice->vidList->root = svoice->child;
|
|
synthVoice[svoice->child & 0xFF].parent = 0xFFFFFFFF;
|
|
synthVoice[svoice->child & 0xFF].vidMasterList = svoice->vidMasterList;
|
|
if (svoice->vidList != svoice->vidMasterList) {
|
|
vidRemove(&svoice->vidList);
|
|
}
|
|
|
|
svoice->vidMasterList = svoice->vidList = NULL;
|
|
} else if (svoice->vidList != svoice->vidMasterList) {
|
|
vidRemove(&svoice->vidList);
|
|
vidRemove(&svoice->vidMasterList);
|
|
} else {
|
|
vidRemove(&svoice->vidList);
|
|
svoice->vidMasterList = NULL;
|
|
}
|
|
}
|
|
|
|
unsigned long vidMakeRoot(struct SYNTH_VOICE* svoice) {
|
|
svoice->vidMasterList = svoice->vidList;
|
|
return svoice->vidList->vid;
|
|
}
|
|
|
|
u32 vidMakeNew(SYNTH_VOICE* svoice, u32 isMaster) {
|
|
u32 vid; // r29
|
|
VID_LIST* nvl; // r30
|
|
VID_LIST* lvl; // r28
|
|
VID_LIST* vl; // r31
|
|
|
|
vid = get_newvid();
|
|
lvl = NULL;
|
|
nvl = vidRoot;
|
|
|
|
while (nvl != NULL) {
|
|
if (nvl->vid > vid) {
|
|
break;
|
|
}
|
|
|
|
if (nvl->vid == vid) {
|
|
vid = get_newvid();
|
|
}
|
|
|
|
lvl = nvl;
|
|
nvl = nvl->next;
|
|
}
|
|
|
|
if ((vl = vidFree) == NULL) {
|
|
return 0xFFFFFFFF;
|
|
}
|
|
|
|
if ((vidFree = vidFree->next) != NULL) {
|
|
vidFree->prev = NULL;
|
|
}
|
|
|
|
if (lvl == NULL) {
|
|
vidRoot = vl;
|
|
} else {
|
|
lvl->next = vl;
|
|
}
|
|
|
|
vl->prev = lvl;
|
|
vl->next = nvl;
|
|
|
|
if (nvl != NULL) {
|
|
nvl->prev = vl;
|
|
}
|
|
|
|
vl->vid = vid;
|
|
vl->root = svoice->id;
|
|
svoice->vidMasterList = isMaster ? vl : NULL;
|
|
svoice->vidList = vl;
|
|
|
|
return isMaster ? vid : svoice->id;
|
|
}
|
|
|
|
u32 vidGetInternalId(u32 vid) {
|
|
VID_LIST* vl;
|
|
|
|
if (vid != 0xffffffff) {
|
|
if ((vl = get_vidlist(vid)) != NULL) {
|
|
return vl->root;
|
|
}
|
|
}
|
|
|
|
return 0xffffffff;
|
|
}
|
|
|
|
static void voiceInitPrioSort() {
|
|
u32 i;
|
|
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
voicePrioSortVoices[i].user = 0;
|
|
}
|
|
|
|
for (i = 0; i < 256; ++i) {
|
|
voicePrioSortVoicesRoot[i] = 0xff;
|
|
}
|
|
|
|
voicePrioSortRootListRoot = 0xffff;
|
|
}
|
|
|
|
void voiceRemovePriority(SYNTH_VOICE* svoice) {
|
|
SYNTH_VOICELIST* vps; // r31
|
|
SYNTH_ROOTLIST* rps; // r30
|
|
|
|
vps = &voicePrioSortVoices[svoice->id & 0xFF];
|
|
if (vps->user != 1) {
|
|
return;
|
|
}
|
|
|
|
if (vps->prev != 0xFF) {
|
|
voicePrioSortVoices[vps->prev].next = vps->next;
|
|
} else {
|
|
voicePrioSortVoicesRoot[svoice->prio] = vps->next;
|
|
}
|
|
|
|
if (vps->next != 0xFF) {
|
|
voicePrioSortVoices[vps->next].prev = vps->prev;
|
|
} else if (vps->prev == 0xFF) {
|
|
rps = &voicePrioSortRootList[svoice->prio];
|
|
|
|
if (rps->prev != 0xFFFF) {
|
|
voicePrioSortRootList[rps->prev].next = rps->next;
|
|
|
|
} else {
|
|
voicePrioSortRootListRoot = rps->next;
|
|
}
|
|
|
|
if (rps->next != 0xFFFF) {
|
|
voicePrioSortRootList[rps->next].prev = rps->prev;
|
|
}
|
|
}
|
|
|
|
vps->user = 0;
|
|
}
|
|
|
|
void voiceSetPriority(SYNTH_VOICE* svoice, u8 prio) {
|
|
u16 li; // r25
|
|
SYNTH_VOICELIST* vps; // r27
|
|
u16 i; // r29
|
|
u32 v; // r26
|
|
v = (u8)svoice->id;
|
|
vps = &voicePrioSortVoices[v];
|
|
if (vps->user == 1) {
|
|
if (svoice->prio == prio) {
|
|
return;
|
|
}
|
|
|
|
voiceRemovePriority(svoice);
|
|
}
|
|
|
|
vps->user = 1;
|
|
vps->prev = 0xff;
|
|
if ((vps->next = voicePrioSortVoicesRoot[prio]) != 0xFF) {
|
|
voicePrioSortVoices[voicePrioSortVoicesRoot[prio]].prev = v;
|
|
} else if (voicePrioSortRootListRoot != 0xFFFF) {
|
|
if (prio >= voicePrioSortRootListRoot) {
|
|
for (i = voicePrioSortRootListRoot; i != 0xFFFF; i = voicePrioSortRootList[i].next) {
|
|
if ((u16)i > prio) {
|
|
break;
|
|
}
|
|
li = i;
|
|
}
|
|
|
|
voicePrioSortRootList[li].next = (u16)prio;
|
|
voicePrioSortRootList[prio].prev = li;
|
|
voicePrioSortRootList[prio].next = i;
|
|
if (i != 0xFFFF) {
|
|
voicePrioSortRootList[i].prev = prio;
|
|
}
|
|
|
|
} else {
|
|
voicePrioSortRootList[prio].next = voicePrioSortRootListRoot;
|
|
voicePrioSortRootList[prio].prev = 0xFFFF;
|
|
voicePrioSortRootList[voicePrioSortRootListRoot].prev = prio;
|
|
voicePrioSortRootListRoot = prio;
|
|
}
|
|
} else {
|
|
voicePrioSortRootList[prio].next = 0xFFFF;
|
|
voicePrioSortRootList[prio].prev = 0xFFFF;
|
|
voicePrioSortRootListRoot = prio;
|
|
}
|
|
|
|
voicePrioSortVoicesRoot[prio] = v;
|
|
svoice->prio = prio;
|
|
hwSetPriority(svoice->id & 0xFF, ((u32)prio << 24) | (svoice->age >> 15));
|
|
}
|
|
|
|
#pragma dont_inline on
|
|
u32 voiceAllocate(u8 priority, u8 maxVoices, u16 allocId, u8 fxFlag) {
|
|
long i; // r31
|
|
long num; // r26
|
|
long voice; // r30
|
|
u16 p; // r29
|
|
u32 type_alloc; // r25
|
|
SYNTH_VOICELIST* sfv; // r27
|
|
}
|
|
#pragma dont_inline reset
|
|
|
|
void voiceFree(SYNTH_VOICE* svoice) {
|
|
u32 i; // r29
|
|
SYNTH_VOICELIST* sfv; // r30
|
|
i = 1;
|
|
MUSY_ASSERT(svoice->id != 0xFFFFFFFF);
|
|
macMakeInactive(svoice, MAC_STATE_STOPPED);
|
|
voiceRemovePriority(svoice);
|
|
svoice->addr = NULL;
|
|
svoice->prio = 0;
|
|
sfv = &voiceList[(i = svoice->id & 0xFF)];
|
|
if (sfv->user == 0) {
|
|
sfv->user = 1;
|
|
if (voiceListRoot != 0xFF) {
|
|
sfv->next = 0xFF;
|
|
sfv->prev = voiceListInsert;
|
|
voiceList[voiceListInsert].next = i;
|
|
} else {
|
|
sfv->next = 0xFF;
|
|
sfv->prev = 0xFF;
|
|
voiceListRoot = i;
|
|
}
|
|
|
|
voiceListInsert = i;
|
|
if (svoice->fxFlag != 0) {
|
|
--voiceFxRunning;
|
|
} else {
|
|
--voiceMusicRunning;
|
|
}
|
|
}
|
|
|
|
svoice->id = 0xFFFFFFFF;
|
|
}
|
|
|
|
static void voiceInitFreeList() {
|
|
u32 i; // r31
|
|
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
voiceList[i].prev = i - 1;
|
|
voiceList[i].next = i + 1;
|
|
voiceList[i].user = 1;
|
|
}
|
|
|
|
voiceList[0].prev = 0xff;
|
|
voiceList[synthInfo.voiceNum - 1].next = 0xff;
|
|
voiceListRoot = 0;
|
|
voiceListInsert = synthInfo.voiceNum - 1;
|
|
}
|
|
|
|
void synthInitAllocationAids() {
|
|
voiceInitFreeList();
|
|
voiceInitPrioSort();
|
|
voiceFxRunning = 0;
|
|
voiceMusicRunning = 0;
|
|
}
|
|
|
|
u32 voiceBlock(u8 prio) {
|
|
u32 voice;
|
|
|
|
if ((voice = voiceAllocate(prio, 0xFF, 0xFFFF, 1)) != 0xFFFFFFFF) {
|
|
synthVoice[voice].block = 1;
|
|
synthVoice[voice].fxFlag = 1;
|
|
|
|
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
|
|
synthVoice[voice].allocId = 0xFFFF;
|
|
#endif
|
|
|
|
vidRemoveVoiceReferences(&synthVoice[voice]);
|
|
synthVoice[voice].id = voice | 0xFFFFFF00;
|
|
|
|
if (hwIsActive(voice)) {
|
|
hwBreak(voice);
|
|
}
|
|
|
|
macMakeInactive(&synthVoice[voice], MAC_STATE_STOPPED);
|
|
synthVoice[voice].addr = NULL;
|
|
voiceSetPriority(&synthVoice[voice], prio);
|
|
}
|
|
|
|
return voice;
|
|
}
|
|
|
|
void voiceUnblock(u32 voice) {
|
|
if (voice == 0xFFFFFFFF) {
|
|
return;
|
|
}
|
|
|
|
if (hwIsActive(voice)) {
|
|
hwBreak(voice);
|
|
}
|
|
|
|
synthVoice[voice].id = voice;
|
|
voiceFree(&synthVoice[voice]);
|
|
synthVoice[voice].block = 0;
|
|
}
|
|
|
|
void voiceKill(u32 vi) {
|
|
SYNTH_VOICE* sv = &synthVoice[vi]; // r31
|
|
if (sv->addr != NULL) {
|
|
vidRemoveVoiceReferences(sv);
|
|
sv->cFlags &= ~3;
|
|
sv->age = 0;
|
|
voiceFree(sv);
|
|
}
|
|
|
|
if (sv->block != 0) {
|
|
streamKill(vi);
|
|
}
|
|
|
|
hwBreak(vi);
|
|
}
|
|
|
|
long voiceKillSound(u32 voiceid) {
|
|
s32 ret = -1; // r29
|
|
u32 next_voiceid; // r28
|
|
u32 i; // r30
|
|
if (sndActive != FALSE) {
|
|
for (voiceid = vidGetInternalId(voiceid); voiceid != -1; voiceid = next_voiceid) {
|
|
i = voiceid & 0xff;
|
|
next_voiceid = synthVoice[i].child;
|
|
if (voiceid == synthVoice[i].id) {
|
|
voiceKill(i);
|
|
ret = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
void synthKillAllVoices(unsigned char musiconly) {
|
|
u32 i;
|
|
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
if (synthVoice[i].addr != NULL) {
|
|
if (musiconly == 0 || (musiconly != 0 && synthVoice[i].fxFlag == 0)) {
|
|
voiceKill(i);
|
|
}
|
|
} else {
|
|
voiceKill(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void synthKillVoicesByMacroReferences(u16* ref) {
|
|
u32 i; // r31
|
|
u16 id; // r29
|
|
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
if (synthVoice[i].addr == NULL && synthVoice[i].block == 0) {
|
|
voiceKill(i);
|
|
}
|
|
}
|
|
|
|
while (*ref != 0xFFFF) {
|
|
if ((*ref & 0x8000)) {
|
|
id = *ref & 0x3fff;
|
|
while (id <= ref[1]) {
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
if (synthVoice[i].addr != NULL && id == synthVoice[i].macroId) {
|
|
voiceKill(i);
|
|
}
|
|
}
|
|
++id;
|
|
}
|
|
ref += 2;
|
|
} else {
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
if (synthVoice[i].addr != NULL && *ref == synthVoice[i].macroId) {
|
|
voiceKill(i);
|
|
}
|
|
}
|
|
++ref;
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 voiceIsLastStarted(SYNTH_VOICE* svoice) {
|
|
u32 i; // r31
|
|
|
|
if (svoice->id != 0xFFFFFFFF && svoice->midi != 0xFF) {
|
|
i = svoice->id & 0xFF;
|
|
if (svoice->midiSet == 0xFF) {
|
|
if (synth_last_fxstarted[i] == i) {
|
|
return TRUE;
|
|
}
|
|
} else if (synth_last_started[svoice->midiSet][svoice->midi] == i) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void voiceSetLastStarted(SYNTH_VOICE* svoice) {
|
|
u32 i; // r31
|
|
|
|
if (svoice->id != 0xFFFFFFFF && svoice->midi != 0xFF) {
|
|
i = svoice->id & 0xFF;
|
|
if (svoice->midiSet == 0xFF) {
|
|
synth_last_fxstarted[i] = i;
|
|
} else {
|
|
synth_last_started[svoice->midiSet][svoice->midi] = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void voiceResetLastStarted(struct SYNTH_VOICE* svoice) {
|
|
u32 i;
|
|
|
|
if ((svoice->id != 0xffffffff) && (svoice->midi != 0xff)) {
|
|
i = svoice->id & 0xff;
|
|
if (svoice->midiSet == 0xff) {
|
|
if (synth_last_fxstarted[i] == i) {
|
|
synth_last_fxstarted[i] = 0xff;
|
|
}
|
|
} else if (i == synth_last_started[svoice->midiSet][svoice->midi]) {
|
|
synth_last_started[svoice->midiSet][svoice->midi] = 0xff;
|
|
}
|
|
}
|
|
}
|
|
|
|
void voiceInitLastStarted() {
|
|
u32 i;
|
|
u32 j;
|
|
|
|
for (i = 0; i < 8; ++i) {
|
|
for (j = 0; j < 16; ++j) {
|
|
synth_last_started[i][j] = 0xFF;
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < 64; ++j) {
|
|
synth_last_fxstarted[j] = 0xFF;
|
|
}
|
|
}
|