prime/src/musyx/runtime/synthmacros.c

1777 lines
47 KiB
C

#include "musyx/musyx_priv.h"
#include "musyx/seq.h"
#include "musyx/synth.h"
static u8 DebugMacroSteps = 0;
static SYNTH_VOICE* macActiveMacroRoot = NULL;
static SYNTH_VOICE* macTimeQueueRoot = NULL;
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);
/*
This may look like a fakematch, however this actually makes sense if you break it down:
1) Shift right to clear bottom 2 nybbles;
2) Shift left to put the moved nybbles back to their original location
3) Mask off the top nybble leaving only 3rd nybble
So taking 0x1234567 as an example the logic looks something like this
1) 0x12345678 >> 16 == 0x00001234
2) 0x00001234 << 16 == 0x12340000
3) 0x12340000 & 0x00FFFFFF == 0x00340000
This behavior could also be matched with a simple mask
0x12345678 & 0x00FF0000 == 0x00340000
But on PPC with CodeWarrior this just produces an improper load:
`
lwz r0,0(r29)
rlwinm r0,r0,0,8,0xf
`
Instead of the expected
`
lwz r3,0(r29)
rlwinm r0,r3,0,8,0xf
`
Note the use of r3 instead of r0
*/
#define EXTRACT_3RDNYBBLE(v) (((v >> 16) << 16) & 0x00FFFFFF)
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
#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 0)
delta = (svoice->curNote - (u8)(cstep->para[0] >> 16)) << 16;
scale = (s8)((cstep->para[0] >> 8) & 0xFF);
#else
delta = (svoice->curNote << 16) - EXTRACT_3RDNYBBLE(cstep->para[0]);
scale = (s8)((u8)(cstep->para[0] >> 8));
#endif
delta = ((delta * scale) >> 7);
delta += (u8)(cstep->para[0] >> 0x18) << 16;
svoice->panning[0] = svoice->panTarget[0] = delta < 0 ? 0 : delta > 0x7f0000 ? 0x7f0000 : 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 = (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 += EXTRACT_3RDNYBBLE(cstep->para[0]);
if (tvol > 0x7f0000) {
tvol = 0x7f0000;
}
curve = (u16)(u8)(cstep->para[0] >> 0x18);
curve |= (((u16)(u8)cstep->para[1]) << 8) & 0xFFFF00;
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 = (s32)(cstep->para[0] & 0xFFFF0000) / 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 = 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 = 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 = 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;
if (index < 16) {
return svoice->local_vars[index];
}
return 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 = 0; // r28
s16 s2 = 0; // r31
s32 t; // r30
s1 = varGet(svoice, (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;
}
}