Link musyx/runtime/synth

This commit is contained in:
Luke Street 2023-07-05 17:57:50 -04:00
parent bfd8a4e1b3
commit a24285819d
8 changed files with 824 additions and 54 deletions

View File

@ -1118,7 +1118,7 @@ salBuildCommandList:
/* 803ABACC 003A8A2C 7C 08 02 A6 */ mflr r0
/* 803ABAD0 003A8A30 90 01 00 84 */ stw r0, 0x84(r1)
/* 803ABAD4 003A8A34 39 61 00 80 */ addi r11, r1, 0x80
/* 803ABAD8 003A8A38 4B FD DF 71 */ bl __save_gpr
/* 803ABAD8 003A8A38 4B FD DF 71 */ bl _savegpr_14
/* 803ABADC 003A8A3C 80 AD AF 40 */ lwz r5, dspCmdList@sda21(r13)
/* 803ABAE0 003A8A40 38 00 00 00 */ li r0, 0
/* 803ABAE4 003A8A44 90 0D AF 24 */ stw r0, dspCmdLastLoad@sda21(r13)
@ -3427,7 +3427,7 @@ lbl_803ADC58:
/* 803ADC60 003AABC0 7C 83 00 50 */ subf r4, r3, r0
/* 803ADC64 003AABC4 4B FD 0E D9 */ bl DCStoreRangeNoSync
/* 803ADC68 003AABC8 39 61 00 80 */ addi r11, r1, 0x80
/* 803ADC6C 003AABCC 4B FD BE 29 */ bl __restore_gpr
/* 803ADC6C 003AABCC 4B FD BE 29 */ bl _restgpr_14
/* 803ADC70 003AABD0 80 01 00 84 */ lwz r0, 0x84(r1)
/* 803ADC74 003AABD4 7C 08 03 A6 */ mtlr r0
/* 803ADC78 003AABD8 38 21 00 80 */ addi r1, r1, 0x80

View File

@ -1502,7 +1502,7 @@ sndStreamAllocStereo:
/* 8039DD28 0039AC88 7C 08 02 A6 */ mflr r0
/* 8039DD2C 0039AC8C 90 01 00 74 */ stw r0, 0x74(r1)
/* 8039DD30 0039AC90 39 61 00 70 */ addi r11, r1, 0x70
/* 8039DD34 0039AC94 4B FE BD 15 */ bl __save_gpr
/* 8039DD34 0039AC94 4B FE BD 15 */ bl _savegpr_14
/* 8039DD38 0039AC98 55 29 06 3E */ clrlwi r9, r9, 0x18
/* 8039DD3C 0039AC9C 8A E1 00 7B */ lbz r23, 0x7b(r1)
/* 8039DD40 0039ACA0 38 09 FF C0 */ addi r0, r9, -64
@ -1686,7 +1686,7 @@ lbl_8039DFC4:
/* 8039DFC8 0039AF28 7E 23 8B 78 */ mr r3, r17
lbl_8039DFCC:
/* 8039DFCC 0039AF2C 39 61 00 70 */ addi r11, r1, 0x70
/* 8039DFD0 0039AF30 4B FE BA C5 */ bl __restore_gpr
/* 8039DFD0 0039AF30 4B FE BA C5 */ bl _restgpr_14
/* 8039DFD4 0039AF34 80 01 00 74 */ lwz r0, 0x74(r1)
/* 8039DFD8 0039AF38 7C 08 03 A6 */ mtlr r0
/* 8039DFDC 0039AF3C 38 21 00 70 */ addi r1, r1, 0x70

View File

@ -416,7 +416,7 @@ StartLayer:
/* 80399034 00395F94 7C 08 02 A6 */ mflr r0
/* 80399038 00395F98 90 01 00 84 */ stw r0, 0x84(r1)
/* 8039903C 00395F9C 39 61 00 80 */ addi r11, r1, 0x80
/* 80399040 00395FA0 4B FF 0A 09 */ bl __save_gpr
/* 80399040 00395FA0 4B FF 0A 09 */ bl _savegpr_14
/* 80399044 00395FA4 8A 61 00 8B */ lbz r19, 0x8b(r1)
/* 80399048 00395FA8 7C 8F 23 78 */ mr r15, r4
/* 8039904C 00395FAC 8A 81 00 8F */ lbz r20, 0x8f(r1)
@ -672,7 +672,7 @@ lbl_803993C8:
lbl_803993D4:
/* 803993D4 00396334 7D C3 73 78 */ mr r3, r14
/* 803993D8 00396338 39 61 00 80 */ addi r11, r1, 0x80
/* 803993DC 0039633C 4B FF 06 B9 */ bl __restore_gpr
/* 803993DC 0039633C 4B FF 06 B9 */ bl _restgpr_14
/* 803993E0 00396340 80 01 00 84 */ lwz r0, 0x84(r1)
/* 803993E4 00396344 7C 08 03 A6 */ mtlr r0
/* 803993E8 00396348 38 21 00 80 */ addi r1, r1, 0x80
@ -1668,7 +1668,7 @@ lbl_8039A1D4:
/* 8039A1E4 00397144 38 21 00 30 */ addi r1, r1, 0x30
/* 8039A1E8 00397148 4E 80 00 20 */ blr
ZeroOffsetHandler:
.fn ZeroOffsetHandler, local
/* 8039A1EC 0039714C 94 21 FF 60 */ stwu r1, -0xa0(r1)
/* 8039A1F0 00397150 7C 08 02 A6 */ mflr r0
/* 8039A1F4 00397154 90 01 00 A4 */ stw r0, 0xa4(r1)
@ -2141,6 +2141,7 @@ lbl_8039A8A8:
/* 8039A8DC 0039783C 7C 08 03 A6 */ mtlr r0
/* 8039A8E0 00397840 38 21 00 A0 */ addi r1, r1, 0xa0
/* 8039A8E4 00397844 4E 80 00 20 */ blr
.endfn ZeroOffsetHandler
.global synthAddJob
synthAddJob:
@ -3356,8 +3357,7 @@ synthSetMusicVolumeType:
/* 8039B98C 003988EC 98 83 00 2D */ stb r4, 0x2d(r3)
/* 8039B990 003988F0 4E 80 00 20 */ blr
synthHWMessageHandler:
.fn synthHWMessageHandler, local
/* 8039B994 003988F4 94 21 FF E0 */ stwu r1, -0x20(r1)
/* 8039B998 003988F8 7C 08 02 A6 */ mflr r0
/* 8039B99C 003988FC 2C 03 00 02 */ cmpwi r3, 2
@ -3416,6 +3416,7 @@ lbl_8039BA44:
/* 8039BA58 003989B8 7C 08 03 A6 */ mtlr r0
/* 8039BA5C 003989BC 38 21 00 20 */ addi r1, r1, 0x20
/* 8039BA60 003989C0 4E 80 00 20 */ blr
.endfn synthHWMessageHandler
.global synthInit
synthInit:
@ -3423,7 +3424,7 @@ synthInit:
/* 8039BA68 003989C8 7C 08 02 A6 */ mflr r0
/* 8039BA6C 003989CC 90 01 00 54 */ stw r0, 0x54(r1)
/* 8039BA70 003989D0 39 61 00 50 */ addi r11, r1, 0x50
/* 8039BA74 003989D4 4B FE DF D5 */ bl __save_gpr
/* 8039BA74 003989D4 4B FE DF D5 */ bl _savegpr_14
/* 8039BA78 003989D8 7C 8F 23 78 */ mr r15, r4
/* 8039BA7C 003989DC 3C 80 80 55 */ lis r4, synthTicksPerSecond@ha
/* 8039BA80 003989E0 3B E4 FE 10 */ addi r31, r4, synthTicksPerSecond@l
@ -3768,7 +3769,7 @@ lbl_8039BFA0:
/* 8039BFB8 00398F18 38 63 B9 94 */ addi r3, r3, synthHWMessageHandler@l
/* 8039BFBC 00398F1C 48 01 72 01 */ bl hwSetMesgCallback
/* 8039BFC0 00398F20 39 61 00 50 */ addi r11, r1, 0x50
/* 8039BFC4 00398F24 4B FE DA D1 */ bl __restore_gpr
/* 8039BFC4 00398F24 4B FE DA D1 */ bl _restgpr_14
/* 8039BFC8 00398F28 80 01 00 54 */ lwz r0, 0x54(r1)
/* 8039BFCC 00398F2C 7C 08 03 A6 */ mtlr r0
/* 8039BFD0 00398F30 38 21 00 50 */ addi r1, r1, 0x50

