mirror of https://github.com/PrimeDecomp/prime.git
1740 lines
46 KiB
C
1740 lines
46 KiB
C
#include "musyx/musyx_priv.h"
|
|
#include "musyx/seq.h"
|
|
#include "musyx/synth.h"
|
|
#include <string.h>
|
|
|
|
static u8 DebugMacroSteps;
|
|
|
|
static SYNTH_VOICE* macActiveMacroRoot;
|
|
static SYNTH_VOICE* macTimeQueueRoot;
|
|
static u64 macRealTime;
|
|
|
|
static void TimeQueueAdd(SYNTH_VOICE* svoice);
|
|
|
|
void macMakeActive(SYNTH_VOICE* svoice);
|
|
|
|
void macSetExternalKeyoff(SYNTH_VOICE* svoice);
|
|
|
|
static void DoSetPitch(SYNTH_VOICE* svoice);
|
|
|
|
static int SendSingleKeyOff(u32 voiceid) {
|
|
u32 i; // r31
|
|
|
|
if (voiceid != 0xFFFFFFFF) {
|
|
|
|
i = voiceid & 0xFF;
|
|
|
|
if (voiceid == synthVoice[i].id) {
|
|
|
|
macSetExternalKeyoff(&synthVoice[i]);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static u32 ExecuteTrap(SYNTH_VOICE* svoice, u8 trapType) {
|
|
if (svoice->trapEventAny != 0 && svoice->trapEventAddr[trapType] != NULL) {
|
|
svoice->curAddr = svoice->trapEventCurAddr[trapType];
|
|
svoice->addr = svoice->trapEventAddr[trapType];
|
|
svoice->trapEventAddr[trapType] = NULL;
|
|
macMakeActive(svoice);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u32 HasHWEventTrap(SYNTH_VOICE* svoice) {
|
|
if (svoice->trapEventAny != '\0') {
|
|
return svoice->trapEventAddr[1] != NULL;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void CheckHWEventTrap(SYNTH_VOICE* svoice) {
|
|
if ((svoice->cFlags & 0x20) == 0 && !hwIsActive(svoice->id & 0xff)) {
|
|
ExecuteTrap(svoice, 1);
|
|
}
|
|
}
|
|
|
|
static u32 mcmdWait(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 w; // r1+0x10
|
|
u32 ms; // r29
|
|
|
|
if ((ms = (u16)(cstep->para[1] >> 0x10))) {
|
|
if (((u8)(cstep->para[0] >> 8) & 1)) {
|
|
if (svoice->cFlags & 8) {
|
|
if (!(svoice->cFlags & 0x10000000000)) {
|
|
return 0;
|
|
}
|
|
svoice->cFlags |= 0x40000000000;
|
|
}
|
|
svoice->cFlags |= 4;
|
|
} else {
|
|
svoice->cFlags &= ~4;
|
|
}
|
|
|
|
if (((u8)(cstep->para[0] >> 0x18) & 1)) {
|
|
if (!(svoice->cFlags & 0x20) && !hwIsActive(svoice->id & 0xFF)) {
|
|
return 0;
|
|
}
|
|
svoice->cFlags |= 0x40000;
|
|
} else {
|
|
svoice->cFlags &= ~0x40000;
|
|
}
|
|
|
|
if (((u8)(cstep->para[0] >> 0x10)) & 1) {
|
|
ms = sndRand() % ms;
|
|
}
|
|
|
|
if (ms != 0xFFFF) {
|
|
if ((w = ((u8)(cstep->para[1] >> 0x8) & 1) != 0)) {
|
|
sndConvertMs(&ms);
|
|
} else {
|
|
sndConvertTicks(&ms, svoice);
|
|
}
|
|
|
|
if (w != 0) {
|
|
if ((u8)cstep->para[1] & 1) {
|
|
svoice->wait = svoice->macStartTime + ms;
|
|
} else {
|
|
svoice->wait = macRealTime + ms;
|
|
}
|
|
} else {
|
|
if ((u8)cstep->para[1] & 1) {
|
|
svoice->wait = ms;
|
|
} else {
|
|
svoice->wait = svoice->waitTime + ms;
|
|
}
|
|
}
|
|
|
|
if (!(svoice->wait > macRealTime)) {
|
|
svoice->waitTime = svoice->wait;
|
|
svoice->wait = 0;
|
|
}
|
|
} else {
|
|
svoice->wait = -1;
|
|
}
|
|
|
|
if (svoice->wait != 0) {
|
|
if (svoice->wait != -1) {
|
|
TimeQueueAdd(svoice);
|
|
}
|
|
macMakeInactive(svoice, 1);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static u32 mcmdWaitMs(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
*((u8*)cstep->para + 6) = 1;
|
|
return mcmdWait(svoice, cstep);
|
|
}
|
|
|
|
static u32 mcmdEndOfMacro(SYNTH_VOICE* svoice) {
|
|
vidRemoveVoiceReferences(svoice);
|
|
voiceFree(svoice);
|
|
return 1;
|
|
}
|
|
|
|
static u32 mcmdStop(SYNTH_VOICE* svoice) { return mcmdEndOfMacro(svoice); }
|
|
|
|
static u32 mcmdReturn(SYNTH_VOICE* svoice) {
|
|
if (svoice->callStackEntryNum != 0) {
|
|
svoice->addr = svoice->callStack[svoice->callStackIndex].addr;
|
|
svoice->curAddr = svoice->callStack[svoice->callStackIndex].curAddr;
|
|
svoice->callStackIndex = (svoice->callStackIndex - 1) & 3;
|
|
--svoice->callStackEntryNum;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void mcmdIfKey(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
MSTEP* addr; // r31
|
|
if (svoice->curNote < ((u8)(cstep->para[0] >> 8))) {
|
|
return;
|
|
}
|
|
|
|
if ((addr = (MSTEP*)dataGetMacro((cstep->para[0] >> 0x10))) != NULL) {
|
|
svoice->addr = addr;
|
|
svoice->curAddr = addr + (u16)cstep->para[1];
|
|
}
|
|
}
|
|
|
|
static void mcmdIfVelocity(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
MSTEP* addr;
|
|
if (((u8)(svoice->volume >> 0x10)) < (u8)(cstep->para[0] >> 8)) {
|
|
return;
|
|
}
|
|
|
|
if ((addr = (MSTEP*)dataGetMacro(cstep->para[0] >> 0x10))) {
|
|
svoice->addr = addr;
|
|
svoice->curAddr = addr + (u16)cstep->para[1];
|
|
}
|
|
}
|
|
|
|
static void mcmdIfModulation(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
MSTEP* addr; // r30
|
|
u8 mod; // r28
|
|
|
|
if (svoice->midi == 0xff) {
|
|
return;
|
|
}
|
|
mod = inpGetModulation(svoice) >> 7;
|
|
if (mod < (u8)(cstep->para[0] >> 8)) {
|
|
return;
|
|
}
|
|
|
|
if ((addr = (MSTEP*)dataGetMacro(cstep->para[0] >> 0x10))) {
|
|
svoice->addr = addr;
|
|
svoice->curAddr = addr + (u16)(cstep->para[1]);
|
|
}
|
|
}
|
|
|
|
static void mcmdIfRandom(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
MSTEP* addr; // r31
|
|
if ((u8)sndRand() < (u8)(cstep->para[0] >> 8)) {
|
|
return;
|
|
}
|
|
|
|
if ((addr = (MSTEP*)dataGetMacro(cstep->para[0] >> 0x10))) {
|
|
svoice->addr = addr;
|
|
svoice->curAddr = addr + (u16)cstep->para[1];
|
|
}
|
|
}
|
|
|
|
static u32 mcmdGoto(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
MSTEP* addr; // r31
|
|
if ((addr = (MSTEP*)dataGetMacro(cstep->para[0] >> 0x10)) != NULL) {
|
|
svoice->addr = addr;
|
|
svoice->curAddr = addr + (u16)cstep->para[1];
|
|
return 0;
|
|
}
|
|
|
|
return mcmdEndOfMacro(svoice);
|
|
}
|
|
|
|
static u32 mcmdGosub(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
MSTEP* addr; // r30
|
|
if ((addr = (MSTEP*)dataGetMacro((u16)(cstep->para[0] >> 0x10))) != NULL) {
|
|
svoice->callStackIndex = (svoice->callStackIndex + 1) & 3;
|
|
svoice->callStack[svoice->callStackIndex].addr = svoice->addr;
|
|
svoice->callStack[svoice->callStackIndex].curAddr = svoice->curAddr;
|
|
if (++svoice->callStackEntryNum > 4) {
|
|
svoice->callStackEntryNum = 4;
|
|
}
|
|
|
|
svoice->addr = addr;
|
|
svoice->curAddr = addr + (u16)cstep->para[1];
|
|
return 0;
|
|
}
|
|
|
|
return mcmdEndOfMacro(svoice);
|
|
}
|
|
|
|
static void mcmdTrapEvent(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
MSTEP* addr; // r29
|
|
u8 t; // r30
|
|
if ((addr = (MSTEP*)dataGetMacro(cstep->para[0] >> 0x10)) != NULL) {
|
|
t = (u8)(cstep->para[0] >> 8);
|
|
svoice->trapEventAddr[t] = addr;
|
|
svoice->trapEventCurAddr[t] = addr + (u16)cstep->para[1];
|
|
svoice->trapEventAny = 1;
|
|
if (t == 0 && (svoice->cFlags & 0x10000000008) == 0x10000000008) {
|
|
svoice->cFlags |= 0x40000000000;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mcmdUntrapEvent(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u8 i; // r31
|
|
svoice->trapEventAddr[(u8)(cstep->para[0] >> 8)] = 0;
|
|
|
|
for (i = 0; i < 3; ++i) {
|
|
if (svoice->trapEventAddr[i] != NULL) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
svoice->trapEventAny = 0;
|
|
}
|
|
|
|
static void mcmdLoop(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
|
|
if (svoice->loop == 0) {
|
|
if ((u8)(cstep->para[0] >> 16) & 1) {
|
|
svoice->loop = sndRand() % (u16)(cstep->para[1] >> 16);
|
|
} else {
|
|
svoice->loop = (cstep->para[1] >> 16);
|
|
}
|
|
|
|
if (svoice->loop == 0xFFFF) {
|
|
goto skip;
|
|
}
|
|
++svoice->loop;
|
|
} else if (svoice->loop == 0xFFFF) {
|
|
goto skip;
|
|
}
|
|
|
|
if (--svoice->loop == 0) {
|
|
return;
|
|
}
|
|
skip:
|
|
if (((u8)(cstep->para[0] >> 8) & 1) != 0 && (svoice->cFlags & 0x10000000008) == 0x00000000008) {
|
|
svoice->loop = 0;
|
|
|
|
} else if (((u8)(cstep->para[0] >> 0x18) & 1) && (svoice->cFlags & 0x20) == 0 &&
|
|
!hwIsActive(svoice->id & 0xFF)) {
|
|
svoice->loop = 0;
|
|
} else {
|
|
svoice->curAddr = svoice->addr + ((u16)cstep->para[1]);
|
|
}
|
|
}
|
|
|
|
static void mcmdPlayMacro(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
s32 key; // r29
|
|
u32 new_child; // r30
|
|
|
|
key = ((u32)svoice->orgNote + (s8)(u8)(cstep->para[0] >> 8));
|
|
key = (key < 0) ? 0 : key > 0x7f ? 0x7f : key;
|
|
|
|
if (svoice->fxFlag != 0) {
|
|
key |= 0x80;
|
|
}
|
|
|
|
svoice->block = 1;
|
|
new_child = macStart((u16)(cstep->para[0] >> 0x10), (u8)(cstep->para[1] >> 0x10),
|
|
(u8)(cstep->para[1] >> 0x18), svoice->allocId, key,
|
|
(u8)(svoice->volume >> 0x10), (u8)(svoice->panning[0] >> 0x10), svoice->midi,
|
|
svoice->midiSet, svoice->section, (u16)cstep->para[1], (u16)svoice->track, 0,
|
|
svoice->vGroup, svoice->studio, svoice->itdMode == 0);
|
|
svoice->block = 0;
|
|
if (new_child != 0xFFFFFFFF) {
|
|
svoice->lastVID = synthVoice[(u8)new_child].vidList->vid;
|
|
synthVoice[(u8)new_child].parent = svoice->id;
|
|
if (svoice->child != -1) {
|
|
synthVoice[(u8)new_child].child = svoice->child;
|
|
synthVoice[(u8)svoice->child].parent = new_child;
|
|
}
|
|
svoice->child = new_child;
|
|
if (svoice->fxFlag != 0) {
|
|
synthFXCloneMidiSetup(&synthVoice[(u8)new_child], svoice);
|
|
}
|
|
} else {
|
|
svoice->lastVID = 0xFFFFFFFF;
|
|
}
|
|
}
|
|
|
|
static void mcmdSendKeyOff(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 voiceid; // r30
|
|
u32 i; // r31
|
|
|
|
voiceid = (svoice->orgNote + (u8)(cstep->para[0] >> 8)) << 8;
|
|
voiceid |= ((u16)(cstep->para[0] >> 16)) << 16;
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
if (synthVoice[i].id == (voiceid | i)) {
|
|
SendSingleKeyOff(voiceid | i);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void mcmdAddAgeCounter(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
s16 step; // r29
|
|
s32 age; // r30
|
|
|
|
step = (u16)(cstep->para[0] >> 16);
|
|
age = (svoice->age >> 15) + step;
|
|
|
|
if (age < 0) {
|
|
svoice->age = 0;
|
|
} else if (age > 0xFFFF) {
|
|
svoice->age = 0x7fff8000;
|
|
} else {
|
|
svoice->age = age * 0x8000;
|
|
}
|
|
|
|
hwSetPriority(svoice->id & 0xFF, ((u32)svoice->prio << 24) | ((u32)svoice->age >> 15));
|
|
}
|
|
|
|
static void mcmdSetAgeCounter(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->age = (u16)(cstep->para[0] >> 0x10) << 0xf;
|
|
hwSetPriority(svoice->id & 0xff, (u32)svoice->prio << 0x18 | svoice->age >> 0xf);
|
|
}
|
|
|
|
static void mcmdSetAgeCounterSpeed(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 time = cstep->para[1];
|
|
if (time != 0) {
|
|
svoice->ageSpeed = (svoice->age >> 8) / time;
|
|
} else {
|
|
svoice->ageSpeed = 0;
|
|
}
|
|
}
|
|
static void mcmdSetAgeCounterByVolume(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 age; // r30
|
|
|
|
age = (((u8)(svoice->volume >> 16) * (u16)cstep->para[1]) >> 7) + (u16)(cstep->para[0] >> 16);
|
|
svoice->age = age > 60000 ? 0x75300000 : age * 0x8000;
|
|
hwSetPriority(svoice->id & 0xff, (u32)svoice->prio << 0x18 | svoice->age >> 0xf);
|
|
}
|
|
|
|
static void mcmdAddPriority(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
s16 add; // r30
|
|
s16 prio; // r31
|
|
add = (u16)(cstep->para[0] >> 16);
|
|
prio = svoice->prio + add;
|
|
prio = (prio < 0) ? 0 : (prio > 0xFF) ? 0xFF : prio;
|
|
|
|
voiceSetPriority(svoice, prio);
|
|
}
|
|
|
|
static void mcmdSetPriority(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
voiceSetPriority(svoice, cstep->para[0] >> 8);
|
|
}
|
|
|
|
static void mcmdSendFlag(MSTEP* cstep) {
|
|
synthGlobalVariable[(u8)(cstep->para[0] >> 8)] = (u8)(cstep->para[0] >> 16);
|
|
}
|
|
|
|
static void mcmdSetPitchWheelRange(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->pbLowerKeyRange = (u8)(cstep->para[0] >> 0x10);
|
|
svoice->pbUpperKeyRange = (u8)(cstep->para[0] >> 8);
|
|
}
|
|
|
|
static u32 mcmdSetKey(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->curNote = (u8)(cstep->para[0] >> 8) & 0x7f;
|
|
svoice->curDetune = (s8)(cstep->para[0] >> 0x10);
|
|
if (voiceIsLastStarted(svoice) != 0) {
|
|
inpSetMidiLastNote(svoice->midi, svoice->midiSet, svoice->curNote & 0xff);
|
|
}
|
|
cstep->para[0] = 4;
|
|
return mcmdWait(svoice, cstep);
|
|
}
|
|
|
|
static u32 mcmdAddKey(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
if ((u8)(cstep->para[0] >> 0x18) == 0) {
|
|
svoice->curNote += (s8)(u8)(cstep->para[0] >> 8);
|
|
} else {
|
|
svoice->curNote = (u16)svoice->orgNote + (s16)(s8)(u8)(cstep->para[0] >> 8);
|
|
}
|
|
|
|
svoice->curNote = (s16)svoice->curNote < 0 ? 0 : svoice->curNote > 0x7f ? 0x7f : svoice->curNote;
|
|
svoice->curDetune = (s8)(cstep->para[0] >> 0x10);
|
|
|
|
if (voiceIsLastStarted(svoice) != 0) {
|
|
inpSetMidiLastNote(svoice->midi, svoice->midiSet, svoice->curNote);
|
|
}
|
|
cstep->para[0] = 4;
|
|
return mcmdWait(svoice, cstep);
|
|
}
|
|
|
|
static u32 mcmdLastKey(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->curNote = svoice->lastNote + (s8)(u8)(cstep->para[0] >> 8);
|
|
svoice->curNote = (s16)svoice->curNote < 0 ? 0 : svoice->curNote > 0x7f ? 0x7f : svoice->curNote;
|
|
svoice->curDetune = (s8)(cstep->para[0] >> 16);
|
|
if (svoice->midi != 0xFF) {
|
|
inpSetMidiLastNote(svoice->midi, svoice->midiSet, svoice->curNote);
|
|
}
|
|
cstep->para[0] = 4;
|
|
|
|
return mcmdWait(svoice, cstep);
|
|
}
|
|
|
|
static void mcmdStartSample(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
static SAMPLE_INFO newsmp;
|
|
u16 smp; // r28
|
|
smp = cstep->para[0] >> 8;
|
|
|
|
if (dataGetSample(smp, &newsmp) != 0) {
|
|
return;
|
|
}
|
|
switch ((u8)(cstep->para[0] >> 0x18)) {
|
|
case 0:
|
|
newsmp.offset = cstep->para[1];
|
|
break;
|
|
case 1:
|
|
newsmp.offset = ((u8)(0x7f - (svoice->volume >> 0x10)) * (u32)cstep->para[1]) / 0x7f;
|
|
;
|
|
break;
|
|
case 2:
|
|
newsmp.offset = ((u8)((svoice->volume >> 0x10)) * (u32)cstep->para[1]) / 0x7f;
|
|
break;
|
|
default:
|
|
newsmp.offset = 0;
|
|
break;
|
|
}
|
|
|
|
if (newsmp.offset >= newsmp.length) {
|
|
newsmp.offset = newsmp.length - 1;
|
|
}
|
|
|
|
hwInitSamplePlayback(svoice->id & 0xFF, smp, &newsmp, (svoice->cFlags & 0x100) == 0,
|
|
((u32)svoice->prio << 24) | ((u32)svoice->age >> 15), svoice->id,
|
|
(svoice->cFlags & 0x80000000000) == 0, svoice->itdMode);
|
|
|
|
svoice->sInfo = newsmp.info;
|
|
|
|
if (svoice->playFrq != -1) {
|
|
DoSetPitch(svoice);
|
|
}
|
|
svoice->cFlags |= 0x20;
|
|
synthKeyStateUpdate(svoice);
|
|
}
|
|
|
|
static void mcmdStopSample(SYNTH_VOICE* svoice) { hwBreak(svoice->id & 0xFF); }
|
|
static void mcmdKeyOff(SYNTH_VOICE* svoice) {
|
|
svoice->cFlags |= 0x80;
|
|
synthKeyStateUpdate(svoice);
|
|
}
|
|
|
|
static void mcmdSetMod2Vibrato(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->vibModAddScale = (s8)(cstep->para[0] >> 8) << 8;
|
|
if (svoice->vibModAddScale >= 0) {
|
|
svoice->vibModAddScale += ((s16)(s8)(cstep->para[0] >> 0x10) << 8) / 100;
|
|
|
|
} else {
|
|
svoice->vibModAddScale -= ((s16)(s8)(cstep->para[0] >> 0x10) << 8) / 100;
|
|
}
|
|
}
|
|
|
|
static void mcmdVibrato(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 time; // r1+0x10
|
|
s8 kr; // r29
|
|
s8 cr; // r30
|
|
|
|
if ((u8)(cstep->para[0] >> 0x18) & 3) {
|
|
svoice->cFlags |= 0x4000;
|
|
} else {
|
|
svoice->cFlags &= ~0x4000;
|
|
}
|
|
|
|
time = (u16)(cstep->para[1] >> 0x10);
|
|
if ((u8)(cstep->para[1] >> 8) & 1) {
|
|
sndConvertMs(&time);
|
|
} else {
|
|
sndConvertTicks(&time, svoice);
|
|
}
|
|
|
|
if (time) {
|
|
svoice->cFlags |= 0x2000;
|
|
svoice->vibPeriod = time;
|
|
|
|
kr = (s8)(cstep->para[0] >> 8);
|
|
cr = (s8)(cstep->para[0] >> 16);
|
|
|
|
if (kr < 0) {
|
|
if (cr < 0) {
|
|
svoice->vibCentRange = -cr;
|
|
} else {
|
|
svoice->vibCentRange = cr;
|
|
}
|
|
|
|
svoice->vibKeyRange = -kr;
|
|
svoice->vibCurTime = svoice->vibPeriod / 2;
|
|
} else {
|
|
if (cr < 0) {
|
|
if (kr == 0) {
|
|
svoice->vibCentRange = -cr;
|
|
svoice->vibCurTime = svoice->vibPeriod / 2;
|
|
} else {
|
|
--kr;
|
|
svoice->vibCentRange = 100 - cr;
|
|
svoice->vibCurTime = 0;
|
|
}
|
|
} else {
|
|
svoice->vibCentRange = cr;
|
|
svoice->vibCurTime = 0;
|
|
}
|
|
svoice->vibKeyRange = kr;
|
|
}
|
|
} else {
|
|
svoice->cFlags &= ~0x2000;
|
|
}
|
|
}
|
|
|
|
static void mcmdSetupLFO(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 time; // r1+0x14
|
|
u32 phase; // r1+0x10
|
|
u8 n; // r31
|
|
|
|
n = (u8)(cstep->para[0] >> 8);
|
|
time = (u16)(cstep->para[0] >> 0x10);
|
|
sndConvertMs(&time);
|
|
if (svoice->lfo[n].period != 0) {
|
|
phase = (u16)cstep->para[1];
|
|
sndConvertMs(&phase);
|
|
svoice->lfo[n].time = phase;
|
|
}
|
|
svoice->lfo[n].period = time;
|
|
}
|
|
|
|
#pragma dont_inline on
|
|
static void DoSetPitch(SYNTH_VOICE* svoice) {
|
|
u32 f; // r28
|
|
u32 of; // r25
|
|
u32 i; // r31
|
|
u32 frq; // r27
|
|
u32 ofrq; // r26
|
|
u32 no; // r30
|
|
s32 key; // r24
|
|
u8 oKey; // r23
|
|
static u16 kf[13] = {
|
|
4096, 4339, 4597, 4871, 5160, 5467, 5792, 6137, 6502, 6888, 7298, 7732, 8192,
|
|
};
|
|
|
|
frq = svoice->playFrq & 0xFFFFFF;
|
|
ofrq = svoice->sInfo & 0xFFFFFF;
|
|
|
|
if (ofrq == frq) {
|
|
svoice->curNote = svoice->sInfo >> 24;
|
|
} else if (ofrq < frq) {
|
|
f = (frq << 12) / ofrq;
|
|
for (no = 0; no < 11 && (1 << ((no + 1) & 0x3f)) < (f >> 12); ++no) {
|
|
}
|
|
|
|
f /= (1 << (no & 0x3f));
|
|
|
|
for (i = 11; f <= kf[i]; i--) {
|
|
}
|
|
|
|
svoice->curNote = (svoice->sInfo >> 24) + no * 12 + i;
|
|
svoice->curDetune = (no - kf[i]) * 100 / (kf[i + 1] - kf[i]);
|
|
}
|
|
}
|
|
#pragma dont_inline reset
|
|
|
|
static void mcmdSetPitch(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->playFrq = (u32)(cstep->para[0] >> 8);
|
|
svoice->playFrq |= (u8)cstep->para[1];
|
|
if (svoice->sInfo != -1) {
|
|
DoSetPitch(svoice);
|
|
}
|
|
}
|
|
|
|
#pragma dont_inline on
|
|
static void mcmdSetADSR(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
ADSR_INFO adsr; // r1+0x10
|
|
ADSR_INFO* adsr_ptr; // r31
|
|
s32 ascale; // r29
|
|
s32 dscale; // r28
|
|
float sScale; // r63
|
|
}
|
|
#pragma dont_inline reset
|
|
|
|
static s32 midi2TimeTab[128] = {
|
|
0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100, 110,
|
|
110, 120, 130, 140, 150, 160, 170, 190, 200, 220, 230, 250,
|
|
270, 290, 310, 330, 350, 380, 410, 440, 470, 500, 540, 580,
|
|
620, 660, 710, 760, 820, 880, 940, 1000, 1000, 1100, 1200, 1300,
|
|
1400, 1500, 1600, 1700, 1800, 2000, 2100, 2300, 2400, 2600, 2800, 3000,
|
|
3200, 3500, 3700, 4000, 4300, 4600, 4900, 5300, 5700, 6100, 6500, 7000,
|
|
7500, 8100, 8600, 9300, 9900, 10000, 11000, 12000, 13000, 14000, 15000, 16000,
|
|
17000, 18000, 19000, 21000, 22000, 24000, 26000, 28000, 30000, 32000, 34000, 37000,
|
|
39000, 42000, 45000, 49000, 50000, 55000, 60000, 65000, 70000, 75000, 80000, 85000,
|
|
90000, 95000, 100000, 105000, 110000, 115000, 120000, 125000, 130000, 135000, 140000, 145000,
|
|
150000, 155000, 160000, 165000, 170000, 175000, 180000, 0,
|
|
};
|
|
|
|
#pragma dont_inline on
|
|
static void mcmdSetADSRFromCtrl(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
float sScale; // r63
|
|
ADSR_INFO adsr; // r1+0x10
|
|
}
|
|
|
|
static void mcmdSetPitchADSR(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
ADSR_INFO adsr; // r1+0x10
|
|
ADSR_INFO* adsr_ptr; // r31
|
|
u32 sl; // r28
|
|
s32 ascale; // r27
|
|
s32 dscale; // r26
|
|
}
|
|
#pragma dont_inline reset
|
|
|
|
static u32 mcmdPitchSweep(SYNTH_VOICE* svoice, MSTEP* cstep, int num) {
|
|
s32 delta; // r31
|
|
svoice->sweepOff[num] = 0;
|
|
svoice->sweepNum[num] = (u8)(cstep->para[0] >> 8);
|
|
svoice->sweepCnt[num] = (s32)svoice->sweepNum[num] << 0x10;
|
|
delta = (int)(short)(cstep->para[0] >> 0x10);
|
|
if (delta >= 0) {
|
|
delta = hwFrq2Pitch(delta);
|
|
} else {
|
|
delta = -hwFrq2Pitch(-delta);
|
|
}
|
|
svoice->sweepAdd[num] = delta << 0x10;
|
|
cstep->para[0] = 0;
|
|
mcmdWait(svoice, cstep);
|
|
}
|
|
|
|
static void DoPanningSetup(SYNTH_VOICE* svoice, MSTEP* cstep, u8 pi) {
|
|
s32 width; // r29
|
|
u32 mstime; // r27
|
|
svoice->panTime[pi] = width = (u16)(cstep->para[0] >> 16);
|
|
sndConvertMs(&svoice->panTime[pi]);
|
|
mstime = (s8)(cstep->para[1]);
|
|
svoice->panning[pi] = ((u8)(cstep->para[0] >> 8)) << 16;
|
|
svoice->panTarget[pi] = svoice->panning[pi] + mstime * 0x10000;
|
|
if (svoice->panTime[pi] != 0) {
|
|
svoice->panDelta[pi] = (s32)(mstime << 16) / width;
|
|
} else {
|
|
svoice->panDelta[pi] = (s32)(mstime << 16);
|
|
}
|
|
|
|
svoice->cFlags |= 0x200000000000;
|
|
}
|
|
|
|
static void mcmdSetPanning(SYNTH_VOICE* svoice, MSTEP* cstep) { DoPanningSetup(svoice, cstep, 0); }
|
|
|
|
static void mcmdSetSurroundPanning(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
DoPanningSetup(svoice, cstep, 1);
|
|
}
|
|
|
|
static void mcmdSetPianoPanning(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
s32 delta; // r31
|
|
s32 scale; // r30
|
|
delta = (svoice->curNote << 16) - ((u8)(cstep->para[0] >> 16) << 16);
|
|
scale = (s8)((u8)(cstep->para[0] >> 8));
|
|
delta = ((delta * scale) >> 7);
|
|
delta += (u8)(cstep->para[0] >> 0x18) << 16;
|
|
delta = delta < 0 ? 0 : delta > 0x7f0000 ? 0x7f0000 : delta;
|
|
svoice->panTarget[0] = delta;
|
|
svoice->panning[0] = delta;
|
|
}
|
|
|
|
static u32 TranslateVolume(u32 volume, u16 curve) {
|
|
u8* ptr; // r30
|
|
u32 vlow; // r28
|
|
u32 vhigh; // r31
|
|
s32 d; // r27
|
|
|
|
if (curve != 0xFFFF) {
|
|
if ((ptr = (u8*)dataGetCurve(curve))) {
|
|
vhigh = (volume >> 16) & 0xFFFF;
|
|
vlow = volume & 0xFFFF;
|
|
|
|
if (vhigh < 0x7f) {
|
|
d = vlow * (ptr[vhigh + 1] - ptr[vhigh]);
|
|
#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 0)
|
|
volume = d + ((u16)ptr[vhigh] << 16);
|
|
#else
|
|
volume = d + (ptr[vhigh] << 16);
|
|
#endif
|
|
} else {
|
|
volume = ptr[vhigh] << 16;
|
|
}
|
|
}
|
|
}
|
|
|
|
return volume;
|
|
}
|
|
|
|
static void mcmdScaleVolume(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u16 curve; // r29
|
|
u16 scale; // r28
|
|
scale = (u16)(u8)(cstep->para[0] >> 8);
|
|
|
|
if ((u8)(cstep->para[1] >> 8) == 0) {
|
|
svoice->volume = (svoice->volume * scale) / 0x7f;
|
|
} else {
|
|
svoice->volume = (svoice->orgVolume * scale) / 0x7f;
|
|
}
|
|
#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 0)
|
|
svoice->volume += (u8)(cstep->para[0] >> 16) << 16;
|
|
#else
|
|
svoice->volume += EXTRACT_3RDNYBBLE(cstep->para[0]);
|
|
#endif
|
|
if (svoice->volume > 0x7f0000) {
|
|
svoice->volume = 0x7f0000;
|
|
}
|
|
|
|
curve = (u8)(cstep->para[0] >> 0x18);
|
|
curve |= ((u16)((u8)cstep->para[1]) << 8);
|
|
|
|
svoice->volume = TranslateVolume(svoice->volume, curve);
|
|
svoice->cFlags |= 0x100000000000;
|
|
}
|
|
|
|
static void mcmdScaleVolumeDLS(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u16 scale; // r31
|
|
|
|
scale = (cstep->para[0] >> 8);
|
|
if ((u8)(cstep->para[0] >> 0x18) == 0) {
|
|
svoice->volume = ((svoice->volume >> 5) * scale) >> 7;
|
|
} else {
|
|
svoice->volume = ((svoice->orgVolume >> 5) * scale) >> 7;
|
|
}
|
|
if (svoice->volume > 0x7f0000) {
|
|
svoice->volume = 0x7f0000;
|
|
}
|
|
|
|
svoice->cFlags |= 0x100000000000;
|
|
}
|
|
|
|
static void DoEnvelopeCalculation(SYNTH_VOICE* svoice, MSTEP* cstep, s32 start_vol) {
|
|
u32 tvol; // r31
|
|
u32 time; // r1+0x14
|
|
s32 mstime; // r28
|
|
u16 curve; // r27
|
|
|
|
time = (u16)(cstep->para[1] >> 16);
|
|
|
|
if ((u8)(cstep->para[1] >> 8) & 1) {
|
|
sndConvertMs(&time);
|
|
} else {
|
|
sndConvertTicks(&time, svoice);
|
|
}
|
|
|
|
mstime = sndConvert2Ms(time);
|
|
if (mstime == 0) {
|
|
mstime = 1;
|
|
}
|
|
|
|
tvol = (svoice->volume * (u8)(cstep->para[0] >> 8) >> 7);
|
|
tvol += (u8)(cstep->para[0] >> 16) << 16;
|
|
|
|
if (tvol > 0x7f0000) {
|
|
tvol = 0x7f0000;
|
|
}
|
|
|
|
curve = (u16)(u8)(cstep->para[0] >> 0x18);
|
|
curve |= (((u16)(u8)cstep->para[1]) << 8);
|
|
tvol = TranslateVolume(tvol, curve);
|
|
svoice->envTarget = tvol;
|
|
svoice->envCurrent = start_vol;
|
|
svoice->envDelta = (s32)(tvol - start_vol) / mstime;
|
|
svoice->volume = start_vol;
|
|
svoice->cFlags |= 0x8000;
|
|
}
|
|
|
|
static void mcmdEnvelope(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
DoEnvelopeCalculation(svoice, cstep, svoice->volume);
|
|
}
|
|
static void mcmdFadeIn(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
DoEnvelopeCalculation(svoice, cstep, 0);
|
|
}
|
|
|
|
#pragma dont_inline on
|
|
static void mcmdRandomKey(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u8 k1; // r30
|
|
u8 k2; // r29
|
|
u8 t; // r24
|
|
s32 i1; // r28
|
|
s32 i2; // r27
|
|
u8 detune; // r26
|
|
}
|
|
#pragma dont_inline reset
|
|
|
|
static void mcmdSetPitchbendAfterKeyOff(SYNTH_VOICE* svoice) { svoice->cFlags |= 0x10000; }
|
|
static void mcmdScaleReverb(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->revVolScale = (u8)(cstep->para[0] >> 8);
|
|
svoice->revVolOffset = (u8)(cstep->para[0] >> 0x10);
|
|
}
|
|
static void SelectSource(SYNTH_VOICE* svoice, CTRL_DEST* dest, MSTEP* cstep, u64 tstflag,
|
|
u32 dirtyFlag) {
|
|
u8 comb; // r28
|
|
s32 scale; // r30
|
|
|
|
if (!(svoice->cFlags & tstflag)) {
|
|
comb = 0;
|
|
svoice->cFlags |= tstflag;
|
|
} else {
|
|
comb = (u8)cstep->para[1];
|
|
}
|
|
|
|
scale = ((s16)(cstep->para[0] >> 16) << 16) / 100;
|
|
if (scale < 0) {
|
|
scale -= ((s8)(cstep->para[1] >> 0x10) << 8) / 100;
|
|
} else {
|
|
scale += ((s8)(cstep->para[1] >> 0x10) << 8) / 100;
|
|
}
|
|
|
|
inpAddCtrl(dest, (u8)(cstep->para[0] >> 8), scale, comb, (u8)(cstep->para[1] >> 8) != 0);
|
|
|
|
if ((dirtyFlag & 0x80000000) != 0) {
|
|
inpSetGlobalMIDIDirtyFlag(svoice->midi, svoice->midiSet, dirtyFlag);
|
|
} else {
|
|
svoice->midiDirtyFlags |= dirtyFlag;
|
|
}
|
|
}
|
|
|
|
static void mcmdVolumeSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpVolume, cstep, 0x80000, 1);
|
|
}
|
|
|
|
static void mcmdPanningSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpPanning, cstep, 0x100000, 2);
|
|
}
|
|
|
|
static void mcmdPitchWheelSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpPitchBend, cstep, 0x200000, 8);
|
|
}
|
|
|
|
static void mcmdModWheelSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpModulation, cstep, 0x400000, 0x20);
|
|
}
|
|
|
|
static void mcmdPedalSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpPedal, cstep, 0x2000000, 0x40);
|
|
}
|
|
|
|
static void mcmdPortamentoSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpPortamento, cstep, 0x1000000, 0x80);
|
|
}
|
|
|
|
static void mcmdReverbSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpReverb, cstep, 0x800000, 0x200);
|
|
}
|
|
|
|
static void mcmdPreAuxASelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpPreAuxA, cstep, 0x20000000, 0x100);
|
|
}
|
|
|
|
static void mcmdPreAuxBSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpPreAuxB, cstep, 0x40000000, 0x400);
|
|
}
|
|
|
|
static void mcmdPostAuxBSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpPostAuxB, cstep, 0x80000000, 0x800);
|
|
}
|
|
|
|
static void mcmdSurroundPanningSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpSurroundPanning, cstep, 0x4000000, 4);
|
|
}
|
|
|
|
static void mcmdDopplerSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpDoppler, cstep, 0x8000000, 0x10);
|
|
}
|
|
|
|
static void mcmdTremoloSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
SelectSource(svoice, &svoice->inpTremolo, cstep, 0x10000000, 0x1000);
|
|
}
|
|
|
|
static void mcmdAuxAFXSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 i; // r31
|
|
static u64 mask[4] = {0x100000000, 0x200000000, 0x400000000, 0x800000000}; // size: 0x20
|
|
static u32 dirty[4] = {0x80000001, 0x80000002, 0x80000004, 0x80000008}; // size: 0x10
|
|
i = (u8)(cstep->para[1] >> 0x18);
|
|
SelectSource(svoice, &inpAuxA[svoice->studio][i], cstep, mask[i], dirty[i]);
|
|
}
|
|
|
|
static void mcmdAuxBFXSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 i; // r31
|
|
static u64 mask[4] = {0x1000000000, 0x2000000000, 0x4000000000, 0x8000000000}; // size: 0x20
|
|
static u32 dirty[4] = {0x80000010, 0x80000020, 0x80000040, 0x80000080}; // size: 0x10
|
|
i = (u8)(cstep->para[1] >> 0x18);
|
|
SelectSource(svoice, &inpAuxB[svoice->studio][i], cstep, mask[i], dirty[i]);
|
|
}
|
|
|
|
static void mcmdPortamento(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 time; // r1+0x10
|
|
svoice->portType = cstep->para[0] >> 16;
|
|
time = (u16)(cstep->para[1] >> 16);
|
|
if (((u8)(cstep->para[1] >> 8) & 1)) {
|
|
sndConvertMs(&time);
|
|
} else {
|
|
sndConvertTicks(&time, svoice);
|
|
}
|
|
|
|
svoice->portDuration = time;
|
|
|
|
switch ((u8)(cstep->para[0] >> 8)) {
|
|
case 0:
|
|
if (svoice->midi != 0xFF) {
|
|
inpSetMidiCtrl(0x41, svoice->midi, svoice->midiSet, 0);
|
|
}
|
|
|
|
svoice->cFlags &= ~0x400;
|
|
return;
|
|
case 1:
|
|
if (svoice->midi != 0xFF) {
|
|
inpSetMidiCtrl(0x41, svoice->midi, svoice->midiSet, 0x7f);
|
|
}
|
|
init_port:
|
|
if (!(svoice->cFlags & 0x400)) {
|
|
synthInitPortamento(svoice);
|
|
}
|
|
svoice->cFlags |= 0x400;
|
|
break;
|
|
case 2:
|
|
if (svoice->midi != 0xFF && inpGetMidiCtrl(0x41, svoice->midi, svoice->midiSet) > 8064) {
|
|
goto init_port;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
s32 varGet32(SYNTH_VOICE* svoice, u32 ctrl, u8 index) {
|
|
if (ctrl != 0) {
|
|
return inpGetExCtrl(svoice, index);
|
|
}
|
|
|
|
index &= 0x1f;
|
|
return index < 16 ? svoice->local_vars[index] : synthGlobalVariable[index - 16];
|
|
}
|
|
|
|
s16 varGet(SYNTH_VOICE* svoice, u32 ctrl, u8 index) { return varGet32(svoice, ctrl, index); }
|
|
|
|
void varSet32(SYNTH_VOICE* svoice, u32 ctrl, u8 index, s32 v) {
|
|
if (ctrl != 0) {
|
|
inpSetExCtrl(svoice, index, v);
|
|
return;
|
|
}
|
|
index &= 0x1f;
|
|
|
|
if (index < 16) {
|
|
svoice->local_vars[index] = v;
|
|
return;
|
|
}
|
|
|
|
synthGlobalVariable[index - 16] = v;
|
|
}
|
|
void varSet(SYNTH_VOICE* svoice, u32 ctrl, u8 index, s16 v) { varSet32(svoice, ctrl, index, v); }
|
|
|
|
static void mcmdVarCalculation(SYNTH_VOICE* svoice, MSTEP* cstep, u8 op) {
|
|
s16 s1; // r28
|
|
s16 s2; // r31
|
|
s32 t; // r30
|
|
|
|
s1 = varGet(svoice, (u8)(cstep->para[0] >> 24), cstep->para[1]);
|
|
if (op == 4) {
|
|
s2 = cstep->para[1] >> 8;
|
|
} else {
|
|
s2 = varGet(svoice, (u8)(cstep->para[1] >> 8), cstep->para[1] >> 16);
|
|
}
|
|
switch (op) {
|
|
case 4:
|
|
case 0:
|
|
t = (s1 + s2);
|
|
break;
|
|
case 1:
|
|
t = (s1 - s2);
|
|
break;
|
|
case 2:
|
|
t = (s1 * s2);
|
|
break;
|
|
case 3:
|
|
if (s2 != 0) {
|
|
t = (s1 / s2);
|
|
} else {
|
|
t = 0;
|
|
}
|
|
break;
|
|
}
|
|
|
|
varSet(svoice, (u8)(cstep->para[0] >> 8), (u8)(cstep->para[0] >> 0x10),
|
|
(t < -0x8000 ? -0x8000
|
|
: t > 0x7FFF ? 0x7FFF
|
|
: t));
|
|
}
|
|
|
|
static void mcmdSetVarImmediate(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
varSet(svoice, (u8)(cstep->para[0] >> 8), (u8)(cstep->para[0] >> 0x10), (s16)cstep->para[1]);
|
|
}
|
|
|
|
static void mcmdIfVarCompare(SYNTH_VOICE* svoice, MSTEP* cstep, u8 cmp) {
|
|
s32 a; // r28
|
|
s32 b; // r27
|
|
u8 result; // r30
|
|
|
|
a = varGet32(svoice, (u8)(cstep->para[0] >> 8), (u8)(cstep->para[0] >> 0x10));
|
|
b = varGet32(svoice, (u8)(cstep->para[0] >> 0x18), (u8)cstep->para[1]);
|
|
|
|
switch (cmp) {
|
|
case 0:
|
|
result = (u16) !(b - a);
|
|
break;
|
|
case 1:
|
|
result = (a < b);
|
|
break;
|
|
}
|
|
|
|
if ((u8)(cstep->para[1] >> 8) != 0) {
|
|
result = !result;
|
|
}
|
|
if ((u8)result != 0) {
|
|
svoice->curAddr = svoice->addr + (u16)(cstep->para[1] >> 0x10);
|
|
}
|
|
}
|
|
u32 macPostMessage(u32 vid, s32 mesg) {
|
|
SYNTH_VOICE* sv; // r31
|
|
if ((vid = vidGetInternalId(vid)) != -1 && (sv = &synthVoice[vid & 0xFF])->mesgNum < 4) {
|
|
++sv->mesgNum;
|
|
sv->mesgQueue[sv->mesgWrite] = mesg;
|
|
sv->mesgWrite = (sv->mesgWrite + 1) & 3;
|
|
ExecuteTrap(sv, 2);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static void mcmdSendMessage(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u8 i; // r31
|
|
s32 mesg; // r30
|
|
u16 macro; // r28
|
|
|
|
mesg = varGet32(svoice, 0, (u8)(cstep->para[1] >> 8));
|
|
|
|
if (!(u8)(cstep->para[0] >> 8)) {
|
|
macro = (u16)(cstep->para[0] >> 16);
|
|
if (macro != 0xFFFF) {
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
if (synthVoice[i].addr != NULL && macro == synthVoice[i].macroId) {
|
|
macPostMessage(synthVoice[i].vidList->vid, mesg);
|
|
}
|
|
}
|
|
} else if (synthMessageCallback != NULL) {
|
|
synthMessageCallback(svoice->vidList->vid, mesg);
|
|
}
|
|
} else {
|
|
macPostMessage(varGet32(svoice, 0, (u8)cstep->para[1]), mesg);
|
|
}
|
|
}
|
|
|
|
static void mcmdGetMessage(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
s32 mesg; // r30
|
|
mesg = 0;
|
|
if (svoice->mesgNum != '\0') {
|
|
mesg = svoice->mesgQueue[svoice->mesgRead];
|
|
svoice->mesgRead = (svoice->mesgRead + 1) & 3;
|
|
--svoice->mesgNum;
|
|
}
|
|
varSet32(svoice, 0, (u8)(cstep->para[0] >> 8), mesg);
|
|
}
|
|
|
|
static void mcmdGetVID(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
if ((u8)(cstep->para[0] >> 0x10) == 0) {
|
|
varSet32(svoice, 0, (u8)(cstep->para[0] >> 8), svoice->vidList->vid);
|
|
} else {
|
|
varSet32(svoice, 0, (u8)(cstep->para[0] >> 8), svoice->lastVID);
|
|
}
|
|
}
|
|
static void mcmdModeSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->volTable = (u8)(cstep->para[0] >> 8) ? TRUE : FALSE;
|
|
svoice->itdMode = (u8)(cstep->para[0] >> 0x10) ? FALSE : TRUE;
|
|
}
|
|
static void mcmdSRCModeSelect(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
hwSetSRCType(svoice->id & 0xff, (u8)(cstep->para[0] >> 8));
|
|
hwSetPolyPhaseFilter(svoice->id & 0xff, (u8)(cstep->para[0] >> 0x10));
|
|
svoice->cFlags |= 0x80000000000;
|
|
}
|
|
static void mcmdSetKeyGroup(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
u32 i; // r31
|
|
u8 kg; // r30
|
|
u32 kill; // r29
|
|
|
|
svoice->keyGroup = 0;
|
|
kg = (u8)(cstep->para[0] >> 8);
|
|
kill = (u8)(cstep->para[0] >> 0x10) != 0;
|
|
|
|
if (kg) {
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
if (synthVoice[i].addr != NULL && (synthVoice[i].cFlags & 0x2) == 0 &&
|
|
kg == synthVoice[i].keyGroup) {
|
|
if (!kill) {
|
|
macSetExternalKeyoff(&synthVoice[i]);
|
|
} else {
|
|
voiceKill(i);
|
|
}
|
|
}
|
|
}
|
|
svoice->keyGroup = kg;
|
|
}
|
|
}
|
|
static void mcmdSetupTremolo(SYNTH_VOICE* svoice, MSTEP* cstep) {
|
|
svoice->treScale = (cstep->para[0] >> 8);
|
|
svoice->treModAddScale = cstep->para[1];
|
|
svoice->treCurScale = 1.f;
|
|
}
|
|
|
|
static void macHandleActive(SYNTH_VOICE* svoice) {
|
|
static MSTEP cstep;
|
|
u8 i; // r29
|
|
u8 lastNote; // r27
|
|
u32 ex; // r30
|
|
CHANNEL_DEFAULTS* channelDefaults; // r28
|
|
|
|
if (svoice->cFlags & 3) {
|
|
if (svoice->cFlags & 1) {
|
|
svoice->cFlags &= ~1;
|
|
hwBreak(svoice->id & 0xFF);
|
|
}
|
|
|
|
svoice->panning[0] = svoice->panTarget[0] = (u32)(svoice->setup.pan) << 16;
|
|
svoice->panning[1] = svoice->panTarget[1] = 0;
|
|
svoice->volume = (u32)(svoice->setup.vol << 16);
|
|
svoice->volTable = 0;
|
|
svoice->orgVolume = svoice->volume;
|
|
svoice->midi = svoice->setup.midi;
|
|
svoice->midiSet = svoice->setup.midiSet;
|
|
svoice->section = svoice->setup.section;
|
|
svoice->track = svoice->setup.track;
|
|
svoice->itdMode = svoice->setup.itdMode;
|
|
svoice->keyGroup = 0;
|
|
svoice->vibModAddScale = 0;
|
|
svoice->treScale = 0;
|
|
inpInit(svoice);
|
|
if ((lastNote = inpGetMidiLastNote(svoice->midi, svoice->midiSet)) != 0xFF) {
|
|
svoice->lastNote = lastNote;
|
|
} else {
|
|
svoice->lastNote = svoice->orgNote;
|
|
}
|
|
|
|
inpSetMidiLastNote(svoice->midi, svoice->midiSet, svoice->orgNote);
|
|
voiceSetLastStarted(svoice);
|
|
svoice->vGroup = svoice->setup.vGroup;
|
|
svoice->studio = svoice->setup.studio;
|
|
svoice->portTime = 0;
|
|
svoice->portDuration = 25600;
|
|
svoice->portType = 0;
|
|
if (svoice->midi != 0xff) {
|
|
svoice->portLastCtrlState = inpGetMidiCtrl(65, svoice->midi, svoice->midiSet);
|
|
} else {
|
|
svoice->portLastCtrlState = 0;
|
|
}
|
|
channelDefaults = inpGetChannelDefaults(svoice->midi, svoice->midiSet);
|
|
svoice->pbLowerKeyRange = channelDefaults->pbRange;
|
|
svoice->pbUpperKeyRange = channelDefaults->pbRange;
|
|
svoice->revVolScale = 128;
|
|
svoice->revVolOffset = 0;
|
|
svoice->loop = 0;
|
|
svoice->sweepNum[0] = 0;
|
|
svoice->sweepNum[1] = 0;
|
|
svoice->sweepOff[0] = 0;
|
|
svoice->sweepOff[1] = 0;
|
|
svoice->lfo[0].period = 0;
|
|
svoice->lfo[0].value = 0;
|
|
svoice->lfo[0].lastValue = 0x7fff;
|
|
svoice->lfo[1].period = 0;
|
|
svoice->lfo[1].value = 0;
|
|
svoice->lfo[1].lastValue = 0x7fff;
|
|
|
|
for (i = 0; i < 3; ++i) {
|
|
svoice->trapEventAddr[i] = NULL;
|
|
}
|
|
|
|
svoice->trapEventAny = 0;
|
|
svoice->sInfo = -1;
|
|
svoice->playFrq = -1;
|
|
svoice->pbLast = 0x2000;
|
|
svoice->curOutputVolume = 0;
|
|
svoice->cFlags &= 8;
|
|
svoice->cFlags |= 0x300000000000;
|
|
memset(svoice->local_vars, 0, sizeof(svoice->local_vars));
|
|
svoice->waitTime = macRealTime;
|
|
svoice->macStartTime = macRealTime;
|
|
synthStartSynthJobHandling(svoice);
|
|
}
|
|
|
|
DebugMacroSteps = 0;
|
|
|
|
do {
|
|
if (++DebugMacroSteps > 32) {
|
|
break;
|
|
}
|
|
|
|
cstep.para[0] = svoice->curAddr->para[0];
|
|
cstep.para[1] = svoice->curAddr->para[1];
|
|
++svoice->curAddr;
|
|
ex = 0;
|
|
switch (cstep.para[0] & 0x7f) {
|
|
case 0x0:
|
|
ex = mcmdEndOfMacro(svoice);
|
|
break;
|
|
case 0x1:
|
|
ex = mcmdStop(svoice);
|
|
break;
|
|
case 0x2:
|
|
mcmdIfKey(svoice, &cstep);
|
|
break;
|
|
case 0x3:
|
|
mcmdIfVelocity(svoice, &cstep);
|
|
break;
|
|
case 0x4:
|
|
ex = mcmdWait(svoice, &cstep);
|
|
break;
|
|
case 0x5:
|
|
mcmdLoop(svoice, &cstep);
|
|
break;
|
|
case 0x6:
|
|
ex = mcmdGoto(svoice, &cstep);
|
|
break;
|
|
case 0x7:
|
|
ex = mcmdWaitMs(svoice, &cstep);
|
|
break;
|
|
case 0x8:
|
|
mcmdPlayMacro(svoice, &cstep);
|
|
break;
|
|
case 0x9:
|
|
mcmdSendKeyOff(svoice, &cstep);
|
|
break;
|
|
case 0xa:
|
|
mcmdIfModulation(svoice, &cstep);
|
|
break;
|
|
case 0xb:
|
|
mcmdSetPianoPanning(svoice, &cstep);
|
|
break;
|
|
case 0xc:
|
|
mcmdSetADSR(svoice, &cstep);
|
|
break;
|
|
case 0xd:
|
|
mcmdScaleVolume(svoice, &cstep);
|
|
break;
|
|
case 0xe:
|
|
mcmdSetPanning(svoice, &cstep);
|
|
break;
|
|
case 0xf:
|
|
mcmdEnvelope(svoice, &cstep);
|
|
break;
|
|
case 0x10:
|
|
mcmdStartSample(svoice, &cstep);
|
|
break;
|
|
case 0x11:
|
|
mcmdStopSample(svoice);
|
|
break;
|
|
case 0x12:
|
|
mcmdKeyOff(svoice);
|
|
break;
|
|
case 0x13:
|
|
mcmdIfRandom(svoice, &cstep);
|
|
break;
|
|
case 0x14:
|
|
mcmdFadeIn(svoice, &cstep);
|
|
break;
|
|
case 0x15:
|
|
mcmdSetSurroundPanning(svoice, &cstep);
|
|
break;
|
|
case 0x16:
|
|
mcmdSetADSRFromCtrl(svoice, &cstep);
|
|
break;
|
|
case 0x17:
|
|
mcmdRandomKey(svoice, &cstep);
|
|
break;
|
|
case 0x18:
|
|
ex = mcmdAddKey(svoice, &cstep);
|
|
break;
|
|
case 0x19:
|
|
ex = mcmdSetKey(svoice, &cstep);
|
|
break;
|
|
case 0x1a:
|
|
ex = mcmdLastKey(svoice, &cstep);
|
|
break;
|
|
case 0x1b:
|
|
mcmdPortamento(svoice, &cstep);
|
|
break;
|
|
case 0x1c:
|
|
mcmdVibrato(svoice, &cstep);
|
|
break;
|
|
case 0x1d:
|
|
ex = mcmdPitchSweep(svoice, &cstep, 0);
|
|
break;
|
|
case 0x1e:
|
|
ex = mcmdPitchSweep(svoice, &cstep, 1);
|
|
break;
|
|
case 0x1f:
|
|
mcmdSetPitch(svoice, &cstep);
|
|
break;
|
|
case 0x20:
|
|
mcmdSetPitchADSR(svoice, &cstep);
|
|
break;
|
|
case 0x21:
|
|
mcmdScaleVolumeDLS(svoice, &cstep);
|
|
break;
|
|
case 0x22:
|
|
mcmdSetMod2Vibrato(svoice, &cstep);
|
|
break;
|
|
case 0x23:
|
|
mcmdSetupTremolo(svoice, &cstep);
|
|
break;
|
|
case 0x24:
|
|
mcmdReturn(svoice);
|
|
break;
|
|
case 0x25:
|
|
ex = mcmdGosub(svoice, &cstep);
|
|
break;
|
|
case 0x28:
|
|
mcmdTrapEvent(svoice, &cstep);
|
|
break;
|
|
case 0x29:
|
|
mcmdUntrapEvent(svoice, &cstep);
|
|
break;
|
|
case 0x2a:
|
|
mcmdSendMessage(svoice, &cstep);
|
|
break;
|
|
case 0x2b:
|
|
mcmdGetMessage(svoice, &cstep);
|
|
break;
|
|
case 0x2c:
|
|
mcmdGetVID(svoice, &cstep);
|
|
break;
|
|
case 0x30:
|
|
mcmdAddAgeCounter(svoice, &cstep);
|
|
break;
|
|
case 0x31:
|
|
mcmdSetAgeCounter(svoice, &cstep);
|
|
break;
|
|
case 0x32:
|
|
mcmdSendFlag(&cstep);
|
|
break;
|
|
case 0x33:
|
|
mcmdSetPitchWheelRange(svoice, &cstep);
|
|
break;
|
|
case 0x34:
|
|
mcmdScaleReverb(svoice, &cstep);
|
|
break;
|
|
case 0x35:
|
|
mcmdSetPitchbendAfterKeyOff(svoice);
|
|
break;
|
|
case 0x36:
|
|
mcmdSetPriority(svoice, &cstep);
|
|
break;
|
|
case 0x37:
|
|
mcmdAddPriority(svoice, &cstep);
|
|
break;
|
|
case 0x38:
|
|
mcmdSetAgeCounterSpeed(svoice, &cstep);
|
|
break;
|
|
case 0x39:
|
|
mcmdSetAgeCounterByVolume(svoice, &cstep);
|
|
break;
|
|
case 0x40:
|
|
mcmdVolumeSelect(svoice, &cstep);
|
|
break;
|
|
case 0x41:
|
|
mcmdPanningSelect(svoice, &cstep);
|
|
break;
|
|
case 0x42:
|
|
mcmdPitchWheelSelect(svoice, &cstep);
|
|
break;
|
|
case 0x43:
|
|
mcmdModWheelSelect(svoice, &cstep);
|
|
break;
|
|
case 0x44:
|
|
mcmdPedalSelect(svoice, &cstep);
|
|
break;
|
|
case 0x45:
|
|
mcmdPortamentoSelect(svoice, &cstep);
|
|
break;
|
|
case 0x46:
|
|
mcmdReverbSelect(svoice, &cstep);
|
|
break;
|
|
case 0x47:
|
|
mcmdSurroundPanningSelect(svoice, &cstep);
|
|
break;
|
|
case 0x48:
|
|
mcmdDopplerSelect(svoice, &cstep);
|
|
break;
|
|
case 0x49:
|
|
mcmdTremoloSelect(svoice, &cstep);
|
|
break;
|
|
case 0x4a:
|
|
mcmdPreAuxASelect(svoice, &cstep);
|
|
break;
|
|
case 0x4b:
|
|
mcmdPreAuxBSelect(svoice, &cstep);
|
|
break;
|
|
case 0x4c:
|
|
mcmdPostAuxBSelect(svoice, &cstep);
|
|
break;
|
|
case 0x4d:
|
|
mcmdAuxAFXSelect(svoice, &cstep);
|
|
break;
|
|
case 0x4e:
|
|
mcmdAuxBFXSelect(svoice, &cstep);
|
|
break;
|
|
case 0x50:
|
|
mcmdSetupLFO(svoice, &cstep);
|
|
break;
|
|
case 0x58:
|
|
mcmdModeSelect(svoice, &cstep);
|
|
break;
|
|
case 0x59:
|
|
mcmdSetKeyGroup(svoice, &cstep);
|
|
break;
|
|
case 0x5a:
|
|
mcmdSRCModeSelect(svoice, &cstep);
|
|
break;
|
|
case 0x60:
|
|
mcmdVarCalculation(svoice, &cstep, 0);
|
|
break;
|
|
case 0x61:
|
|
mcmdVarCalculation(svoice, &cstep, 1);
|
|
break;
|
|
case 0x62:
|
|
mcmdVarCalculation(svoice, &cstep, 2);
|
|
break;
|
|
case 0x63:
|
|
mcmdVarCalculation(svoice, &cstep, 3);
|
|
break;
|
|
case 0x64:
|
|
mcmdVarCalculation(svoice, &cstep, 4);
|
|
break;
|
|
case 0x65:
|
|
mcmdSetVarImmediate(svoice, &cstep);
|
|
break;
|
|
case 0x70:
|
|
mcmdIfVarCompare(svoice, &cstep, 0);
|
|
break;
|
|
case 0x71:
|
|
mcmdIfVarCompare(svoice, &cstep, 1);
|
|
}
|
|
} while (!ex);
|
|
}
|
|
|
|
void macHandle(u32 deltaTime) {
|
|
SYNTH_VOICE* sv; // r31
|
|
SYNTH_VOICE* nextSv; // r30
|
|
u64 w; // r28
|
|
|
|
for (sv = macTimeQueueRoot; sv != NULL && sv->wait <= macRealTime;) {
|
|
nextSv = sv->nextTimeQueueMacro;
|
|
w = sv->wait;
|
|
macMakeActive(sv);
|
|
sv->waitTime = w;
|
|
sv = nextSv;
|
|
}
|
|
|
|
sv = macActiveMacroRoot;
|
|
for (; sv != NULL; sv = sv->nextMacActive) {
|
|
if (HasHWEventTrap(sv) != 0) {
|
|
CheckHWEventTrap(sv);
|
|
}
|
|
|
|
macHandleActive(sv);
|
|
}
|
|
macRealTime += deltaTime;
|
|
}
|
|
|
|
void macSampleEndNotify(SYNTH_VOICE* sv) {
|
|
if (sv->macState != MAC_STATE_YIELDED) {
|
|
return;
|
|
}
|
|
/* clang-format off */
|
|
MUSY_ASSERT(sv->addr!=NULL);
|
|
/* clang-format on */
|
|
|
|
if (!ExecuteTrap(sv, 1) && (sv->cFlags & 0x40000)) {
|
|
macMakeActive(sv);
|
|
}
|
|
}
|
|
void macSetExternalKeyoff(SYNTH_VOICE* sv) {
|
|
sv->cFlags |= 8;
|
|
if (!sv->addr) {
|
|
return;
|
|
}
|
|
|
|
if (!(sv->cFlags & 0x10000000000)) {
|
|
if (!ExecuteTrap(sv, 0) && (sv->cFlags & 0x4)) {
|
|
macMakeActive(sv);
|
|
}
|
|
} else {
|
|
sv->cFlags |= 0x40000000000;
|
|
}
|
|
}
|
|
|
|
void macSetPedalState(SYNTH_VOICE* svoice, u32 state) {
|
|
if (state != 0) {
|
|
svoice->cFlags |= 0x10000000000;
|
|
} else {
|
|
if (svoice->addr && (svoice->cFlags & 0x40000000000)) {
|
|
if (!ExecuteTrap(svoice, 0) && (svoice->cFlags & 0x4)) {
|
|
macMakeActive(svoice);
|
|
}
|
|
}
|
|
|
|
svoice->cFlags &= ~(0x10000000000 | 0x40000000000);
|
|
}
|
|
}
|
|
|
|
static void TimeQueueAdd(SYNTH_VOICE* svoice) {
|
|
SYNTH_VOICE* sv; // r31
|
|
SYNTH_VOICE* lastSv; // r30
|
|
|
|
lastSv = NULL;
|
|
for (sv = macTimeQueueRoot; sv != NULL && sv->wait < svoice->wait;) {
|
|
lastSv = sv;
|
|
sv = sv->nextTimeQueueMacro;
|
|
}
|
|
|
|
if (sv == NULL) {
|
|
if (lastSv == NULL) {
|
|
macTimeQueueRoot = svoice;
|
|
svoice->nextTimeQueueMacro = NULL;
|
|
svoice->prevTimeQueueMacro = NULL;
|
|
} else {
|
|
lastSv->nextTimeQueueMacro = svoice;
|
|
svoice->prevTimeQueueMacro = lastSv;
|
|
svoice->nextTimeQueueMacro = NULL;
|
|
}
|
|
} else {
|
|
svoice->nextTimeQueueMacro = sv;
|
|
if (svoice->prevTimeQueueMacro = sv->prevTimeQueueMacro) {
|
|
sv->prevTimeQueueMacro->nextTimeQueueMacro = svoice;
|
|
} else {
|
|
macTimeQueueRoot = svoice;
|
|
}
|
|
sv->prevTimeQueueMacro = svoice;
|
|
}
|
|
}
|
|
static void UnYieldMacro(SYNTH_VOICE* svoice, u32 disableUpdate) {
|
|
if (svoice->wait != 0) {
|
|
if (svoice->wait != -1) {
|
|
if (svoice->prevTimeQueueMacro == NULL) {
|
|
macTimeQueueRoot = svoice->nextTimeQueueMacro;
|
|
} else {
|
|
svoice->prevTimeQueueMacro->nextTimeQueueMacro = svoice->nextTimeQueueMacro;
|
|
}
|
|
|
|
if (svoice->nextTimeQueueMacro) {
|
|
svoice->nextTimeQueueMacro->prevTimeQueueMacro = svoice->prevTimeQueueMacro;
|
|
}
|
|
}
|
|
|
|
if (!disableUpdate) {
|
|
synthForceLowPrecisionUpdate(svoice);
|
|
}
|
|
|
|
svoice->wait = 0;
|
|
svoice->waitTime = macRealTime;
|
|
svoice->cFlags &= ~0x40004;
|
|
}
|
|
}
|
|
void macMakeActive(SYNTH_VOICE* sv) {
|
|
if (sv->macState == MAC_STATE_RUNNABLE) {
|
|
return;
|
|
}
|
|
/* clang-format off */
|
|
MUSY_ASSERT(sv->addr!=NULL);
|
|
/* clang-format on */
|
|
UnYieldMacro(sv, 0);
|
|
if (sv->nextMacActive = macActiveMacroRoot) {
|
|
macActiveMacroRoot->prevMacActive = sv;
|
|
}
|
|
sv->prevMacActive = NULL;
|
|
macActiveMacroRoot = sv;
|
|
sv->macState = MAC_STATE_RUNNABLE;
|
|
}
|
|
|
|
void macMakeInactive(SYNTH_VOICE* svoice, MAC_STATE newState) {
|
|
if (svoice->macState == newState) {
|
|
return;
|
|
}
|
|
|
|
/* clang-format off */
|
|
MUSY_ASSERT(svoice->addr!=NULL);
|
|
/* clang-format on */
|
|
if (svoice->macState == MAC_STATE_RUNNABLE) {
|
|
if (svoice->prevMacActive == NULL) {
|
|
macActiveMacroRoot = svoice->nextMacActive;
|
|
} else {
|
|
svoice->prevMacActive->nextMacActive = svoice->nextMacActive;
|
|
}
|
|
|
|
if (svoice->nextMacActive != NULL) {
|
|
svoice->nextMacActive->prevMacActive = svoice->prevMacActive;
|
|
}
|
|
}
|
|
|
|
if (newState == MAC_STATE_STOPPED) {
|
|
UnYieldMacro(svoice, 1);
|
|
}
|
|
svoice->macState = newState;
|
|
}
|
|
|
|
u32 macStart(u16 macid, u8 priority, u8 maxVoices, u16 allocId, u8 key, u8 vol, u8 panning, u8 midi,
|
|
u8 midiSet, u8 section, u16 step, u16 trackid, u8 new_vid, u8 vGroup, u8 studio,
|
|
u32 itd) {
|
|
u32 voice; // r30
|
|
u32 vid; // r25
|
|
MSTEP* addr; // r28
|
|
SYNTH_VOICE* svoice; // r31
|
|
u16 seqPrio; // r24
|
|
|
|
if ((addr = dataGetMacro(macid))) {
|
|
if (!(key & 0x80) && (seqPrio = seqGetMIDIPriority(midiSet, midi)) != 0xFFFF) {
|
|
priority = seqPrio;
|
|
}
|
|
|
|
if ((voice = voiceAllocate(priority, maxVoices, allocId, (key & 0x80) ? 1 : 0)) != -1) {
|
|
svoice = &synthVoice[voice];
|
|
vidRemoveVoiceReferences(svoice);
|
|
macMakeInactive(svoice, MAC_STATE_STOPPED);
|
|
svoice->cFlags = (svoice->cFlags & 0x10) | 2;
|
|
|
|
if (hwIsActive(voice)) {
|
|
svoice->cFlags |= 1;
|
|
}
|
|
|
|
svoice->wait = 0;
|
|
|
|
if ((key & 0x80) != 0) {
|
|
svoice->fxFlag = 01;
|
|
key &= 0x7f;
|
|
inpResetMidiCtrl(voice, 0xff, 1);
|
|
inpResetChannelDefaults(voice, 0xff);
|
|
svoice->setup.midi = voice;
|
|
svoice->setup.midiSet = 0xff;
|
|
svoice->setup.section = 0;
|
|
} else {
|
|
svoice->fxFlag = 0;
|
|
svoice->setup.midi = midi;
|
|
svoice->setup.midiSet = midiSet;
|
|
svoice->setup.section = section;
|
|
}
|
|
|
|
svoice->macroId = macid;
|
|
svoice->allocId = allocId;
|
|
svoice->age = 0x75300000;
|
|
svoice->ageSpeed = 0x400;
|
|
svoice->addr = addr;
|
|
svoice->curAddr = addr + step;
|
|
svoice->orgNote = key;
|
|
svoice->curNote = key;
|
|
svoice->curDetune = 0;
|
|
svoice->setup.vol = vol;
|
|
svoice->setup.pan = panning;
|
|
svoice->setup.track = trackid;
|
|
svoice->callStackEntryNum = 0;
|
|
svoice->callStackIndex = 0;
|
|
svoice->child = -1;
|
|
svoice->parent = -1;
|
|
svoice->lastVID = -1;
|
|
svoice->setup.vGroup = vGroup;
|
|
svoice->setup.studio = studio;
|
|
svoice->setup.itdMode = itd != 0 ? 0 : 1;
|
|
svoice->mesgNum = svoice->mesgRead = svoice->mesgWrite = 0;
|
|
svoice->id = voice | ((macid << 16) | (key << 8));
|
|
voiceSetPriority(svoice, priority);
|
|
|
|
if ((vid = vidMakeNew(svoice, new_vid)) != -1) {
|
|
macMakeActive(svoice);
|
|
return vid;
|
|
}
|
|
|
|
if (hwIsActive(voice)) {
|
|
hwBreak(voice);
|
|
}
|
|
|
|
voiceFree(svoice);
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void macInit() {
|
|
u32 i; // r31
|
|
|
|
macActiveMacroRoot = 0;
|
|
macTimeQueueRoot = 0;
|
|
macRealTime = 0;
|
|
for (i = 0; i < synthInfo.voiceNum; ++i) {
|
|
synthVoice[i].addr = NULL;
|
|
synthVoice[i].macState = MAC_STATE_STOPPED;
|
|
synthVoice[i].loop = 0;
|
|
}
|
|
}
|