musyx/runtime/synth progress

Former-commit-id: bfd8a4e1b3
This commit is contained in:
Luke Street 2023-07-04 17:18:48 -04:00
parent f6fd95fa72
commit 6c9d013207
4 changed files with 411 additions and 65 deletions

View File

@ -10,6 +10,10 @@
extern "C" {
#endif
#define CLAMP(value, min, max) ((value) > (max) ? (max) : (value) < (min) ? (min) : (value))
// TODO matching hack
#define CLAMP_INV(value, min, max) ((value) < (min) ? (min) : (value) > (max) ? (max) : (value))
typedef struct SYNTH_VOICELIST {
// total size: 0x4
u8 prev; // offset 0x0, size 0x1
@ -862,6 +866,9 @@ u32 dataInsertLayer(u16 cid, void* layerdata, u16 size);
u32 dataRemoveLayer(u16 sid);
u32 dataInsertFX(u16 gid, FX_TAB* fx, u16 fxNum);
FX_TAB* dataGetFX(u16 fid);
void* dataGetLayer(u16 cid, u16* n);
void* dataGetKeymap(u16 cid);
s32 hwInit(u32* frq, u16 numVoices, u16 numStudios, u32 flags); /* extern */
void hwInitSamplePlayback(u32 v, u16 smpID, void* newsmp, u32 set_defadsr, u32 prio,
u32 callbackUserValue, u32 setSRC, u8 itdMode);
@ -886,6 +893,7 @@ void synthInit(u32, u8); /* extern */
void synthSetBpm(u32 pbm, u8 set, u8 section);
void synthFXCloneMidiSetup(SYNTH_VOICE* dest, SYNTH_VOICE* src);
void synthSetMusicVolumeType(u8 vGroup, u8 type);
void synthAddJob(SYNTH_VOICE* svoice, SYNTH_JOBTYPE jobType, u32 deltaTime);
extern s32 synthGlobalVariable[16];
extern u16 voicePrioSortRootListRoot;
@ -895,6 +903,9 @@ extern u8 voiceListInsert;
extern u8 voiceListRoot;
void voiceSetPriority(SYNTH_VOICE* svoice, u8 prio);
u32 voiceIsLastStarted(SYNTH_VOICE* svoice);
void voiceSetLastStarted(SYNTH_VOICE* svoice);
void voiceResetLastStarted(SYNTH_VOICE* svoice);
void voiceInitLastStarted();
s32 voiceKillSound(u32 voiceid);
extern u64 synthRealTime;
@ -923,6 +934,7 @@ u8 hwInitStream(u32 len);
s16 varGet(SYNTH_VOICE* svoice, u32 ctrl, u8 index);
u32 sndGetPitch(u8 key, u32 sInfo);
s32 sndPitchUpOne(u16 note);
extern SND_HOOKS salHooks;
extern u8 sndActive;
extern u8 synthIdleWaitActive;
@ -1033,6 +1045,9 @@ void inpSetMidiLastNote(u8 midi, u8 midiSet, u8 key);
u16 inpGetModulation(SYNTH_VOICE* svoice);
void inpResetMidiCtrl(u8 ch, u8 set, u32 coldReset);
void inpResetChannelDefaults(u8 midi, u8 midiSet);
u16 inpGetPitchBend(SYNTH_VOICE* svoice);
u16 inpGetDoppler(SYNTH_VOICE* svoice);
/* TODO: Figure out what `unk` is */
void hwSetSRCType(u32 v, u8 salSRCType);
void hwSetITDMode(u32 v, u8 mode);
@ -1066,6 +1081,12 @@ void sndProfUpdateMisc(SND_PROFILE_INFO* info);
void sndProfResetPMC(SND_PROFILE_DATA* info);
void sndProfStartPMC(SND_PROFILE_DATA* info);
void vidRemoveVoiceReferences(SYNTH_VOICE* svoice);
u32 vidMakeNew(SYNTH_VOICE* svoice, u32 isMaster);
u32 vidMakeRoot(SYNTH_VOICE* svoice);
u32 adsrHandleLowPrecision(ADSR_VARS* adsr, u16* adsr_start, u16* adsr_delta);
#ifdef __cplusplus
}
#endif

View File

@ -1082,8 +1082,6 @@ static SEQ_EVENT* GetGlobalEvent(SEQ_SECTION* section) {
return ev;
}
#define Clamp(value, min, max) ((value) > (max) ? (max) : (value) < (min) ? (min) : (value))
static SEQ_EVENT* HandleEvent(SEQ_EVENT* event, u8 secIndex, u32* loopFlag) {
CPAT* pa; // r26
NOTE_DATA* pe; // r24
@ -1169,10 +1167,10 @@ static SEQ_EVENT* HandleEvent(SEQ_EVENT* event, u8 secIndex, u32* loopFlag) {
if ((cseq->trackMute[event->trackId / 32] & (1 << (event->trackId & 0x1f))) != 0) {
if ((macId = cseq->prgState[midi].macId) != 0xffff) {
key += pa->patternInfo->transpose;
key = Clamp(key, 0, 0x7f);
key = CLAMP(key, 0, 0x7f);
velocity += pa->patternInfo->velocityAdd;
velocity = Clamp(velocity, 0, 0x7f);
velocity = CLAMP(velocity, 0, 0x7f);
if ((note = AllocateNote(event->time + pe->length, secIndex)) != NULL) {
if ((note->id = synthStartSound(

View File

@ -5,7 +5,7 @@ static u32 synthTicksPerSecond[9][16];
static SYNTH_JOBTAB synthJobTable[32];
CTRL_DEST inpAuxA[8][4];
CTRL_DEST inpAuxB[8][4];
long synthGlobalVariable[16];
s32 synthGlobalVariable[16];
synthITDInfo synthITDDefault[8];
void* synthAuxBUser[8];
SND_AUX_CALLBACK synthAuxBCallback[8];
@ -85,7 +85,53 @@ static u32 do_voice_portamento(u8 key, u8 midi, u8 midiSet, u32 isMaster, u32* r
u32 id; // r27
SYNTH_VOICE* sv; // r31
SYNTH_VOICE* last_sv; // r28
u32 legatoVoiceIsStarting; // r26
bool legatoVoiceIsStarting; // r26
legatoVoiceIsStarting = FALSE;
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 ((sv->cFlags & 2) != 0) {
legatoVoiceIsStarting = TRUE;
}
if ((sv->cFlags & 0x10) != 0 && (sv->cFlags & 0x10000000008) != 0x8 && hwIsActive(i)) {
if (vid == SND_ID_ERROR && (sv->cFlags & 0x20002) == 0x20002) {
*rejected = TRUE;
return SND_ID_ERROR;
}
last_sv = sv;
sv->portCurPitch = (sv->curNote * 65536) + (sv->curDetune * 65536) / 100;
sv->lastNote = sv->curNote;
sv->curNote = key + ((sv->curNote & 0xff) - sv->orgNote);
sv->orgNote = key;
sv->curDetune = 0;
sv->portTime = 0;
sv->cFlags |= 0x20000;
vidRemoveVoiceReferences(&synthVoice[i]);
if (vid == SND_ID_ERROR) {
sv->child = SND_ID_ERROR;
sv->parent = SND_ID_ERROR;
vid = vidMakeNew(&synthVoice[i], isMaster);
id = sv->id;
} else {
synthVoice[id & 0xff].child = sv->id;
sv->parent = id;
id = sv->id;
vidMakeNew(&synthVoice[i], FALSE);
}
}
}
}
if (vid != SND_ID_ERROR) {
voiceSetLastStarted(last_sv);
inpSetMidiLastNote(last_sv->midi, last_sv->midiSet, last_sv->curNote);
*rejected = FALSE;
} else {
*rejected = legatoVoiceIsStarting;
}
return vid;
}
static u32 check_portamento(u8 key, u8 midi, u8 midiSet, u32 newVID, u32* vid) {
@ -99,6 +145,10 @@ static u32 check_portamento(u8 key, u8 midi, u8 midiSet, u32 newVID, u32* vid) {
return 1;
}
static u32 StartKeymap(u16 keymapID, s16 prio, u8 maxVoices, u16 allocId, u8 key, u8 vol,
u8 panning, u8 midi, u8 midiSet, u8 section, u16 step, u16 trackid,
u32 vidFlag, u8 vGroup, u8 studio, u32 itd);
static u32 StartLayer(u16 layerID, s16 prio, u8 maxVoices, u16 allocId, u8 key, u8 vol, u8 panning,
u8 midi, u8 midiSet, u8 section, u16 step, u16 trackid, u32 vidFlag,
u8 vGroup, u8 studio, u32 itd) {
@ -107,33 +157,178 @@ static u32 StartLayer(u16 layerID, s16 prio, u8 maxVoices, u16 allocId, u8 key,
u32 new_id; // r1+0x34
u32 id; // r27
LAYER* l; // r31
long p; // r30
long k; // r29
s32 p; // r30
s32 k; // r29
u8 v; // r25
u8 mKey; // r24
vid = SND_ID_ERROR;
if ((l = dataGetLayer(layerID, &n)) == NULL) {
goto end;
}
mKey = key & 0x7f;
for (; n != 0; --n, ++l) {
if (l->id == 0xffff || l->keyLow > mKey || l->keyHigh < mKey) {
continue;
}
k = mKey + l->transpose;
k = CLAMP(k, 0, 127);
if ((l->id & 0xC000) == 0) {
if (check_portamento(k, midi, midiSet, vidFlag, &new_id)) {
if (new_id != 0xFFFFFFFF) {
goto apply_new_id;
} else {
goto start_new_id;
}
}
continue;
}
start_new_id:
if ((l->panning & 0x80) == 0) {
p = l->panning - 0x40;
p += panning;
// TODO
// p = CLAMP(p, 0, 0x7f);
p = CLAMP_INV(p, 0, 0x7f);
} else {
p = 0x80;
}
v = (vol * l->volume) / 0x7f;
prio += l->prioOffset;
prio = CLAMP(prio, 0, 0xff);
switch (l->id & 0xC000) {
case 0:
new_id = macStart(l->id, prio, maxVoices, allocId, k | key & 0x80, v, p, midi, midiSet,
section, step, trackid, 0, vGroup, studio, itd);
break;
case 0x4000:
new_id = StartKeymap(l->id, prio, maxVoices, allocId, k | key & 0x80, v, p, midi, midiSet,
section, step, trackid, 0, vGroup, studio, itd);
break;
case 0x8000:
new_id = StartLayer(l->id, prio, maxVoices, allocId, k | key & 0x80, v, p, midi, midiSet,
section, step, trackid, 0, vGroup, studio, itd);
break;
}
if (new_id != SND_ID_ERROR) {
apply_new_id:
if (vid == SND_ID_ERROR) {
if (vidFlag != 0) {
vid = vidMakeRoot(&synthVoice[new_id & 0xff]);
} else {
vid = new_id;
}
} else {
synthVoice[id & 0xff].child = new_id;
synthVoice[new_id & 0xff].parent = id;
}
id = new_id;
while (synthVoice[id & 0xff].child != SND_ID_ERROR) {
id = synthVoice[id & 0xff].child;
}
}
}
end:
return vid;
}
static u32 StartKeymap(u16 keymapID, s16 prio, u8 maxVoices, u16 allocId, u8 key, u8 vol,
u8 panning, u8 midi, u8 midiSet, u8 section, u16 step, u16 trackid,
u32 vidFlag, u8 vGroup, u8 studio, u32 itd) {
u8 o; // r30
struct KEYMAP* keymap; // r31
long p; // r26
long k; // r29
KEYMAP* keymap; // r31
s32 p; // r26
s32 k; // r29
u32 vid; // r1+0x34
if ((keymap = dataGetKeymap(keymapID)) != NULL) {
o = key & 0x7f;
if (keymap[o].id != 0xffff && (keymap[o].id & 0xc000) != 0x4000) {
if ((keymap[o].panning & 0x80) == 0) {
p = (keymap[key].panning - 0x40);
p += panning;
if (p < 0) {
panning = 0;
} else if (p > 0x7f) {
panning = 0x7f;
} else {
panning = p;
}
} else {
panning = 0x80;
}
k = (key & 0x7f) + keymap[o].transpose;
k = CLAMP(k, 0, 127);
prio += keymap[o].prioOffset;
prio = CLAMP(prio, 0, 0xff);
if ((keymap[o].id & 0xc000) == 0) {
if (!check_portamento(k & 0xff, midi, midiSet, vidFlag, &vid)) {
return 0xffffffff;
}
if (vid != 0xffffffff) {
return vid;
}
return macStart(keymap[o].id, prio, maxVoices, allocId, k | key & 0x80, vol, panning, midi,
midiSet, section, step, trackid, vidFlag, vGroup, studio, itd);
}
return StartLayer(keymap[o].id, prio, maxVoices, allocId, k | key & 0x80, vol, panning, midi,
midiSet, section, step, trackid, vidFlag & 0xff, vGroup, studio, itd);
}
}
return SND_ID_ERROR;
}
#pragma dont_inline on
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
prio += prioOffset;
prio = CLAMP(prio, 0, 0xff);
switch (id & 0xC000) {
case 0:
if (!check_portamento(key, midi, midiSet, 1, &vid)) {
return 0xffffffff;
}
if (vid != 0xffffffff) {
return vid;
}
return macStart(id, prio, max, id, key, vol, panning, midi, midiSet, section, step, trackid, 1,
vGroup, studio, itd);
case 0x4000:
return StartKeymap(id, prio, max, id, key, vol, panning, midi, midiSet, section, step, trackid,
1, vGroup, studio, itd);
case 0x8000:
return StartLayer(id, prio, max, id, key, vol, panning, midi, midiSet, section, step, trackid,
1, vGroup, studio, itd);
default:
return SND_ID_ERROR;
}
}
#pragma dont_inline reset
static u32 convert_cents(SYNTH_VOICE* svoice, u32 ccents) {
unsigned long curDetune; // r30
unsigned long cpitch; // r31
u32 curDetune; // r30
u32 cpitch; // r31
cpitch = sndGetPitch(ccents / 65536, svoice->sInfo) * 65536;
if ((curDetune = ccents & 0xffff) != 0) {
cpitch += curDetune * ((sndPitchUpOne(cpitch / 65536) & 0xffff) - (cpitch / 65536 & 0xffff));
}
return cpitch;
}
static void UpdateTimeMIDICtrl(SYNTH_VOICE* sv) {
@ -145,42 +340,174 @@ static void UpdateTimeMIDICtrl(SYNTH_VOICE* sv) {
sv->midiDirtyFlags = 0x1fff;
}
static void LowPrecisionHandler(unsigned long i) {
unsigned long j; // r30
long pbend; // r29
unsigned long ccents; // r28
unsigned long cpitch; // r26
unsigned short Modulation; // r24
unsigned short portamento; // r25
unsigned long lowDeltaTime; // r27
struct SYNTH_VOICE* sv; // r31
unsigned long cntDelta; // r20
unsigned long addFactor; // r19
unsigned short adsr_start; // r1+0xE
unsigned short adsr_delta; // r1+0xC
long vrange; // r23
long voff; // r22
static void LowPrecisionHandler(u32 i) {
u32 j; // r30
s32 pbend; // r29
u32 ccents; // r28
u32 cpitch; // r26
u16 Modulation; // r24
u16 portamento; // r25
u32 lowDeltaTime; // r27
SYNTH_VOICE* sv; // r31
u32 cntDelta; // r20
u32 addFactor; // r19
u16 adsr_start; // r1+0xE
u16 adsr_delta; // r1+0xC
s32 vrange; // r23
s32 voff; // r22
sv = &synthVoice[i];
if (!hwIsActive(i) && sv->addr == NULL) {
goto end;
}
lowDeltaTime = synthRealTime - sv->lastLowCallTime;
sv->lastLowCallTime = synthRealTime;
for (j = 0; j < 2; ++j) {
if (sv->lfo[j].period == 0) {
continue;
}
sv->lfo[j].time += lowDeltaTime;
sv->lfo[j].value =
sndSin((sv->lfo[j].time % sv->lfo[j].period * 16) / (sv->lfo[j].period / 256));
if (sv->lfo[j].value != sv->lfo[j].lastValue) {
sv->lfo[j].lastValue = sv->lfo[j].value;
if (sv->lfoUsedByInput[j]) {
sv->lfoUsedByInput[j] = 0;
sv->midiDirtyFlags |= 0x1fff;
}
}
}
if ((sv->cFlags & 0x2000) != 0) {
sv->vibCurTime += lowDeltaTime;
sv->vibCurOffset = sndSin((sv->vibCurTime % sv->vibPeriod * 16) / (sv->vibPeriod / 256));
}
if (sv->sweepNum[0] | sv->sweepNum[1]) {
cntDelta = (lowDeltaTime & 0x00ffffff) << 4;
addFactor = lowDeltaTime & 0x0fffffff;
for (j = 0; j < 2; ++j) {
if (sv->sweepNum[j] == 0) {
continue;
}
sv->sweepCnt[j] -= cntDelta;
if (sv->sweepCnt[j] <= 0) {
sv->sweepCnt[j] = sv->sweepNum[j] << 16;
sv->sweepOff[j] = 0;
} else {
sv->sweepOff[j] += (sv->sweepAdd[j] >> 12) * addFactor;
}
}
}
for (j = 0; j < 2; ++j) {
if (sv->panning[j] == sv->panTarget[j]) {
continue;
}
sv->panTime[j] -= lowDeltaTime;
if ((s32)sv->panTime[j] <= 0) {
sv->panning[j] = sv->panTarget[j];
sv->panTime[j] = 0;
} else {
sv->panning[j] = sv->panTarget[j] - (sv->panTime[j] / 256) * sv->panDelta[j];
sv->panning[j] = CLAMP_INV((s32)sv->panning[j], 0, 0x7f0000u);
}
sv->cFlags |= 0x200000000000;
}
if ((sv->cFlags & 0x20000000000) != 0 &&
adsrHandleLowPrecision(&sv->pitchADSR, &adsr_start, &adsr_delta)) {
sv->cFlags &= ~0x20000000000;
}
ccents = sv->curNote * 65536 + (sv->curDetune * 65536) / 100;
if ((sv->cFlags & 0x10010) != 0) {
if (sv->midi != 0xff) {
pbend = inpGetPitchBend(sv);
sv->pbLast = pbend;
goto pbend_adjust;
}
} else {
pbend = sv->pbLast;
pbend_adjust:
if (pbend != 0x2000) {
pbend -= 0x2000;
if (pbend < 0) {
ccents += sv->pbLowerKeyRange * pbend * 8;
} else {
ccents += sv->pbUpperKeyRange * pbend * 8;
}
}
}
if ((sv->cFlags & 0x2000) != 0) {
Modulation = inpGetModulation(sv);
vrange = sv->vibKeyRange * 256 + (sv->vibCentRange * 256) / 100;
if (sv->vibModAddScale != 0) {
vrange += (sv->vibModAddScale * ((Modulation >> 7) & 0x1ff)) >> 7;
}
if ((sv->cFlags & 0x4000) != 0) {
voff = (sv->vibCurOffset * ((Modulation >> 7) & 0x1ff)) >> 7;
} else {
voff = sv->vibCurOffset;
}
ccents += (vrange * voff) >> 4;
}
if (sv->midi != 0xff) {
portamento = inpGetMidiCtrl(SND_MIDICTRL_PORTAMENTO, sv->midi, sv->midiSet);
if (portamento != sv->portLastCtrlState || (sv->cFlags & 0x21000) == 0x20000) {
if (portamento <= 0x1f80) {
sv->cFlags &= ~0x400;
} else {
if ((sv->cFlags & 0x400) == 0) {
synthInitPortamento(sv);
}
sv->cFlags |= 0x400;
}
sv->cFlags |= 0x1000;
sv->portLastCtrlState = portamento;
}
}
ccents = apply_portamento(sv, ccents, lowDeltaTime);
if ((sv->cFlags & 0x20000000000) != 0) {
ccents += sv->pitchADSRRange * (sv->pitchADSR.currentVolume >> 16) >> 7;
}
cpitch = convert_cents(sv, ccents);
cpitch += sv->sweepOff[0] + sv->sweepOff[1];
cpitch = ((cpitch >> 16) * inpGetDoppler(sv)) >> 13;
sv->curPitch = cpitch;
hwSetPitch(i, cpitch);
synthAddJob(sv, 0, 0xf00);
end:
UpdateTimeMIDICtrl(sv);
}
static void ZeroOffsetHandler(unsigned long i) {
struct SYNTH_VOICE* sv; // r31
unsigned long lowDeltaTime; // r26
unsigned short Modulation; // r25
float vol; // r62
float auxa; // r57
float auxb; // r56
float f; // r59
float voiceVol; // r60
unsigned long volUpdate; // r30
float lfo; // r55
float scale; // r63
float mscale; // r54
long pan; // r28
float preVol; // r58
float postVol; // r61
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
s32 pan; // r28
f32 preVol; // r58
f32 postVol; // r61
}
static void EventHandler(unsigned long i) {
static void EventHandler(u32 i) {
SYNTH_VOICE* sv; // r31
}
@ -197,7 +524,7 @@ static void synthInitJobQueue() {
}
#pragma dont_inline on
void synthAddJob(SYNTH_VOICE* svoice, SYNTH_JOBTYPE jobType, unsigned long deltaTime) {
void synthAddJob(SYNTH_VOICE* svoice, SYNTH_JOBTYPE jobType, u32 deltaTime) {
SYNTH_QUEUE* newJq; // r31
SYNTH_QUEUE** root; // r30
u8 jobTabIndex; // r29
@ -219,7 +546,7 @@ void synthForceLowPrecisionUpdate(SYNTH_VOICE* svoice) {
void synthKeyStateUpdate(SYNTH_VOICE* svoice) { synthAddJob(svoice, SYNTH_JOBTYPE_EVENT, 0); }
void HandleJobQueue(SYNTH_QUEUE** queueRoot, void (*handler)(unsigned long)) {
void HandleJobQueue(SYNTH_QUEUE** queueRoot, void (*handler)(u32)) {
SYNTH_QUEUE* jq; // r31
SYNTH_QUEUE* nextJq; // r30
@ -259,15 +586,15 @@ void HandleFaderTermination(SYNTHMasterFader* smf) {
}
}
void synthHandle(unsigned long deltaTime) {
unsigned long i; // r29
unsigned long s; // r30
void synthHandle(u32 deltaTime) {
u32 i; // r29
u32 s; // r30
SYNTHMasterFader* smf; // r31
unsigned long testFlag; // r27
u32 testFlag; // r27
SND_AUX_INFO info; // r1+0x18
}
unsigned char synthFXGetMaxVoices(u16 fid) {
u8 synthFXGetMaxVoices(u16 fid) {
FX_TAB* fx;
if ((fx = dataGetFX(fid)) != NULL) {
return fx->maxVoices;

View File

@ -202,7 +202,7 @@ void* dataGetKeymap(unsigned short cid) {
long layercmp(void* p1, void* p2) { return ((LAYER_TAB*)p1)->id - ((LAYER_TAB*)p2)->id; }
void* dataGetLayer(unsigned short cid, unsigned short* n) {
void* dataGetLayer(u16 cid, u16* n) {
static LAYER_TAB key;
static LAYER_TAB* result;