mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-06-08 19:49:32 -04:00
4df8ccc871
* 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
511 lines
13 KiB
C
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];
|
|
}
|