View File

@ -5524,7 +5524,7 @@ macStart:
/* 803A71C4 003A4124 7C 08 02 A6 */ mflr r0
/* 803A71C8 003A4128 90 01 00 54 */ stw r0, 0x54(r1)
/* 803A71CC 003A412C 39 61 00 50 */ addi r11, r1, 0x50
/* 803A71D0 003A4130 4B FE 28 79 */ bl __save_gpr
/* 803A71D0 003A4130 4B FE 28 79 */ bl _savegpr_14
/* 803A71D4 003A4134 8A C1 00 5B */ lbz r22, 0x5b(r1)
/* 803A71D8 003A4138 7C 6F 1B 78 */ mr r15, r3
/* 803A71DC 003A413C 8A E1 00 5F */ lbz r23, 0x5f(r1)
@ -5807,7 +5807,7 @@ lbl_803A75DC:
/* 803A75DC 003A453C 38 60 FF FF */ li r3, -1
lbl_803A75E0:
/* 803A75E0 003A4540 39 61 00 50 */ addi r11, r1, 0x50
/* 803A75E4 003A4544 4B FE 24 B1 */ bl __restore_gpr
/* 803A75E4 003A4544 4B FE 24 B1 */ bl _restgpr_14
/* 803A75E8 003A4548 80 01 00 54 */ lwz r0, 0x54(r1)
/* 803A75EC 003A454C 7C 08 03 A6 */ mtlr r0
/* 803A75F0 003A4550 38 21 00 50 */ addi r1, r1, 0x50

View File

