Files
dusklight/libs/dolphin/src/syn/synctrl.c
T
Luke Street 4df8ccc871 Reorganize library code into libs/ (#3119)
* Reorganize files into libs/{dolphin,JSystem,PowerPC_EABI_Support,revolution,TRK_MINNOW_DOLPHIN}

* Update configure.py and project.py for new libs structure

* Refactor `#include <dolphin/x.h>` -> `<x.h>`

* Remove `__REVOLUTION_SDK__` forwards from dolphin

* Fix dolphin/ references in revolution

* Wrap `#include <dolphin.h>` in `!__REVOLUTION_SDK__`

* Always build TRK against dolphin headers

* Resolve revolution SDK header resolution issues
2026-03-01 14:35:36 -08:00

511 lines
13 KiB
C

#include <dolphin/dolphin.h>
#include <dolphin/ax.h>
#include <dolphin/mix.h>
#include <dolphin/syn.h>
#include "sdk_math.h"
#include "__syn.h"
f32 __SYNn128[128] = {
0.000000f,
0.007813f,
0.015625f,
0.023438f,
0.031250f,
0.039063f,
0.046875f,
0.054688f,
0.062500f,
0.070313f,
0.078125f,
0.085938f,
0.093750f,
0.101563f,
0.109375f,
0.117188f,
0.125000f,
0.132813f,
0.140625f,
0.148438f,
0.156250f,
0.164063f,
0.171875f,
0.179688f,
0.187500f,
0.195313f,
0.203125f,
0.210938f,
0.218750f,
0.226563f,
0.234375f,
0.242188f,
0.250000f,
0.257813f,
0.265625f,
0.273438f,
0.281250f,
0.289063f,
0.296875f,
0.304688f,
0.312500f,
0.320313f,
0.328125f,
0.335938f,
0.343750f,
0.351563f,
0.359375f,
0.367188f,
0.375000f,
0.382813f,
0.390625f,
0.398438f,
0.406250f,
0.414063f,
0.421875f,
0.429688f,
0.437500f,
0.445313f,
0.453125f,
0.460938f,
0.468750f,
0.476563f,
0.484375f,
0.492188f,
0.500000f,
0.507813f,
0.515625f,
0.523438f,
0.531250f,
0.539063f,
0.546875f,
0.554688f,
0.562500f,
0.570313f,
0.578125f,
0.585938f,
0.593750f,
0.601563f,
0.609375f,
0.617188f,
0.625000f,
0.632813f,
0.640625f,
0.648438f,
0.656250f,
0.664063f,
0.671875f,
0.679688f,
0.687500f,
0.695313f,
0.703125f,
0.710938f,
0.718750f,
0.726563f,
0.734375f,
0.742188f,
0.750000f,
0.757813f,
0.765625f,
0.773438f,
0.781250f,
0.789063f,
0.796875f,
0.804688f,
0.812500f,
0.820313f,
0.828125f,
0.835938f,
0.843750f,
0.851563f,
0.859375f,
0.867188f,
0.875000f,
0.882813f,
0.890625f,
0.898438f,
0.906250f,
0.914063f,
0.921875f,
0.929688f,
0.937500f,
0.945313f,
0.953125f,
0.960938f,
0.968750f,
0.976563f,
0.984375f,
0.992188f
};
// prototypes
static void __SYNSetData(SYNSYNTH* synth, u8 midiChannel);
static void __SYNSetSustainPedal(SYNSYNTH* synth, u8 midiChannel, u8 data);
static void __SYNProgramChange(SYNSYNTH* synth, u8 midiChannel, u8 program);
static void __SYNReleaseChannelNotes(SYNSYNTH* synth, u8 midiChannel);
static void __SYNNoteOff(SYNSYNTH* synth, u8 midiChannel, u8 keyNum);
static void __SYNNoteOn(SYNSYNTH* synth, u8 midiChannel, u8 keyNum, u8 keyVel);
static void __SYNPitchWheel(SYNSYNTH* synth, u8 midiChannel, u8 lsb, u8 msb);
static void __SYNMidiIn(SYNSYNTH* synth, u8* input);
static void __SYNSetData(SYNSYNTH* synth, u8 midiChannel) {
ASSERTLINE(59, synth);
ASSERTLINE(60, midiChannel < 16);
if (synth->rpn[midiChannel]) {
u16 param = (synth->controller[midiChannel][0x65] << 8) + synth->controller[midiChannel][0x64];
switch(param) {
case 0:
synth->pwMaxCents[midiChannel] = (synth->controller[midiChannel][0x26] + (synth->controller[midiChannel][0x6] * 100)) << 0x10;
break;
case 1:
ASSERTMSGLINE(80, FALSE, "RPN 0001 not supported\n");
break;
case 2:
ASSERTMSGLINE(86, FALSE, "RPN 0002 not supported\n");
break;
case 3:
ASSERTMSGLINE(92, FALSE, "RPN 0003 not supported\n");
break;
case 4:
ASSERTMSGLINE(98, FALSE, "RPN 0004 not supported\n");
break;
}
}
}
static void __SYNSetSustainPedal(SYNSYNTH* synth, u8 midiChannel, u8 data) {
int i;
SYNVOICE* voice;
ASSERTLINE(111, synth);
ASSERTLINE(112, midiChannel < 16);
ASSERTLINE(113, data < 128);
// check if you're below 0x80 only to check if you're below 0x40. ok then.
if (data < 64) {
for (i = 0; i < 128; i++) {
voice = synth->voice[midiChannel][i];
if (voice && voice->hold) {
__SYNSetVoiceToRelease(voice, synth->priorityNoteRelease);
voice->synth->voice[voice->midiChannel][voice->keyNum] = 0;
}
}
}
}
static void __SYNProgramChange(SYNSYNTH* synth, u8 midiChannel, u8 program) {
ASSERTLINE(142, synth);
ASSERTLINE(143, midiChannel < 16);
ASSERTLINE(144, program < 128);
if (midiChannel == 9) {
synth->inst[midiChannel] = synth->percussiveInst;
} else {
synth->inst[midiChannel] = synth->melodicInst;
}
synth->inst[midiChannel] += program;
}
static void __SYNReleaseChannelNotes(SYNSYNTH* synth, u8 midiChannel) {
int i;
SYNVOICE* voice;
ASSERTLINE(162, synth);
ASSERTLINE(163, midiChannel < 16);
for (i = 0; i < 128; i++) {
voice = synth->voice[midiChannel][i];
if (voice) {
__SYNSetVoiceToRelease(voice, synth->priorityNoteRelease);
synth->voice[midiChannel][i] = 0;
}
}
}
void __SYNClearAllNotes(SYNSYNTH* synth) {
u8 i;
ASSERTLINE(189, synth);
for (i = 0; i < 16; i++) {
__SYNReleaseChannelNotes(synth, i);
}
}
void __SYNSetController(SYNSYNTH* synth, u8 midiChannel, u8 function, u8 value) {
ASSERTLINE(201, synth);
ASSERTLINE(202, midiChannel < 16);
ASSERTLINE(203, function < 128);
ASSERTLINE(204, value < 128);
synth->controller[midiChannel][function] = value;
switch(function) {
case 6:
__SYNSetData(synth, midiChannel);
break;
case 7:
synth->volAttn[midiChannel] = __SYNVolumeAttenuation[value];
break;
case 11:
synth->expAttn[midiChannel] = __SYNVolumeAttenuation[value];
break;
case 0x26:
__SYNSetData(synth, midiChannel);
break;
case 0x40:
__SYNSetSustainPedal(synth, midiChannel, value);
break;
case 0x5B:
synth->auxAAttn[midiChannel] = __SYNVolumeAttenuation[value];
break;
case 0x5C:
synth->auxBAttn[midiChannel] = __SYNVolumeAttenuation[value];
break;
case 0x5D:
break;
case 0x62:
case 0x63:
synth->rpn[midiChannel] = 0;
break;
case 0x64:
case 0x65:
synth->rpn[midiChannel] = 1;
break;
case 0x78:
__SYNReleaseChannelNotes(synth, midiChannel);
break;
case 0x79:
if (value == 0) {
__SYNResetController0(synth, midiChannel);
} else {
__SYNResetController(synth, midiChannel);
}
break;
case 0x7B:
case 0x7C:
case 0x7D:
case 0x7E:
case 0x7F:
__SYNReleaseChannelNotes(synth, midiChannel);
break;
default:
break;
}
}
void __SYNResetController0(SYNSYNTH* synth, u8 midiChannel) {
u8 volume;
u8 pan;
u8 expression;
int i;
ASSERTLINE(315, synth);
ASSERTLINE(316, midiChannel < 16);
synth->pwMaxCents[midiChannel] = 0xC80000;
synth->pwCents[midiChannel] = 0;
volume = synth->controller[midiChannel][7];
pan = synth->controller[midiChannel][10];
expression = synth->controller[midiChannel][11];
for (i = 0; i < 128; i++) {
synth->controller[midiChannel][i] = 0;
}
__SYNSetController(synth, midiChannel, 7, volume);
__SYNSetController(synth, midiChannel, 0xA, pan);
__SYNSetController(synth, midiChannel, 0xB, expression);
__SYNSetController(synth, midiChannel, 0x5B, 0);
__SYNSetController(synth, midiChannel, 0x5C, 0);
}
void __SYNResetController(SYNSYNTH* synth, u8 midiChannel) {
int i;
ASSERTLINE(345, synth);
ASSERTLINE(346, midiChannel < 16);
synth->pwMaxCents[midiChannel] = 0xC80000;
synth->pwCents[midiChannel] = 0;
for (i = 0; i < 128; i++) {
synth->controller[midiChannel][i] = 0;
}
__SYNSetController(synth, midiChannel, 7, 0x64);
__SYNSetController(synth, midiChannel, 0xA, 0x40);
__SYNSetController(synth, midiChannel, 0xB, 0x7F);
__SYNSetController(synth, midiChannel, 0x5B, 0);
__SYNSetController(synth, midiChannel, 0x5C, 0);
}
void __SYNResetAllControllers(SYNSYNTH* synth) {
u8 midiChannel;
ASSERTLINE(372, synth);
for (midiChannel = 0; midiChannel < 16; midiChannel++) {
__SYNProgramChange(synth, midiChannel, 0);
__SYNResetController(synth, midiChannel);
}
}
static void __SYNNoteOff(SYNSYNTH* synth, u8 midiChannel, u8 keyNum) {
SYNVOICE* voice;
ASSERTLINE(389, synth);
ASSERTLINE(390, midiChannel < 16);
ASSERTLINE(391, keyNum < 128);
voice = synth->voice[midiChannel][keyNum];
if (voice) {
if (synth->controller[midiChannel][64] > 64) {
voice->hold = 1;
return;
}
__SYNSetVoiceToRelease(voice, synth->priorityNoteRelease);
synth->voice[midiChannel][keyNum] = 0;
}
}
static void __SYNNoteOn(SYNSYNTH* synth, u8 midiChannel, u8 keyNum, u8 keyVel) {
AXVPB* axvpb;
SYNVOICE* voice;
SYNVOICE* oldVoice;
ASSERTLINE(420, synth);
ASSERTLINE(421, midiChannel < 16);
ASSERTLINE(422, keyNum < 128);
ASSERTLINE(423, keyVel < 128);
if (keyVel) {
if (synth->voice[midiChannel][keyNum]) {
__SYNSetVoiceToRelease(synth->voice[midiChannel][keyNum], synth->priorityNoteRelease);
synth->voice[midiChannel][keyNum] = 0;
}
axvpb = AXAcquireVoice(synth->priorityVoiceAlloc, &__SYNClearVoiceReferences, (u32)synth);
if (axvpb) {
voice = &__SYNVoice[axvpb->index];
voice->axvpb = axvpb;
voice->synth = synth;
voice->midiChannel = midiChannel;
voice->keyNum = keyNum;
voice->keyVel = keyVel;
voice->hold = 0;
if (__SYNGetWavetableData(voice) != 0) {
synth->voice[midiChannel][keyNum] = voice;
synth->notes++;
voice->keyGroup = voice->region->keyGroup;
if (voice->keyGroup != 0) {
oldVoice = synth->keyGroup[midiChannel][voice->keyGroup];
if (oldVoice) {
oldVoice->synth = 0;
MIXReleaseChannel(oldVoice->axvpb);
AXFreeVoice(oldVoice->axvpb);
synth->voice[midiChannel][oldVoice->keyNum] = 0;
synth->notes--;
}
synth->keyGroup[midiChannel][voice->keyGroup] = voice;
}
__SYNSetupPitch(voice);
__SYNSetupVolume(voice);
__SYNSetupPan(voice);
__SYNSetupLfo(voice);
__SYNSetupVolumeEnvelope(voice);
__SYNSetupPitchEnvelope(voice);
if (midiChannel == 9) {
MIXInitChannel(axvpb, 0, __SYNGetVoiceInput(voice), synth->auxAAttn[midiChannel] >> 0x10, synth->auxBAttn[midiChannel] >> 0x10, voice->pan, 0x7F, __SYNGetVoiceFader(voice));
} else {
MIXInitChannel(axvpb, 0, __SYNGetVoiceInput(voice), synth->auxAAttn[midiChannel] >> 0x10, synth->auxBAttn[midiChannel] >> 0x10, synth->controller[midiChannel][10], 0x7F, __SYNGetVoiceFader(voice));
}
__SYNSetupSample(voice);
__SYNSetupSrc(voice);
axvpb->pb.state = 1;
axvpb->sync = (axvpb->sync | 4);
AXSetVoicePriority(axvpb, synth->priorityNoteOn);
return;
}
voice->synth = NULL;
MIXReleaseChannel(axvpb);
AXFreeVoice(axvpb);
}
} else {
__SYNNoteOff(synth, midiChannel, keyNum);
}
}
static void __SYNPitchWheel(SYNSYNTH* synth, u8 midiChannel, u8 lsb, u8 msb) {
s32 position;
ASSERTLINE(565, synth);
ASSERTLINE(566, midiChannel < 16);
ASSERTLINE(567, lsb < 128);
ASSERTLINE(568, msb < 128);
position = lsb + (msb << 7) - 0x2000;
synth->pwCents[midiChannel] = (synth->pwMaxCents[midiChannel] * ((f32)position / 8192.0f));
}
static void __SYNMidiIn(SYNSYNTH* synth, u8* input) {
u8* ch;
u8 midiFunction;
u8 midiChannel;
u8 _2ndByte;
u8 _3rdByte;
ASSERTLINE(589, synth);
ASSERTLINE(590, input);
ch = input;
midiFunction = (*(ch) >> 4); ch += 0;
midiChannel = (*(ch) & 0xF); ch += 1;
_2ndByte = *(ch); ch += 1;
switch(midiFunction) {
case 8:
__SYNNoteOff(synth, midiChannel, _2ndByte);
return;
case 9:
_3rdByte = *(ch); ch += 1;
__SYNNoteOn(synth, midiChannel, _2ndByte, _3rdByte);
return;
case 11:
_3rdByte = *(ch); ch += 1;
__SYNSetController(synth, midiChannel, _2ndByte, _3rdByte);
return;
case 12:
__SYNProgramChange(synth, midiChannel, _2ndByte);
return;
case 14:
_3rdByte = *(ch); ch+=1;
__SYNPitchWheel(synth, midiChannel, _2ndByte, _3rdByte);
return;
}
}
void __SYNRunInputBufferEvents(SYNSYNTH* synth) {
u8* input;
for (input = &synth->input[0][0]; synth->inputCounter; synth->inputCounter--) {
__SYNMidiIn(synth, input);
input+=3;
}
synth->inputPosition = &synth->input[0][0];
}
u8 SYNGetMidiController(SYNSYNTH* synth, u8 midiChannel, u8 function) {
ASSERTLINE(678, synth);
ASSERTLINE(679, midiChannel < 16);
ASSERTLINE(680, function < 128);
return synth->controller[midiChannel][function];
}