diff --git a/asm/musyx/runtime/snd_midictrl.s b/asm/musyx/runtime/snd_midictrl.s index 17483260..fd996ade 100644 --- a/asm/musyx/runtime/snd_midictrl.s +++ b/asm/musyx/runtime/snd_midictrl.s @@ -2,42 +2,56 @@ .section .bss .balign 8 -inpGlobalMIDIDirtyFlags: +.obj inpGlobalMIDIDirtyFlags, local .skip 0x200 -midi_ctrl: +.endobj inpGlobalMIDIDirtyFlags + +.obj midi_ctrl, local .skip 0x4300 -inpChannelDefaults: +.endobj midi_ctrl + +.obj inpChannelDefaults, local .skip 0x80 -fx_ctrl: +.endobj inpChannelDefaults + +.obj fx_ctrl, local .skip 0x2180 -inpFXChannelDefaults: +.endobj fx_ctrl + +.obj inpFXChannelDefaults, local .skip 0x40 -midi_lastNote: +.endobj inpFXChannelDefaults + +.obj midi_lastNote, local .skip 0x80 -fx_lastNote: +.endobj midi_lastNote + +.obj fx_lastNote, local .skip 0x40 +.endobj fx_lastNote .section .data, "wa" .balign 8 -.global lbl_803F41E8 -lbl_803F41E8: +.obj lbl_803F41E8, local # ROM: 0x3F11E8 .4byte 0x80000001 .4byte 0x80000002 .4byte 0x80000004 .4byte 0x80000008 +.endobj lbl_803F41E8 -lbl_803F41F8: +.obj lbl_803F41F8, local # ROM: 0x3F11F8 .4byte 0x80000010 .4byte 0x80000020 .4byte 0x80000040 .4byte 0x80000080 +.endobj lbl_803F41F8 -lbl_803F4208: +.obj lbl_803F4208, local # ROM: 0x3F1208 .4byte lbl_803B2A78 .4byte lbl_803B2A80 @@ -48,9 +62,9 @@ lbl_803F4208: .4byte lbl_803B2AA8 .4byte lbl_803B2AB0 .4byte lbl_803B2AB8 +.endobj lbl_803F4208 - -lbl_803F422C: +.obj lbl_803F422C, local # ROM: 0x3F122C .4byte lbl_803B2AF8 .4byte lbl_803B2B00 @@ -61,9 +75,10 @@ lbl_803F422C: .4byte lbl_803B2B28 .4byte lbl_803B2B30 .4byte lbl_803B2B38 +.endobj lbl_803F422C -lbl_803F4250: +.obj lbl_803F4250, local .4byte lbl_803B2C2C .4byte lbl_803B2C34 .4byte lbl_803B2C3C @@ -73,12 +88,13 @@ lbl_803F4250: .4byte lbl_803B2C5C .4byte lbl_803B2C64 .4byte lbl_803B2C6C -.skip 4 +.endobj lbl_803F4250 + .section .rodata .balign 8 -.global lbl_803D8AC0 -lbl_803D8AC0: + +.obj inpColdMIDIDefaults, local # ROM: 0x3D5AC0 .4byte 0 .4byte 0x0000007F @@ -112,11 +128,18 @@ lbl_803D8AC0: .4byte 0 .4byte 0 .4byte 0 - .float 2.0 - .float 2.0 + .byte 0x40 + .byte 0x00 + .byte 0x00 + .byte 0x00 + .byte 0x40 + .byte 0x00 + .byte 0x00 + .byte 0x00 -.global lbl_803D8B48 -lbl_803D8B48: +.endobj inpColdMIDIDefaults + +.obj inpWarmMIDIDefaults, local # ROM: 0x3D5B48 .4byte 0xFF00FFFF .4byte 0xFFFFFFFF @@ -152,8 +175,7 @@ lbl_803D8B48: .4byte 0xFFFFFFFF .4byte 0x40FFFFFF .4byte 0xFFFF0000 - - +.endobj inpWarmMIDIDefaults .section .text, "ax" @@ -692,17 +714,17 @@ lbl_803B17FC: inpResetMidiCtrl: /* 803B181C 003AE77C 94 21 FF F0 */ stwu r1, -0x10(r1) /* 803B1820 003AE780 7C 08 02 A6 */ mflr r0 -/* 803B1824 003AE784 3C C0 80 3E */ lis r6, lbl_803D8B48@ha +/* 803B1824 003AE784 3C C0 80 3E */ lis r6, inpWarmMIDIDefaults@ha /* 803B1828 003AE788 28 05 00 00 */ cmplwi r5, 0 /* 803B182C 003AE78C 90 01 00 14 */ stw r0, 0x14(r1) -/* 803B1830 003AE790 38 C6 8B 48 */ addi r6, r6, lbl_803D8B48@l +/* 803B1830 003AE790 38 C6 8B 48 */ addi r6, r6, inpWarmMIDIDefaults@l /* 803B1834 003AE794 93 E1 00 0C */ stw r31, 0xc(r1) /* 803B1838 003AE798 7C 9F 23 78 */ mr r31, r4 /* 803B183C 003AE79C 93 C1 00 08 */ stw r30, 8(r1) /* 803B1840 003AE7A0 7C 7E 1B 78 */ mr r30, r3 /* 803B1844 003AE7A4 41 82 00 0C */ beq lbl_803B1850 -/* 803B1848 003AE7A8 3C 60 80 3E */ lis r3, lbl_803D8AC0@ha -/* 803B184C 003AE7AC 38 C3 8A C0 */ addi r6, r3, lbl_803D8AC0@l +/* 803B1848 003AE7A8 3C 60 80 3E */ lis r3, inpColdMIDIDefaults@ha +/* 803B184C 003AE7AC 38 C3 8A C0 */ addi r6, r3, inpColdMIDIDefaults@l lbl_803B1850: /* 803B1850 003AE7B0 57 E4 06 3E */ clrlwi r4, r31, 0x18 /* 803B1854 003AE7B4 28 04 00 FF */ cmplwi r4, 0xff @@ -1783,8 +1805,8 @@ lbl_803B2654: /* 803B265C 003AF5BC 38 21 00 10 */ addi r1, r1, 0x10 /* 803B2660 003AF5C0 4E 80 00 20 */ blr -.global inpGetAuxB -inpGetAuxB: +.global inpGetAuxA +inpGetAuxA: /* 803B2664 003AF5C4 94 21 FF F0 */ stwu r1, -0x10(r1) /* 803B2668 003AF5C8 7C 08 02 A6 */ mflr r0 /* 803B266C 003AF5CC 3C E0 80 56 */ lis r7, inpGlobalMIDIDirtyFlags@ha @@ -1834,8 +1856,8 @@ lbl_803B2708: /* 803B2710 003AF670 38 21 00 10 */ addi r1, r1, 0x10 /* 803B2714 003AF674 4E 80 00 20 */ blr -.global inpGetAuxA -inpGetAuxA: +.global inpGetAuxB +inpGetAuxB: /* 803B2718 003AF678 94 21 FF F0 */ stwu r1, -0x10(r1) /* 803B271C 003AF67C 7C 08 02 A6 */ mflr r0 /* 803B2720 003AF680 3C E0 80 56 */ lis r7, inpGlobalMIDIDirtyFlags@ha diff --git a/asm/musyx/runtime/synth.s b/asm/musyx/runtime/synth.s index acb2d44e..643f03e3 100644 --- a/asm/musyx/runtime/synth.s +++ b/asm/musyx/runtime/synth.s @@ -2594,7 +2594,7 @@ lbl_8039AF24: /* 8039AF28 00397E88 56 83 06 3E */ clrlwi r3, r20, 0x18 /* 8039AF2C 00397E8C 88 DC 00 00 */ lbz r6, 0(r28) /* 8039AF30 00397E90 56 A4 06 3E */ clrlwi r4, r21, 0x18 -/* 8039AF34 00397E94 48 01 77 31 */ bl inpGetAuxB +/* 8039AF34 00397E94 48 01 77 31 */ bl inpGetAuxA /* 8039AF38 00397E98 3A B5 00 01 */ addi r21, r21, 1 /* 8039AF3C 00397E9C B0 7A 00 00 */ sth r3, 0(r26) /* 8039AF40 00397EA0 28 15 00 04 */ cmplwi r21, 4 @@ -2617,7 +2617,7 @@ lbl_8039AF78: /* 8039AF7C 00397EDC 56 83 06 3E */ clrlwi r3, r20, 0x18 /* 8039AF80 00397EE0 88 D8 00 00 */ lbz r6, 0(r24) /* 8039AF84 00397EE4 56 A4 06 3E */ clrlwi r4, r21, 0x18 -/* 8039AF88 00397EE8 48 01 77 91 */ bl inpGetAuxA +/* 8039AF88 00397EE8 48 01 77 91 */ bl inpGetAuxB /* 8039AF8C 00397EEC 3A B5 00 01 */ addi r21, r21, 1 /* 8039AF90 00397EF0 B0 7A 00 00 */ sth r3, 0(r26) /* 8039AF94 00397EF4 28 15 00 04 */ cmplwi r21, 4 diff --git a/include/musyx/musyx_priv.h b/include/musyx/musyx_priv.h index c2e8de04..5f9b7cd0 100644 --- a/include/musyx/musyx_priv.h +++ b/include/musyx/musyx_priv.h @@ -899,6 +899,7 @@ void voiceSetPriority(struct SYNTH_VOICE* svoice, unsigned char prio); u32 voiceIsLastStarted(struct SYNTH_VOICE* svoice); s32 voiceKillSound(u32 voiceid); +extern u64 synthRealTime; u32 synthGetTicksPerSecond(SYNTH_VOICE* svoice); void synthKillVoicesByMacroReferences(u16* ref); void synthExit(); @@ -915,6 +916,7 @@ u32 hwIsActive(u32); u32 hwGlobalActivity(); void hwSetAUXProcessingCallbacks(unsigned char studio, SND_AUX_CALLBACK auxA, void* userA, SND_AUX_CALLBACK auxB, void* userB); +s16 varGet(SYNTH_VOICE* svoice, u32 ctrl, u8 index); u32 sndGetPitch(u8 key, u32 sInfo); extern SND_HOOKS salHooks; @@ -971,6 +973,7 @@ typedef struct SND_STREAM_INFO { } SND_STREAM_INFO; void streamOutputModeChanged(); +u8 inpTranslateExCtrl(unsigned char ctrl); void inpSetGlobalMIDIDirtyFlag(u8 chan, u8 midiSet, s32 flag); void inpAddCtrl(struct CTRL_DEST* dest, unsigned char ctrl, long scale, unsigned char comb, unsigned long isVar); diff --git a/src/musyx/runtime/snd_midictrl.c b/src/musyx/runtime/snd_midictrl.c index 81e9dd22..dcc350a0 100644 --- a/src/musyx/runtime/snd_midictrl.c +++ b/src/musyx/runtime/snd_midictrl.c @@ -1,25 +1,53 @@ +/* + + + + + + + + + + + + + + + +*/ + #include "musyx/musyx_priv.h" #define SYNTH_FX_MIDISET 0xFF -typedef struct CHANNEL_DEFAULTS { - unsigned char pbRange; -} CHANNEL_DEFAULTS; +static u8 midi_lastNote[8][16]; static u8 fx_lastNote[64]; -static u8 midi_lastNote[8][16]; -static CHANNEL_DEFAULTS inpFXChannelDefaults[64]; -static u8 fx_ctrl[64][134]; -static CHANNEL_DEFAULTS inpChannelDefaults[8][16]; + static u8 midi_ctrl[8][16][134]; + +static u8 fx_ctrl[64][134]; + static u32 inpGlobalMIDIDirtyFlags[8][16]; +static CHANNEL_DEFAULTS inpChannelDefaults[8][16]; + +static CHANNEL_DEFAULTS inpFXChannelDefaults[64]; + inline bool GetGlobalFlagSet(u8 chan, u8 midiSet, s32 flag) { return (flag & inpGlobalMIDIDirtyFlags[midiSet][chan]) != 0; } -void inpResetGlobalMIDIDirtyFlags() { +/* + + + + + + +*/ +static void inpResetGlobalMIDIDirtyFlags() { u32 i, j; for (i = 0; i < 8; ++i) { for (j = 0; j < 16; ++j) { @@ -28,64 +56,590 @@ void inpResetGlobalMIDIDirtyFlags() { } } -bool inpResetGlobalMIDIDirtyFlag(u8 chan, u8 midiSet, s32 flag) { - // MUSY_ASSERT(midiSet!=SYNTH_FX_MIDISET); - bool ret = GetGlobalFlagSet(chan, midiSet, flag); - if (ret) { +static u32 inpResetGlobalMIDIDirtyFlag(u8 chan, u8 midiSet, u32 flag) { + u32 ret; + // clang-format off + MUSY_ASSERT(midiSet!=SYNTH_FX_MIDISET); + // clang-format on + if ((ret = GetGlobalFlagSet(chan, midiSet, flag))) { inpGlobalMIDIDirtyFlags[midiSet][chan] &= ~flag; } return ret; } void inpSetGlobalMIDIDirtyFlag(u8 chan, u8 midiSet, s32 flag) { - // MUSY_ASSERT(midiSet!=SYNTH_FX_MIDISET); + // clang-format off + MUSY_ASSERT(midiSet!=SYNTH_FX_MIDISET); + // clang-format on inpGlobalMIDIDirtyFlags[midiSet][chan] |= flag; } void inpSetRPNHi(u8 set, u8 channel, u8 value) { - u16 rpn; // r28 - u32 i; // r31 - u8 range; // r29 - - if ((midi_ctrl[set][channel][100] | midi_ctrl[set][channel][101]) != 0) { - return; - } + u16 rpn; // r28 + u32 i; // r31 + u8 range; // r29 - inpChannelDefaults[set][channel].pbRange = value; + rpn = (midi_ctrl[set][channel][100]) | (midi_ctrl[set][channel][101] << 8); + switch (rpn) { + case 0: + range = value > 24 ? 24 : value; + inpChannelDefaults[set][channel].pbRange = range; - for (i = 0; i < synthInfo.voiceNum; ++i) { - if (set != synthVoice[i].midiSet || channel != synthVoice[i].midi){ - continue; + for (i = 0; i < synthInfo.voiceNum; ++i) { + if (set == synthVoice[i].midiSet && channel == synthVoice[i].midi) { + synthVoice[i].pbUpperKeyRange = range; + synthVoice[i].pbLowerKeyRange = range; + } } - synthVoice[i].pbUpperKeyRange = value; - synthVoice[i].pbLowerKeyRange = value; + break; + default: + break; } } -void inpSetRPNLo(u8 a, u8 b, u8 c) {} +void inpSetRPNLo(u8 set, u8 channel, u8 value) {} -void inpSetRPNDec(u8 a, u8 b) {} +void inpSetRPNDec(u8 set, u8 channel) { + u16 rpn; // r28 + u32 i; // r31 + u8 range; // r30 -void inpSetRPNInc(u8 a, u8 b) {} + rpn = (midi_ctrl[set][channel][100]) | (midi_ctrl[set][channel][101] << 8); + switch (rpn) { + case 0: + range = inpChannelDefaults[set][channel].pbRange; + if (range != 0) { + --range; + } + inpChannelDefaults[set][channel].pbRange = range; + for (i = 0; i < synthInfo.voiceNum; ++i) { + if (set == synthVoice[i].midiSet && channel == synthVoice[i].midi) { + synthVoice[i].pbUpperKeyRange = range; + synthVoice[i].pbLowerKeyRange = range; + } + } + break; + default: + break; + } +} + +void inpSetRPNInc(u8 set, u8 channel) { + u16 rpn; // r28 + u32 i; // r31 + u8 range; // r30 + + rpn = (midi_ctrl[set][channel][100]) | (midi_ctrl[set][channel][101] << 8); + switch (rpn) { + case 0: + range = inpChannelDefaults[set][channel].pbRange; + if (range < 24) { + ++range; + } + + inpChannelDefaults[set][channel].pbRange = range; + for (i = 0; i < synthInfo.voiceNum; ++i) { + if (set == synthVoice[i].midiSet && channel == synthVoice[i].midi) { + synthVoice[i].pbUpperKeyRange = range; + synthVoice[i].pbLowerKeyRange = range; + } + } + break; + default: + break; + } +} void inpSetMidiCtrl(u8 ctrl, u8 channel, u8 set, u8 value) { - u32 i; + u32 i; if (channel == 0xFF) { return; } if (set != 0xFF) { - switch(ctrl) { - case 38: - inpSetRPNInc(0xFF, channel); - break; - case 97: - inpSetRPNInc(0xFF, channel); - break; - case 6: - inpSetRPNHi(0xff, channel, value); - break; + switch (ctrl) { + case 6: + inpSetRPNHi(set, channel, value); + break; + case 38: + inpSetRPNLo(set, channel, value); + break; + case 96: + inpSetRPNDec(set, channel); + break; + case 97: + inpSetRPNInc(set, channel); + break; } + + midi_ctrl[set][channel][ctrl] = value & 0x7f; + for (i = 0; i < synthInfo.voiceNum; ++i) { + if (set == synthVoice[i].midiSet && channel == synthVoice[i].midi) { + synthVoice[i].midiDirtyFlags = 0x1fff; + synthKeyStateUpdate(&synthVoice[i]); + } + } + inpGlobalMIDIDirtyFlags[set][channel] = 0xff; + } else { + switch (ctrl) { + case 6: + inpSetRPNHi(set, channel, value); + break; + case 38: + inpSetRPNLo(set, channel, value); + break; + case 96: + inpSetRPNDec(set, channel); + break; + case 97: + inpSetRPNInc(set, channel); + break; + } + + fx_ctrl[channel][ctrl] = value & 0x7f; + for (i = 0; i < synthInfo.voiceNum; ++i) { + if (set == synthVoice[i].midiSet && channel == synthVoice[i].midi) { + synthVoice[i].midiDirtyFlags = 0x1fff; + synthKeyStateUpdate(&synthVoice[i]); + } + } + } +} + +void inpSetMidiCtrl14(u8 ctrl, u8 channel, u8 set, u16 value) { + + if (channel == 0xFF) { + return; + } + + if (ctrl < 64) { + inpSetMidiCtrl(ctrl & 31, channel, set, value >> 7); + inpSetMidiCtrl((ctrl & 31) + 32, channel, set, value & 0x7f); + } else if (ctrl == 128 || ctrl == 129) { + inpSetMidiCtrl(ctrl & 254, channel, set, value >> 7); + inpSetMidiCtrl((ctrl & 254) + 1, channel, set, value & 0x7f); + } else if (ctrl == 132 || ctrl == 133) { + inpSetMidiCtrl(ctrl & 254, channel, set, value >> 7); + inpSetMidiCtrl((ctrl & 254) + 1, channel, set, value & 0x7f); + } else { + inpSetMidiCtrl(ctrl, channel, set, value >> 7); + } +} + +static const u8 inpColdMIDIDefaults[134] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x40, 0x7F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x7F, 0x7F, 0x7F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, +}; +static const u8 inpWarmMIDIDefaults[134] = { + 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x40, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + +}; + +void inpResetMidiCtrl(u8 ch, u8 set, u32 coldReset) { + const u8* values; // r30 + u8* dest; // r29 + u32 i; // r31 + + values = coldReset ? inpColdMIDIDefaults : inpWarmMIDIDefaults; + dest = set != 0xFF ? midi_ctrl[set][ch] : fx_ctrl[ch]; + + if (coldReset) { + memcpy(dest, values, 134); + } else { + for (i = 0; i < 134; ++i) { + if (values[i] != 0xFF) { + dest[i] = values[i]; + } + } + } + + inpSetMidiLastNote(ch, set, 0xFF); +} + +u16 inpGetMidiCtrl(u8 ctrl, u8 channel, u8 set) { + + if (channel != 0xff) { + if (set != 0xff) { + + if (ctrl < 0x40) { + return midi_ctrl[set][channel][ctrl & 0x1f] << 7 | + midi_ctrl[set][channel][(ctrl & 0x1f) + 0x20]; + } else if (ctrl < 0x46) { + return midi_ctrl[set][channel][ctrl] < 0x40 ? 0 : 0x3fff; + } else if (ctrl >= 0x60 && ctrl < 0x66) { + return 0; + } else { + if ((ctrl == 0x80) || (ctrl == 0x81)) { + return midi_ctrl[set][channel][ctrl & 0xfe] << 7 | + midi_ctrl[set][channel][(ctrl & 0xfe) + 1]; + } else if ((ctrl == 0x84) || (ctrl == 0x85)) { + return midi_ctrl[set][channel][ctrl & 0xfe] << 7 | + midi_ctrl[set][channel][(ctrl & 0xfe) + 1]; + } else { + return (u16)midi_ctrl[set][channel][ctrl] << 7; + } + } + } else { + if (ctrl < 0x40) { + return fx_ctrl[channel][ctrl & 0x1f] << 7 | fx_ctrl[channel][(ctrl & 0x1f) + 0x20]; + } else if (ctrl < 0x46) { + return fx_ctrl[channel][ctrl] < 0x40 ? 0 : 0x3fff; + } else if (ctrl >= 0x60 && ctrl < 0x66) { + return 0; + } else { + if ((ctrl == 0x80) || (ctrl == 0x81)) { + return fx_ctrl[channel][ctrl & 0xfe] << 7 | fx_ctrl[channel][(ctrl & 0xfe) + 1]; + } else if ((ctrl == 0x84) || (ctrl == 0x85)) { + return fx_ctrl[channel][ctrl & 0xfe] << 7 | fx_ctrl[channel][(ctrl & 0xfe) + 1]; + } else { + return (u16)fx_ctrl[channel][ctrl] << 7; + } + } + } + } + return 0; +} + +CHANNEL_DEFAULTS* inpGetChannelDefaults(u8 midi, u8 midiSet) { + if (midiSet == 0xFF) { + return &inpFXChannelDefaults[midi]; + } + + return &inpChannelDefaults[midiSet][midi]; +} + +void inpResetChannelDefaults(u8 midi, u8 midiSet) { + CHANNEL_DEFAULTS* channelDefaults; // r31 + channelDefaults = + midiSet != 0xFF ? &inpChannelDefaults[midiSet][midi] : &inpFXChannelDefaults[midi]; + channelDefaults->pbRange = 2; +} + +void inpAddCtrl(CTRL_DEST* dest, u8 ctrl, long scale, u8 comb, u32 isVar) { + u8 n; // r30 + if (comb == 0) { + dest->numSource = 0; + } + + if (dest->numSource < 4) { + n = dest->numSource; + dest->numSource = n + 1; + if (isVar == 0) { + ctrl = inpTranslateExCtrl(ctrl); + } else { + comb |= 0x10; + } + + dest->source[n].midiCtrl = ctrl; + dest->source[n].combine = comb; + dest->source[n].scale = scale; + } +} + +void inpFXCopyCtrl(u8 ctrl, SYNTH_VOICE* dvoice, SYNTH_VOICE* svoice) { + u8 di; // r30 + u8 si; // r29 + di = dvoice->id; + si = svoice->id; + + if (ctrl < 64) { + fx_ctrl[di][ctrl & 31] = fx_ctrl[si][ctrl & 31]; + fx_ctrl[di][(ctrl & 31) + 32] = fx_ctrl[si][(ctrl & 31) + 32]; + } else if (ctrl == 128 || ctrl == 129) { + fx_ctrl[di][ctrl & 254] = fx_ctrl[si][ctrl & 254]; + fx_ctrl[di][(ctrl & 254) + 1] = fx_ctrl[si][(ctrl & 254) + 1]; + } else if (ctrl == 132 || ctrl == 133) { + fx_ctrl[di][ctrl & 254] = fx_ctrl[si][ctrl & 254]; + fx_ctrl[di][(ctrl & 254) + 1] = fx_ctrl[si][(ctrl & 254) + 1]; + } else { + fx_ctrl[di][ctrl] = fx_ctrl[si][ctrl]; + } +} + +void inpSetMidiLastNote(u8 midi, u8 midiSet, u8 key) { + if (midiSet != 0xFF) { + midi_lastNote[midiSet][midi] = key; + } else { + fx_lastNote[midi] = key; + } +} + +u8 inpGetMidiLastNote(u8 midi, u8 midiSet) { + if (midiSet != 0xFF) { + return midi_lastNote[midiSet][midi]; + } + return fx_lastNote[midi]; +} + +#pragma dont_inline on +static u16 _GetInputValue(SYNTH_VOICE* svoice, CTRL_DEST* inp, u8 midi, u8 midiSet) { + u32 i; // r26 + u32 value; // r29 + u8 ctrl; // r28 + s32 tmp; // r31 + s32 vtmp; // r30 + u32 sign; // r25 + + for (value = 0, i = 0; i < inp->numSource; ++i) { + if (inp->source[i].combine & 0x10) { + tmp = (svoice != NULL ? varGet(svoice, 0, inp->source[i].midiCtrl) : 0); + } else { + ctrl = inp->source[i].midiCtrl; + if (ctrl == 128 || ctrl == 1 || ctrl == 10 || ctrl == 160 || ctrl == 161 || ctrl == 131) { + switch (ctrl) { + case 160: + case 161: + if (svoice != NULL) { + tmp = svoice->lfo[ctrl - 160].value << 1; + svoice->lfoUsedByInput[ctrl - 160] = 1; + } else { + tmp = 0; + } + break; + default: + tmp = inpGetMidiCtrl(ctrl, midi, midiSet) - 0x2000; + break; + } + } else if (ctrl == 163) { + tmp = svoice != NULL ? svoice->orgVolume >> 9 : 0; + } else if (ctrl < 163) { + if (ctrl < 162) { + tmp = inpGetMidiCtrl(ctrl, midi, midiSet); + } else if (svoice == NULL) { + tmp = 0; + } else { + tmp = svoice->orgNote << 7; + } + } else if (ctrl > 164) { + if (svoice != NULL) { + tmp = (synthRealTime - svoice->macStartTime) << 8; + if (tmp > 0x3fff) { + tmp = 0x3fff; + } + + svoice->timeUsedByInput = 1; + } else { + tmp = 0; + } + } + + tmp = (tmp * inp->source[i].scale / 2) >> 15; + } + } + + inp->oldValue = value; + return value; +} + +#pragma dont_inline reset + +static u16 GetInputValue(SYNTH_VOICE* svoice, CTRL_DEST* inp, u32 dirtyMask) { + + if (!(svoice->midiDirtyFlags & dirtyMask)) { + return inp->oldValue; + } + + svoice->midiDirtyFlags &= ~dirtyMask; + + return _GetInputValue(svoice, inp, svoice->midi, svoice->midiSet); +} + +static u16 GetGlobalInputValue(CTRL_DEST* inp, u32 dirtyMask, u8 midi, u8 midiSet) { + if (!inpResetGlobalMIDIDirtyFlag(midi, midiSet, dirtyMask)) { + return inp->oldValue; + } + return _GetInputValue(NULL, inp, midi, midiSet); +} + +u16 inpGetVolume(SYNTH_VOICE* svoice) { return GetInputValue(svoice, &svoice->inpVolume, 0x1); } + +u16 inpGetPanning(SYNTH_VOICE* svoice) { return GetInputValue(svoice, &svoice->inpPanning, 0x2); } + +u16 inpGetSurPanning(SYNTH_VOICE* svoice) { + return GetInputValue(svoice, &svoice->inpSurroundPanning, 0x4); +} + +u16 inpGetPitchBend(SYNTH_VOICE* svoice) { + return GetInputValue(svoice, &svoice->inpPitchBend, 0x8); +} + +u16 inpGetDoppler(SYNTH_VOICE* svoice) { return GetInputValue(svoice, &svoice->inpDoppler, 0x10); } + +u16 inpGetModulation(SYNTH_VOICE* svoice) { + return GetInputValue(svoice, &svoice->inpModulation, 0x20); +} + +u16 inpGetPedal(SYNTH_VOICE* svoice) { return GetInputValue(svoice, &svoice->inpPedal, 0x40); } + +u16 inpGetPreAuxA(SYNTH_VOICE* svoice) { return GetInputValue(svoice, &svoice->inpPreAuxA, 0x100); } + +u16 inpGetReverb(SYNTH_VOICE* svoice) { return GetInputValue(svoice, &svoice->inpReverb, 0x200); } + +u16 inpGetPreAuxB(SYNTH_VOICE* svoice) { return GetInputValue(svoice, &svoice->inpPreAuxB, 0x400); } + +u16 inpGetPostAuxB(SYNTH_VOICE* svoice) { + return GetInputValue(svoice, &svoice->inpPostAuxB, 0x800); +} + +u16 inpGetTremolo(SYNTH_VOICE* svoice) { + return GetInputValue(svoice, &svoice->inpTremolo, 0x1000); +} + +u16 inpGetAuxB(u8 studio, u8 index, u8 midi, u8 midiSet) { + static u32 dirtyMask[4] = {0x80000001, 0x80000002, 0x80000004, 0x80000008}; + + return GetGlobalInputValue(&inpAuxA[studio][index], dirtyMask[index], midi, midiSet); +} + +u16 inpGetAuxA(u8 studio, u8 index, u8 midi, u8 midiSet) { + static u32 dirtyMask[4] = {0x80000010, 0x80000020, 0x80000040, 0x80000080}; + + return GetGlobalInputValue(&inpAuxB[studio][index], dirtyMask[index], midi, midiSet); +} + +void inpInit(SYNTH_VOICE* svoice) { + u32 i; // r30 + u32 s; // r29 + + if (svoice != NULL) { + svoice->inpVolume.source[0].midiCtrl = 7; + svoice->inpVolume.source[0].combine = 0; + svoice->inpVolume.source[0].scale = 0x10000; + svoice->inpVolume.source[1].midiCtrl = 11; + svoice->inpVolume.source[1].combine = 2; + svoice->inpVolume.source[1].scale = 0x10000; + svoice->inpVolume.numSource = 2; + svoice->inpPanning.source[0].midiCtrl = 10; + svoice->inpPanning.source[0].combine = 0; + svoice->inpPanning.source[0].scale = 0x10000; + svoice->inpPanning.numSource = 1; + svoice->inpSurroundPanning.source[0].midiCtrl = 131; + svoice->inpSurroundPanning.source[0].combine = 0; + svoice->inpSurroundPanning.source[0].scale = 0x10000; + svoice->inpSurroundPanning.numSource = 1; + svoice->inpPitchBend.source[0].midiCtrl = 128; + svoice->inpPitchBend.source[0].combine = 0; + svoice->inpPitchBend.source[0].scale = 0x10000; + svoice->inpPitchBend.numSource = 1; + svoice->inpModulation.source[0].midiCtrl = 1; + svoice->inpModulation.source[0].combine = 0; + svoice->inpModulation.source[0].scale = 0x10000; + svoice->inpModulation.numSource = 1; + svoice->inpPedal.source[0].midiCtrl = 64; + svoice->inpPedal.source[0].combine = 0; + svoice->inpPedal.source[0].scale = 0x10000; + svoice->inpPedal.numSource = 1; + svoice->inpPortamento.source[0].midiCtrl = 65; + svoice->inpPortamento.source[0].combine = 0; + svoice->inpPortamento.source[0].scale = 0x10000; + svoice->inpPortamento.numSource = 1; + svoice->inpPreAuxA.numSource = 0; + svoice->inpReverb.source[0].midiCtrl = 91; + svoice->inpReverb.source[0].combine = 0; + svoice->inpReverb.source[0].scale = 0x10000; + svoice->inpReverb.numSource = 1; + svoice->inpPreAuxB.numSource = 0; + svoice->inpPostAuxB.source[0].midiCtrl = 93; + svoice->inpPostAuxB.source[0].combine = 0; + svoice->inpPostAuxB.source[0].scale = 0x10000; + svoice->inpPostAuxB.numSource = 1; + svoice->inpDoppler.source[0].midiCtrl = 132; + svoice->inpDoppler.source[0].combine = 0; + svoice->inpDoppler.source[0].scale = 0x10000; + svoice->inpDoppler.numSource = 1; + svoice->inpTremolo.numSource = 0; + + svoice->midiDirtyFlags = 0x1fff; + svoice->lfoUsedByInput[0] = 0; + svoice->lfoUsedByInput[1] = 0; + svoice->timeUsedByInput = 0; + } else { + for (s = 0; s < 8; ++s) { + for (i = 0; i < 4; ++i) { + inpAuxA[s][i].numSource = 0; + inpAuxB[s][i].numSource = 0; + } + } + + inpResetGlobalMIDIDirtyFlags(); + } +} + +u8 inpTranslateExCtrl(u8 ctrl) { + switch (ctrl) { + case 0x80: + ctrl = 0x80; + break; + case 0x81: + ctrl = 0x82; + break; + case 0x82: + ctrl = 0xa0; + break; + case 0x83: + ctrl = 0xa1; + break; + case 0x84: + ctrl = 0x83; + break; + case 0x85: + ctrl = 0x84; + break; + case 0x86: + ctrl = 0xa2; + break; + case 0x87: + ctrl = 0xa3; + break; + case 0x88: + ctrl = 0xa4; + break; + } + return ctrl; +} +u16 inpGetExCtrl(SYNTH_VOICE* svoice, u8 ctrl) { + u16 v; // r30 + switch (inpTranslateExCtrl(ctrl)) { + case 160: + v = (svoice->lfo[0].value << 1) + 0x2000; + break; + case 161: + v = (svoice->lfo[1].value << 1) + 0x2000; + break; + default: + v = svoice->midi != 0xFF ? inpGetMidiCtrl(ctrl, svoice->midi, svoice->midiSet) : 0; + break; + } + + return v; +} +void inpSetExCtrl(SYNTH_VOICE* svoice, u8 ctrl, s16 v) { + v = v < 0 ? 0 : v > 0x3fff ? 0x3fff : v; + + switch (inpTranslateExCtrl(ctrl)) { + case 161: + case 160: + break; + default: + if (svoice->midi != 0xFF) { + inpSetMidiCtrl14(ctrl, svoice->midi, svoice->midiSet, v); + } + break; } }