@ -935,7 +935,7 @@ LIBS = [
"host": False,
"objects": [
["musyx/runtime/seq", True],
["musyx/runtime/synth", False],
["musyx/runtime/synth", True],
["musyx/runtime/seq_api", True],
["musyx/runtime/snd_synthapi", True, {"add_to_all": False}],
["musyx/runtime/stream", False],

View File

@ -384,10 +384,11 @@ typedef struct CALLSTACK {
} CALLSTACK;
typedef struct SYNTH_QUEUE {
struct SYNTH_QUEUE* next;
struct SYNTH_QUEUE* prev;
u8 voice;
u8 jobTabIndex;
// total size: 0xC
struct SYNTH_QUEUE* next; // offset 0x0, size 0x4
struct SYNTH_QUEUE* prev; // offset 0x4, size 0x4
u8 voice; // offset 0x8, size 0x1
u8 jobTabIndex; // offset 0x9, size 0x1
} SYNTH_QUEUE;
typedef enum {
@ -883,13 +884,17 @@ u32 seqStartPlay(PAGE* norm, PAGE* drum, MIDISETUP* midiSetup, u32* song, SND_PL
u8 studio, u16 sgid);
u32 seqGetPrivateId(u32 seqId);
void streamInit(); /* extern */
void vsInit(); /* extern */
void vsInit(); /* extern */
u32 vsSampleStartNotify(u8 voice);
void vsSampleEndNotify(u32 pubID);
void hwExit();
void dataExit();
void s3dInit(u32); /* extern */
void s3dKillEmitterByFXID(FX_TAB* fxTab, u32 num);
void s3dExit();
void synthInit(u32, u8); /* extern */
void synthInit(u32 mixFrq, u32 numVoices);
void synthSetBpm(u32 pbm, u8 set, u8 section);
void synthFXCloneMidiSetup(SYNTH_VOICE* dest, SYNTH_VOICE* src);
void synthSetMusicVolumeType(u8 vGroup, u8 type);
@ -907,6 +912,7 @@ void voiceSetLastStarted(SYNTH_VOICE* svoice);
void voiceResetLastStarted(SYNTH_VOICE* svoice);
void voiceInitLastStarted();
s32 voiceKillSound(u32 voiceid);
void voiceKill(u32 vi);
extern u64 synthRealTime;
u32 synthGetTicksPerSecond(SYNTH_VOICE* svoice);
@ -931,6 +937,8 @@ u32 hwGlobalActivity();
void hwSetAUXProcessingCallbacks(u8 studio, SND_AUX_CALLBACK auxA, void* userA,
SND_AUX_CALLBACK auxB, void* userB);
u8 hwInitStream(u32 len);
u8 hwGetTimeOffset();
u32 hwGetVirtualSampleID(u32 v);
s16 varGet(SYNTH_VOICE* svoice, u32 ctrl, u8 index);
u32 sndGetPitch(u8 key, u32 sInfo);
@ -1030,9 +1038,8 @@ void streamOutputModeChanged();
u8 inpTranslateExCtrl(u8 ctrl);
void inpSetGlobalMIDIDirtyFlag(u8 chan, u8 midiSet, s32 flag);
void inpAddCtrl(CTRL_DEST* dest, u8 ctrl, s32 scale, u8 comb, u32 isVar);
void inpSetMidiCtrl(unsigned char ctrl, unsigned char channel, unsigned char set,
unsigned char value);
void inpSetMidiCtrl14(unsigned char ctrl, unsigned char channel, unsigned char set, u16 value);
void inpSetMidiCtrl(u8 ctrl, u8 channel, u8 set, u8 value);
void inpSetMidiCtrl14(u8 ctrl, u8 channel, u8 set, u16 value);
void inpSetExCtrl(SYNTH_VOICE* svoice, u8 ctrl, s16 v);
CHANNEL_DEFAULTS* inpGetChannelDefaults(u8 midi, u8 midiSet);
extern CTRL_DEST inpAuxA[8][4];
@ -1047,6 +1054,18 @@ void inpResetMidiCtrl(u8 ch, u8 set, u32 coldReset);
void inpResetChannelDefaults(u8 midi, u8 midiSet);
u16 inpGetPitchBend(SYNTH_VOICE* svoice);
u16 inpGetDoppler(SYNTH_VOICE* svoice);
u16 inpGetTremolo(SYNTH_VOICE* svoice);
u16 inpGetPanning(SYNTH_VOICE* svoice);
u16 inpGetSurPanning(SYNTH_VOICE* svoice);
u16 inpGetVolume(SYNTH_VOICE* svoice);
u16 inpGetReverb(SYNTH_VOICE* svoice);
u16 inpGetPreAuxA(SYNTH_VOICE* svoice);
u16 inpGetPostAuxA(SYNTH_VOICE* svoice);
u16 inpGetPreAuxB(SYNTH_VOICE* svoice);
u16 inpGetPostAuxB(SYNTH_VOICE* svoice);
u16 inpGetPedal(SYNTH_VOICE* svoice);
u16 inpGetAuxA(u8 studio, u8 index, u8 midi, u8 midiSet);
u16 inpGetAuxB(u8 studio, u8 index, u8 midi, u8 midiSet);
/* TODO: Figure out what `unk` is */
void hwSetSRCType(u32 v, u8 salSRCType);
@ -1056,6 +1075,9 @@ bool hwAddInput(u8 studio, SND_STUDIO_INPUT* in_desc);
bool hwRemoveInput(u8 studio, SND_STUDIO_INPUT* in_desc);
void hwChangeStudio(u32 v, u8 studio);
void hwDisableHRTF();
void hwStart(u32 v, u8 studio);
void hwKeyOff(u32 v);
void hwFrameDone();
extern u32 dspHRTFOn;
@ -1075,7 +1097,11 @@ u8 aramAllocateStreamBuffer(u32 len);
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);
void macHandle(u32 deltaTime);
void macMakeInactive(SYNTH_VOICE* svoice, MAC_STATE);
void macSetPedalState(SYNTH_VOICE* svoice, u32 state);
void macSetExternalKeyoff(SYNTH_VOICE* svoice);
void macSampleEndNotify(SYNTH_VOICE* sv);
void sndProfUpdateMisc(SND_PROFILE_INFO* info);
void sndProfResetPMC(SND_PROFILE_DATA* info);
@ -1086,6 +1112,7 @@ u32 vidMakeNew(SYNTH_VOICE* svoice, u32 isMaster);
u32 vidMakeRoot(SYNTH_VOICE* svoice);
u32 adsrHandleLowPrecision(ADSR_VARS* adsr, u16* adsr_start, u16* adsr_delta);
bool adsrRelease(ADSR_VARS* adsr);
#ifdef __cplusplus
}

View File

@ -26,7 +26,7 @@ SND_VOICEID synthFXStart(u16 fid, u8 vol, u8 pan, u8 studio, u32 itd);
void synthVolume(u8 volume, u16 time, u8 vGroup, u8 seqMode, u32 seqId);
u32 synthStartSound(u16 id, u8 prio, u8 max,
#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 0)
unsigned long sourceID,
u32 sourceID,
#endif
u8 key, u8 vol, u8 panning, u8 midi, u8 midiSet, u8 section, u16 step,
u16 trackid, u8 vGroup, s16 prioOffset, u8 studio, u32 itd);

View File

@ -1,4 +1,5 @@
#include "musyx/synth.h"
#include "musyx/musyx_priv.h"
static u32 synthTicksPerSecond[9][16];
@ -91,7 +92,11 @@ static u32 do_voice_portamento(u8 key, u8 midi, u8 midiSet, u32 isMaster, u32* r
vid = SND_ID_ERROR;
for (i = 0, sv = synthVoice; i < synthInfo.voiceNum; ++i, ++sv) {
if (sv->id != SND_ID_ERROR && sv->midi == midi && sv->midiSet == midiSet) {
if (
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
sv->block == 0 &&
#endif
sv->id != SND_ID_ERROR && sv->midi == midi && sv->midiSet == midiSet) {
if ((sv->cFlags & 2) != 0) {
legatoVoiceIsStarting = TRUE;
}
@ -137,7 +142,7 @@ static u32 do_voice_portamento(u8 key, u8 midi, u8 midiSet, u32 isMaster, u32* r
static u32 check_portamento(u8 key, u8 midi, u8 midiSet, u32 newVID, u32* vid) {
u32 rejected; // r1+0x14
if (inpGetMidiCtrl(65, midi, midiSet) > 8064) {
if (inpGetMidiCtrl(65 /* TODO SND_MIDICTRL_? */, midi, midiSet) > 8064) {
*vid = do_voice_portamento(key & 0x7f, midi, midiSet, newVID, &rejected);
return !rejected;
}
@ -177,7 +182,13 @@ static u32 StartLayer(u16 layerID, s16 prio, u8 maxVoices, u16 allocId, u8 key,
k = CLAMP(k, 0, 127);
if ((l->id & 0xC000) == 0) {
if (check_portamento(k, midi, midiSet, vidFlag, &new_id)) {
if (check_portamento(k, midi, midiSet,
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
0,
#else
vidFlag,
#endif
&new_id)) {
if (new_id != 0xFFFFFFFF) {
goto apply_new_id;
} else {
@ -231,8 +242,14 @@ static u32 StartLayer(u16 layerID, s16 prio, u8 maxVoices, u16 allocId, u8 key,
}
id = new_id;
while (synthVoice[id & 0xff].child != SND_ID_ERROR) {
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
synthVoice[id & 0xff].block = 1;
#endif
id = synthVoice[id & 0xff].child;
}
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
synthVoice[id & 0xff].block = 1;
#endif
}
}
@ -291,30 +308,67 @@ static u32 StartKeymap(u16 keymapID, s16 prio, u8 maxVoices, u16 allocId, u8 key
return SND_ID_ERROR;
}
u32 synthStartSound(u16 id, u8 prio, u8 max, u8 key, u8 vol, u8 panning, u8 midi, u8 midiSet,
u8 section, u16 step, u16 trackid, u8 vGroup, s16 prioOffset, u8 studio,
u32 itd) {
u32 vid; // r1+0x34
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
static void unblockAllAllocatedVoices(u32 vid) {
u32 id; // r31
id = vidGetInternalId(vid);
#line 501
MUSY_ASSERT_MSG(id != SND_ID_ERROR, "*** Alloc unblock: ID is illegal");
while (id != SND_ID_ERROR) {
synthVoice[id & 0xff].block = 0;
id = synthVoice[id & 0xff].child;
}
}
#endif
u32 synthStartSound(u16 id, u8 prio, u8 max,
#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 0)
u32 sourceID,
#endif
u8 key, u8 vol, u8 panning, u8 midi, u8 midiSet, u8 section, u16 step,
u16 trackid, u8 vGroup, s16 prioOffset, u8 studio, u32 itd) {
prio += prioOffset;
prio = CLAMP(prio, 0, 0xff);
switch (id & 0xC000) {
case 0:
case 0: {
u32 vid; // r1+0x34
if (!check_portamento(key, midi, midiSet, 1, &vid)) {
return 0xffffffff;
return SND_ID_ERROR;
}
if (vid != 0xffffffff) {
if (vid != SND_ID_ERROR) {
return vid;
}
return macStart(id, prio, max, id, key, vol, panning, midi, midiSet, section, step, trackid, 1,
vGroup, studio, itd);
case 0x4000:
}
case 0x4000: {
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
u32 vid = StartKeymap(id, prio, max, id, key, vol, panning, midi, midiSet, section, step,
trackid, 1, vGroup, studio, itd);
if (vid != SND_ID_ERROR) {
unblockAllAllocatedVoices(vid);
}
return vid;
#else
return StartKeymap(id, prio, max, id, key, vol, panning, midi, midiSet, section, step, trackid,
1, vGroup, studio, itd);
case 0x8000:
#endif
}
case 0x8000: {
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
u32 vid = StartLayer(id, prio, max, id, key, vol, panning, midi, midiSet, section, step,
trackid, 1, vGroup, studio, itd);
if (vid != SND_ID_ERROR) {
unblockAllAllocatedVoices(vid);
}
return vid;
#else
return StartLayer(id, prio, max, id, key, vol, panning, midi, midiSet, section, step, trackid,
1, vGroup, studio, itd);
#endif
}
default:
return SND_ID_ERROR;
}
@ -423,7 +477,13 @@ static void LowPrecisionHandler(u32 i) {
}
ccents = sv->curNote * 65536 + (sv->curDetune * 65536) / 100;
if ((sv->cFlags & 0x10010) != 0) {
if ((sv->cFlags &
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
0x10030
#else
0x10010
#endif
) != 0) {
if (sv->midi != 0xff) {
pbend = inpGetPitchBend(sv);
sv->pbLast = pbend;
@ -446,10 +506,18 @@ static void LowPrecisionHandler(u32 i) {
Modulation = inpGetModulation(sv);
vrange = sv->vibKeyRange * 256 + (sv->vibCentRange * 256) / 100;
if (sv->vibModAddScale != 0) {
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
vrange += (sv->vibModAddScale * ((Modulation & 0x1ffff) >> 7)) >> 7;
#else
vrange += (sv->vibModAddScale * ((Modulation >> 7) & 0x1ff)) >> 7;
#endif
}
if ((sv->cFlags & 0x4000) != 0) {
#if MUSY_VERSION >= MUSY_VERSION_CHECK(1, 5, 4)
voff = (sv->vibCurOffset * ((Modulation & 0x1ffff) >> 7)) >> 7;
#else
voff = (sv->vibCurOffset * ((Modulation >> 7) & 0x1ff)) >> 7;
#endif
} else {
voff = sv->vibCurOffset;
}
@ -493,22 +561,157 @@ static void ZeroOffsetHandler(u32 i) {
SYNTH_VOICE* sv; // r31
u32 lowDeltaTime; // r26
u16 Modulation; // r25
f32 vol; // r62
f32 auxa; // r57
f32 auxb; // r56
f32 f; // r59
f32 voiceVol; // r60
u32 volUpdate; // r30
f32 lfo; // r55
f32 scale; // r63
f32 mscale; // r54
f32 vol; // f30
f32 auxa; // f25
f32 auxb; // f24
f32 f; // f27
f32 voiceVol; // f28
bool volUpdate; // r30
f32 lfo; // f23
f32 scale; // f31
f32 mscale; // f22
s32 pan; // r28
f32 preVol; // r58
f32 postVol; // r61
f32 preVol; // f26
f32 postVol; // f29
sv = &synthVoice[i];
if (!hwIsActive(i) && sv->addr == NULL) {
goto end;
}
lowDeltaTime = synthRealTime - sv->lastZeroCallTime;
sv->lastZeroCallTime = synthRealTime;
if ((sv->cFlags & 0x8000) != 0) {
sv->envCurrent += sv->envDelta * (lowDeltaTime >> 8);
if (sv->envDelta < 0) {
if ((s32)sv->envTarget >= (s32)sv->envCurrent) {
sv->envCurrent = sv->envTarget;
sv->cFlags &= ~0x8000;
}
} else if ((s32)sv->envTarget <= (s32)sv->envCurrent) {
sv->envCurrent = sv->envTarget;
sv->cFlags &= ~0x8000;
}
sv->volume = sv->envCurrent;
volUpdate = TRUE;
} else {
volUpdate = (sv->cFlags & 0x100000000000) != 0;
}
sv->cFlags &= ~0x100000000000;
f = synthMasterFader[sv->vGroup].pauseVol * synthMasterFader[sv->vGroup].volume *
synthMasterFader[sv->fxFlag ? 22 : 21].volume;
if (sv->track != 0xff) {
vol = f * (f32)synthTrackVolume[sv->track] * (1.f / 127.f);
} else {
vol = f;
}
if (vol != sv->lastVolFaderScale) {
sv->lastVolFaderScale = vol;
volUpdate = TRUE;
}
voiceVol = (f32)sv->volume * (1.f / (8192.f * 1016.f) /* 1.201479e-07 */);
if ((sv->treScale | sv->treModAddScale) != 0) {
Modulation = inpGetModulation(sv);
lfo = (f32)(8192 - (8192 - ((s16)inpGetTremolo(sv) - 8192) >> 1)) * (1.f / 8192.f);
mscale = 1.f - (f32)Modulation * (4096 - sv->treModAddScale) * 1.490207e-08f /* 1/(8192^2)? */;
scale = (f32)sv->treScale * mscale * (1.f / 4096.f);
if (sv->treCurScale < scale) {
if ((sv->treCurScale += 0.2f) > scale) {
sv->treCurScale = scale;
}
} else if (sv->treCurScale > scale) {
if ((sv->treCurScale -= 0.2f) < scale) {
sv->treCurScale = scale;
}
}
voiceVol *= 1.f - lfo * (1.f - sv->treCurScale);
volUpdate = TRUE;
}
if ((synthFlags & 1) == 0) {
if ((sv->cFlags & 0x200000000000) != 0 || (sv->midiDirtyFlags & 0x6) != 0) {
sv->cFlags &= ~0x200000000000;
pan = sv->panning[0] + (inpGetPanning(sv) - 8192) * 0x200;
sv->lastPan = CLAMP_INV(pan, 0, 0x7f0000);
if ((synthFlags & 2) != 0) {
if ((sv->lastSPan = sv->panning[1] + inpGetSurPanning(sv) * 512) > 0x7f0000) {
sv->lastSPan = 0x7f0000;
}
} else {
sv->lastSPan = 0;
}
volUpdate = TRUE;
} else if ((synthFlags & 2) == 0) {
sv->lastSPan = 0;
}
} else {
sv->lastPan = 0x400000;
sv->lastSPan = 0;
volUpdate |= (sv->cFlags & 0x200000000000) != 0;
sv->cFlags &= ~0x200000000000;
}
if (volUpdate || (sv->midiDirtyFlags & 0xf01) != 0) {
preVol = voiceVol;
postVol = voiceVol * vol * (f32)inpGetVolume(sv) * 0.00006103888f /* 1/16384? */;
auxa = ((f32)sv->revVolOffset * (1.f / 127.f)) +
((preVol * (f32)inpGetPreAuxA(sv) * 0.00006103888f /* 1/16384? */) +
((f32)sv->revVolScale *
(postVol * (f32)inpGetReverb(sv) * 0.00006103888f /* 1/16384? */) * (1.f / 127.f)));
auxb = (preVol * (f32)inpGetPreAuxB(sv) * 0.00006103888f /* 1/16384? */) +
(postVol * (f32)inpGetPostAuxB(sv) * 0.00006103888f /* 1/16384? */);
sv->curOutputVolume = (u16)(postVol * 32767.f);
hwSetVolume(i, sv->volTable, postVol, sv->lastPan, sv->lastSPan, auxa, auxb);
}
if (sv->age != 0) {
if ((s32)(sv->age -= sv->ageSpeed * lowDeltaTime) < 0) {
sv->age = 0;
}
hwSetPriority(i, sv->prio << 24 | sv->age >> 15);
}
synthAddJob(sv, SYNTH_JOBTYPE_ZERO, (5 - hwGetTimeOffset()) * 256);
end:
UpdateTimeMIDICtrl(sv);
}
static void EventHandler(u32 i) {
SYNTH_VOICE* sv; // r31
sv = &synthVoice[i];
if (!hwIsActive(i) && sv->addr == NULL) {
goto end;
}
macSetPedalState(sv, inpGetPedal(sv) > 0x1f80);
if ((sv->cFlags & 0x20) != 0) {
sv->cFlags &= ~0x20;
sv->cFlags |= 0x10;
hwStart(i, sv->studio);
}
if ((sv->cFlags & 0x10000000090) == 0x90) {
sv->cFlags &= ~0x90;
hwKeyOff(i);
if ((sv->cFlags & 0x20000000000) != 0 && adsrRelease(&sv->pitchADSR)) {
sv->cFlags &= ~0x20000000000;
}
}
end:
UpdateTimeMIDICtrl(sv);
}
static void synthInitJobQueue() {
@ -523,14 +726,68 @@ static void synthInitJobQueue() {
synthJobTableIndex = 0;
}
#pragma dont_inline on
void synthAddJob(SYNTH_VOICE* svoice, SYNTH_JOBTYPE jobType, u32 deltaTime) {
SYNTH_QUEUE* newJq; // r31
SYNTH_QUEUE** root; // r30
u8 jobTabIndex; // r29
SYNTH_JOBTAB* jobTab; // r28
jobTabIndex = ((deltaTime / 256) + synthJobTableIndex) & 0x1f;
jobTab = &synthJobTable[jobTabIndex];
switch (jobType) {
case SYNTH_JOBTYPE_LOW:
newJq = &svoice->lowPrecisionJob;
if (newJq->jobTabIndex != 0xff) {
if (newJq->jobTabIndex == jobTabIndex) {
return;
}
if (newJq->next != NULL) {
newJq->next->prev = newJq->prev;
}
if (newJq->prev != NULL) {
newJq->prev->next = newJq->next;
} else {
synthJobTable[newJq->jobTabIndex].lowPrecision = newJq->next;
}
}
root = &jobTab->lowPrecision;
break;
case SYNTH_JOBTYPE_ZERO:
newJq = &svoice->zeroOffsetJob;
if (newJq->jobTabIndex != 0xff) {
if (newJq->jobTabIndex == jobTabIndex) {
return;
}
if (newJq->next != NULL) {
newJq->next->prev = newJq->prev;
}
if (newJq->prev != NULL) {
newJq->prev->next = newJq->next;
} else {
synthJobTable[newJq->jobTabIndex].zeroOffset = newJq->next;
}
}
root = &jobTab->zeroOffset;
break;
case SYNTH_JOBTYPE_EVENT:
newJq = &svoice->eventJob;
if (newJq->jobTabIndex != 0xff) {
return;
}
root = &jobTab->event;
break;
default:
break;
}
newJq->jobTabIndex = jobTabIndex;
if ((newJq->next = *root) != NULL) {
(*root)->prev = newJq;
}
newJq->prev = NULL;
*root = newJq;
}
#pragma dont_inline reset
void synthStartSynthJobHandling(SYNTH_VOICE* svoice) {
svoice->lastLowCallTime = synthRealTime;
@ -572,7 +829,6 @@ void HandleVoices() {
}
void HandleFaderTermination(SYNTHMasterFader* smf) {
switch (smf->seqMode) {
case 1:
seqStop(smf->seqId);
@ -591,7 +847,65 @@ void synthHandle(u32 deltaTime) {
u32 s; // r30
SYNTHMasterFader* smf; // r31
u32 testFlag; // r27
SND_AUX_INFO info; // r1+0x18
if (synthInfo.numSamples == 0) {
return;
}
macHandle(deltaTime);
HandleVoices();
if (hwGetTimeOffset() == 0) {
if ((synthMasterFaderActiveFlags | synthMasterFaderPauseActiveFlags) != 0) {
for (i = 0, smf = synthMasterFader, testFlag = 1; i < 32; testFlag <<= 1, ++i, ++smf) {
if ((synthMasterFaderActiveFlags & testFlag) != 0) {
smf->volume = smf->target - smf->time * (smf->target - smf->start);
if ((smf->time -= smf->deltaTime) <= 0.f) {
smf->volume = smf->target;
HandleFaderTermination(smf);
if ((synthMasterFaderActiveFlags &= ~testFlag) == 0 &&
synthMasterFaderPauseActiveFlags == 0) {
break;
}
}
}
if ((synthMasterFaderPauseActiveFlags & testFlag) != 0) {
smf->pauseVol = smf->pauseTarget - smf->pauseTime * (smf->pauseTarget - smf->pauseStart);
if ((smf->pauseTime -= smf->pauseDeltaTime) <= 0.f) {
smf->pauseVol = smf->pauseTarget;
if ((synthMasterFaderPauseActiveFlags &= ~testFlag) == 0 &&
synthMasterFaderActiveFlags == 0) {
break;
}
}
}
}
}
for (s = 0; s < 8; ++s) {
if (synthAuxAMIDI[s] != 0xff) {
SND_AUX_INFO info; // r1+0x18
for (i = 0; i < SND_AUX_NUMPARAMETERS; ++i) {
info.data.parameterUpdate.para[i] =
inpGetAuxA(s, i, synthAuxAMIDI[s], synthAuxAMIDISet[s]);
}
synthAuxACallback[s](SND_AUX_REASON_PARAMETERUPDATE, &info, synthAuxAUser[s]);
}
if (synthAuxBMIDI[s] != 0xff) {
SND_AUX_INFO info; // r1+0xC
for (i = 0; i < SND_AUX_NUMPARAMETERS; ++i) {
info.data.parameterUpdate.para[i] =
inpGetAuxB(s, i, synthAuxBMIDI[s], synthAuxBMIDISet[s]);
}
synthAuxBCallback[s](SND_AUX_REASON_PARAMETERUPDATE, &info, synthAuxBUser[s]);
}
}
}
hwFrameDone();
synthRealTime += deltaTime;
}
u8 synthFXGetMaxVoices(u16 fid) {
@ -616,9 +930,437 @@ u32 synthFXStart(u16 fid, u8 vol, u8 pan, u8 studio, u32 itd) {
pan = fx->panning;
}
v = synthStartSound(fx->macro, fx->priority, fx->maxVoices, fx->key | 0x80, vol, pan, 0xFF,
0xFF, 0, 0, 0xFF, fx->vGroup, 0, studio, itd);
v = synthStartSound(fx->macro, fx->priority, fx->maxVoices,
#if MUSY_VERSION >= MUSY_VERSION_CHECK(2, 0, 0)
0, // TODO
#endif
fx->key | 0x80, vol, pan, 0xFF, 0xFF, 0, 0, 0xFF, fx->vGroup, 0, studio,
itd);
}
return v;
}
bool synthFXSetCtrl(u32 vid, u8 ctrl, u8 value) {
u32 i; // r31
u32 ret; // r29
ret = FALSE;
vid = vidGetInternalId(vid);
while (vid != SND_ID_ERROR) {
i = vid & 0xff;
if (vid == synthVoice[i].id) {
if ((synthVoice[i].cFlags & 0x2) != 0) {
inpSetMidiCtrl(ctrl, i, synthVoice[i].setup.midiSet, value);
} else {
inpSetMidiCtrl(ctrl, i, synthVoice[i].midiSet, value);
}
vid = synthVoice[i].child;
ret = TRUE;
} else {
return ret;
}
}
return ret;
}
bool synthFXSetCtrl14(u32 vid, u8 ctrl, u16 value) {
u32 i; // r31
u32 ret; // r29
ret = FALSE;
vid = vidGetInternalId(vid);
while (vid != SND_ID_ERROR) {
i = vid & 0xff;
if (vid == synthVoice[i].id) {
if ((synthVoice[i].cFlags & 0x2) != 0) {
inpSetMidiCtrl14(ctrl, i, synthVoice[i].setup.midiSet, value);
} else {
inpSetMidiCtrl14(ctrl, i, synthVoice[i].midiSet, value);
}
vid = synthVoice[i].child;
ret = TRUE;
} else {
return ret;
}
}
return ret;
}
void synthFXCloneMidiSetup(SYNTH_VOICE* dest, SYNTH_VOICE* src) {
inpFXCopyCtrl(SND_MIDICTRL_VOLUME, dest, src);
inpFXCopyCtrl(SND_MIDICTRL_PANNING, dest, src);
inpFXCopyCtrl(SND_MIDICTRL_REVERB, dest, src);
inpFXCopyCtrl(SND_MIDICTRL_PITCHBEND, dest, src);
inpFXCopyCtrl(SND_MIDICTRL_DOPPLER, dest, src);
}
bool synthFXVolume(u32 vid, u8 vol) {
u32 i; // r31
u32 ret; // r29
ret = FALSE;
vid = vidGetInternalId(vid);
while (vid != SND_ID_ERROR) {
i = vid & 0xff;
if (vid == synthVoice[i].id) {
if ((synthVoice[i].cFlags & 0x2) != 0) {
inpSetMidiCtrl(SND_MIDICTRL_VOLUME, i, synthVoice[i].setup.midiSet, vol);
} else {
inpSetMidiCtrl(SND_MIDICTRL_VOLUME, i, synthVoice[i].midiSet, vol);
}
vid = synthVoice[i].child;
ret = TRUE;
} else {
return ret;
}
}
return ret;
}
u32 synthSendKeyOff(u32 voiceid) {
u32 i; // r30
u32 ret; // r29
ret = FALSE;
if (sndActive != 0) {
voiceid = vidGetInternalId(voiceid);
while (voiceid != SND_ID_ERROR) {
i = voiceid & 0xff;
if (voiceid == synthVoice[i].id) {
macSetExternalKeyoff(&synthVoice[i]);
ret = TRUE;
}
voiceid = synthVoice[i].child;
}
}
return ret;
}
u16 synthGetVolume(u32 vid) {
u32 i; // r30
vid = vidGetInternalId(vid);
if (vid != SND_ID_ERROR) {
i = vid & 0xff;
if (vid == synthVoice[i].id && (synthVoice[i].cFlags & 0x2) == 0) {
return synthVoice[i].curOutputVolume;
}
}
return 0;
}
void SetupFader(SYNTHMasterFader* smf, u8 volume, u32 time, u8 seqMode, u32 seqId) {
smf->seqMode = seqMode;
smf->seqId = seqId;
if (time != 0) {
smf->start = smf->volume;
smf->target = (f32)volume * (1.f / 127.f);
smf->time = 1.f;
smf->deltaTime = 1280.f / (f32)time;
} else {
smf->volume = smf->target = (f32)volume * (1.f / 127.f);
if (smf->seqId != SND_ID_ERROR) {
HandleFaderTermination(smf);
}
}
}
void synthVolume(u8 volume, u16 time, u8 vGroup, u8 seqMode, u32 seqId) {
u32 ltime; // r1+0x14
u32 i; // r30
u8 type; // r29
SYNTHMasterFader* smf; // r31
if ((ltime = time) != 0) {
sndConvertMs(&ltime);
}
switch (vGroup) {
case SND_ALL_VOLGROUPS:
for (smf = synthMasterFader, i = 0; i < 32; ++i, ++smf) {
if (smf->type == 0 || smf->type == 1) {
SetupFader(smf, volume, ltime, seqMode, SND_ID_ERROR);
synthMasterFaderActiveFlags |= 1 << i;
}
}
return;
case SND_USERALL_VOLGROUPS:
for (smf = synthMasterFader, i = 0; i < 32; ++i, ++smf) {
if (smf->type == 2 || smf->type == 3) {
SetupFader(smf, volume, ltime, seqMode, SND_ID_ERROR);
synthMasterFaderActiveFlags |= 1 << i;
}
}
return;
case SND_USERMUSIC_VOLGROUPS:
type = 2;
goto setup_type;
case SND_USERFX_VOLGROUPS:
type = 3;
goto setup_type;
case SND_MUSIC_VOLGROUPS:
type = 0;
goto setup_type;
case SND_FX_VOLGROUPS:
type = 1;
goto setup_type;
setup_type:
for (smf = synthMasterFader, i = 0; i < 32; ++i, ++smf) {
if (smf->type == type) {
SetupFader(smf, volume, ltime, seqMode, SND_ID_ERROR);
synthMasterFaderActiveFlags |= 1 << i;
}
}
return;
default:
SetupFader(&synthMasterFader[vGroup], volume, ltime, seqMode, seqId);
synthMasterFaderActiveFlags |= 1 << vGroup;
return;
}
}
u32 synthIsFadeOutActive(u8 vGroup) {
if (synthMasterFader[vGroup].type != 4 && (synthMasterFaderActiveFlags & (1 << vGroup)) != 0 &&
synthMasterFader[vGroup].start > synthMasterFader[vGroup].target) {
return TRUE;
}
return FALSE;
}
void synthPauseVolume(u8 volume, u16 time, u8 vGroup) {
u32 i; // r30
u32 ltime; // r1+0x10
u8 type; // r28
SYNTHMasterFader* smf; // r31
if (time == 0) {
++time;
}
ltime = time & 0xffff;
sndConvertMs(&ltime);
switch (vGroup) {
case SND_ALL_VOLGROUPS:
for (smf = synthMasterFader, i = 0; i < 32; ++i, ++smf) {
if (synthMasterFader[i].type == 0 || synthMasterFader[i].type == 1) {
smf->pauseStart = smf->pauseVol;
smf->pauseTarget = (f32)volume * (1.f / 127.f);
smf->pauseTime = 1.f;
smf->pauseDeltaTime = 1280.f / (f32)ltime;
synthMasterFaderActiveFlags |= 1 << i;
}
}
return;
case SND_USERALL_VOLGROUPS:
for (smf = synthMasterFader, i = 0; i < 32; ++i, ++smf) {
if (synthMasterFader[i].type == 2 || synthMasterFader[i].type == 3) {
smf->pauseStart = smf->pauseVol;
smf->pauseTarget = (f32)volume * (1.f / 127.f);
smf->pauseTime = 1.f;
smf->pauseDeltaTime = 1280.f / (f32)ltime;
synthMasterFaderActiveFlags |= 1 << i;
}
}
return;
case SND_USERMUSIC_VOLGROUPS:
type = 2;
goto setup_type;
case SND_USERFX_VOLGROUPS:
type = 3;
goto setup_type;
case SND_MUSIC_VOLGROUPS:
type = 0;
goto setup_type;
case SND_FX_VOLGROUPS:
type = 1;
goto setup_type;
setup_type:
for (smf = synthMasterFader, i = 0; i < 32; ++i, ++smf) {
if (synthMasterFader[i].type == type) {
smf->pauseStart = smf->pauseVol;
smf->pauseTarget = (f32)volume * (1.f / 127.f);
smf->pauseTime = 1.f;
smf->pauseDeltaTime = 1280.f / (f32)ltime;
synthMasterFaderActiveFlags |= 1 << i;
}
}
return;
default:
smf = &synthMasterFader[vGroup];
smf->pauseStart = smf->pauseVol;
smf->pauseTarget = (f32)volume * (1.f / 127.f);
smf->pauseTime = 1.f;
smf->pauseDeltaTime = 1280.f / (f32)ltime;
synthMasterFaderActiveFlags |= 1 << vGroup;
return;
}
}
void synthSetMusicVolumeType(u8 vGroup, u8 type) {
if (sndActive) {
synthMasterFader[vGroup].type = type;
}
}
u32 synthHWMessageHandler(u32 mesg, u32 voiceID) {
u32 ret; // r30
ret = FALSE;
switch (mesg) {
case 0:
if (synthVoice[voiceID & 0xff].block != 0) {
break;
}
vsSampleEndNotify(hwGetVirtualSampleID(voiceID & 0xff));
if (voiceID != synthVoice[voiceID & 0xff].id) {
break;
}
macSampleEndNotify(&synthVoice[voiceID & 0xff]);
break;
case 1:
voiceKill(voiceID & 0xff);
break;
case 2:
ret = vsSampleStartNotify(voiceID);
break;
case 3:
vsSampleEndNotify(hwGetVirtualSampleID(voiceID & 0xff));
break;
default:
#line 1975
MUSY_ASSERT(FALSE);
break;
}
return ret;
}
void synthInit(u32 mixFrq, u32 numVoices) {
u32 i; // r31
synthRealTime = 0;
synthInfo.mixFrq = mixFrq;
synthSetBpm(120, 255, 0);
synthFlags = 0;
synthMessageCallback = NULL;
synthVoice = salMalloc(numVoices * sizeof(SYNTH_VOICE));
if (synthVoice == NULL) {
#line 2135
MUSY_FATAL("Fatal: Could not allocate synthesizer voice array.");
}
memset(synthVoice, 0, numVoices * sizeof(SYNTH_VOICE));
for (i = 0; i < numVoices; ++i) {
synthVoice[i].id = 0xffffffff;
synthVoice[i].cFlags = 0;
synthVoice[i].age = 0;
synthVoice[i].prio = 0;
synthVoice[i].midi = 0xff;
synthVoice[i].volume = 0;
synthVoice[i].volTable = 0;
synthVoice[i].revVolScale = 128;
synthVoice[i].revVolOffset = 0;
synthVoice[i].panning[0] = synthVoice[i].panTarget[0] = 0x400000;
synthVoice[i].panning[1] = synthVoice[i].panTarget[1] = 0;
synthVoice[i].sweepOff[0] = 0;
synthVoice[i].sweepOff[1] = 0;
synthVoice[i].sweepNum[0] = 0;
synthVoice[i].sweepNum[1] = 0;
synthVoice[i].block = 0;
synthVoice[i].vGroup = 23;
synthVoice[i].keyGroup = 0;
synthVoice[i].itdMode = 1;
synthVoice[i].lfo[0].period = 0;
synthVoice[i].lfo[0].value = 0;
synthVoice[i].lfo[0].lastValue = 0x7fff;
synthVoice[i].lfo[1].period = 0;
synthVoice[i].lfo[1].value = 0;
synthVoice[i].lfo[1].lastValue = 0x7fff;
synthVoice[i].portTime = 25600;
synthVoice[i].portType = 0;
synthVoice[i].studio = 0;
synthVoice[i].lowPrecisionJob.voice = i;
synthVoice[i].lowPrecisionJob.jobTabIndex = 0xff;
synthVoice[i].zeroOffsetJob.voice = i;
synthVoice[i].zeroOffsetJob.jobTabIndex = 0xff;
synthVoice[i].eventJob.voice = i;
synthVoice[i].eventJob.jobTabIndex = 0xff;
}
for (i = 0; i < 32; ++i) {
synthMasterFader[i].volume = 0.f;
synthMasterFader[i].pauseVol = 1.f;
synthMasterFader[i].type = 4;
}
synthMasterFaderActiveFlags = 0;
synthMasterFaderPauseActiveFlags = 0;
synthMasterFader[31].type = 1;
for (i = 0; i < 8; ++i) {
synthMasterFader[i + 23].type = 0;
}
synthMasterFader[21].volume = 1.f;
synthMasterFader[22].volume = 1.f;
inpInit(0);
for (i = 0; i < 8; ++i) {
synthAuxACallback[i] = NULL;
synthAuxAMIDI[i] = 0xff;
synthAuxBCallback[i] = NULL;
synthAuxBMIDI[i] = 0xff;
synthITDDefault[i].sfx = 0;
synthITDDefault[i].music = 0;
}
macInit();
vidInit();
synthInitAllocationAids();
for (i = 0; i < 16; ++i) {
synthGlobalVariable[i] = 0;
}
voiceInitLastStarted();
synthInitJobQueue();
hwSetMesgCallback(synthHWMessageHandler);
}
void synthExit() { salFree(synthVoice); }