Vibrato optimizations (#530)

Optimize vibrato to even exceed vanilla's implementation, all without restricting usability from the current implementation. This should save up to about 1ms of audio runtime.
This commit is contained in:
Gregory Heskett
2023-01-20 17:45:53 -05:00
committed by GitHub
parent 65d29dc337
commit dc71aef024
6 changed files with 68 additions and 30 deletions

View File

@@ -189,23 +189,33 @@ s32 get_vibrato_pitch_change(struct VibratoState *vib) {
#endif
f32 get_vibrato_freq_scale(struct VibratoState *vib) {
s32 vibratoExtentTarget;
if (vib->delay != 0) {
vib->delay--;
return 1;
}
// This needs to be set locally because changing the original value to 0 overrides the whole channel,
// effectively negating the ability to disable vibrato and bypass this function in the first place.
// This function isn't huge but it otherwise would get called many thousands of times per second.
vibratoExtentTarget = vib->seqChannel->vibratoExtentTarget;
if (vibratoExtentTarget >= VIBRATO_DISABLED_VALUE) {
vibratoExtentTarget = 0;
}
if (vib->extentChangeTimer) {
if (vib->extentChangeTimer == 1) {
vib->extent = (s32) vib->seqChannel->vibratoExtentTarget;
vib->extent = vibratoExtentTarget;
} else {
vib->extent +=
((s32) vib->seqChannel->vibratoExtentTarget - vib->extent) / (s32) vib->extentChangeTimer;
(vibratoExtentTarget - vib->extent) / (s32) vib->extentChangeTimer;
}
vib->extentChangeTimer--;
} else if (vib->seqChannel->vibratoExtentTarget != (s32) vib->extent) {
} else if (vibratoExtentTarget != (s32) vib->extent) {
if ((vib->extentChangeTimer = vib->seqChannel->vibratoExtentChangeDelay) == 0) {
vib->extent = (s32) vib->seqChannel->vibratoExtentTarget;
vib->extent = vibratoExtentTarget;
}
}
@@ -246,11 +256,11 @@ void note_vibrato_update(struct Note *note) {
note->vibratoFreqScale = get_vibrato_freq_scale(&note->vibratoState);
}
#else
if (note->vibratoState.active) {
if (note->vibratoState.activeFlags & VIBMODE_PORTAMENTO) {
note->portamentoFreqScale = get_portamento_freq_scale(&note->portamento);
if (note->parentLayer != NO_LAYER) {
note->vibratoFreqScale = get_vibrato_freq_scale(&note->vibratoState);
}
}
if ((note->vibratoState.activeFlags & VIBMODE_VIBRATO) && note->parentLayer != NO_LAYER) {
note->vibratoFreqScale = get_vibrato_freq_scale(&note->vibratoState);
}
#endif
}
@@ -265,18 +275,23 @@ void note_vibrato_init(struct Note *note) {
struct VibratoState *vib = &note->vibratoState;
/* This code was probably removed from EU and SH for a reason; probably because it's dumb and makes vibrato harder to use well.
#if defined(VERSION_JP) || defined(VERSION_US)
if (note->parentLayer->seqChannel->vibratoExtentStart == 0
&& note->parentLayer->seqChannel->vibratoExtentTarget == 0
&& note->parentLayer->portamento.mode == 0) {
vib->active = FALSE;
vib->activeFlags = VIBMODE_NONE;
if (note->parentLayer->portamento.mode != 0) {
vib->activeFlags |= VIBMODE_PORTAMENTO;
note->portamento = note->parentLayer->portamento;
}
if (!(note->parentLayer->seqChannel->vibratoExtentStart == 0
&& note->parentLayer->seqChannel->vibratoExtentTarget >= VIBRATO_DISABLED_VALUE)) {
vib->activeFlags |= VIBMODE_VIBRATO;
} else {
return;
}
#endif
*/
#else
vib->active = TRUE;
#endif
vib->time = 0;
#if defined(VERSION_EU) || defined(VERSION_SH)
@@ -313,8 +328,6 @@ void note_vibrato_init(struct Note *note) {
vib->rate = seqChannel->vibratoRateStart;
}
vib->delay = seqChannel->vibratoDelay;
note->portamento = note->parentLayer->portamento;
#endif
}

View File

@@ -31,6 +31,12 @@ enum ADSRDelays {
ADSR_RESTART = -3,
};
enum VibratoModes {
VIBMODE_NONE = 0,
VIBMODE_VIBRATO = (1 << 0),
VIBMODE_PORTAMENTO = (1 << 1),
};
// Envelopes are always stored as big endian, to match sequence files which are
// byte blobs and can embed envelopes. Hence this byteswapping macro.
#if IS_BIG_ENDIAN

View File

@@ -27,6 +27,8 @@
#endif
#endif // EXPAND_AUDIO_HEAP
#define VIBRATO_DISABLED_VALUE (0xFF * 8)
#define NO_LAYER ((struct SequenceChannelLayer *)(-1))
enum MuteBehaviors {
@@ -139,7 +141,7 @@ struct VibratoState {
/* , 0x14*/ u8 active;
#else
/*0x08, */ s8 *curve;
/*0x0C, */ u8 active;
/*0x0C, */ u8 activeFlags;
/*0x0E, */ u16 rate;
/*0x10, */ u16 extent;
#endif

View File

@@ -1423,6 +1423,7 @@ void note_init_all(void) {
note->prevParentLayer = NO_LAYER;
#if defined(VERSION_EU) || defined(VERSION_SH)
note->waveId = 0;
note->vibratoState.active = FALSE;
#else
note->reverbVol = 0;
note->usesHeadsetPanEffects = FALSE;
@@ -1432,12 +1433,12 @@ void note_init_all(void) {
note->targetVolRight = 0;
note->frequency = 0.0f;
note->unused1 = 0x3f;
note->vibratoState.activeFlags = VIBMODE_NONE;
#endif
note->attributes.velocity = 0.0f;
note->adsrVolScale = 0;
note->adsr.state = ADSR_STATE_DISABLED;
note->adsr.action = 0;
note->vibratoState.active = FALSE;
note->portamento.cur = 0.0f;
note->portamento.speed = 0.0f;
#if defined(VERSION_SH)

View File

@@ -64,7 +64,7 @@ void sequence_channel_init(struct SequenceChannel *seqChannel) {
#endif
seqChannel->vibratoRateTarget = 0x800;
seqChannel->vibratoRateStart = 0x800;
seqChannel->vibratoExtentTarget = 0;
seqChannel->vibratoExtentTarget = VIBRATO_DISABLED_VALUE;
seqChannel->vibratoExtentStart = 0;
seqChannel->vibratoRateChangeDelay = 0;
seqChannel->vibratoExtentChangeDelay = 0;
@@ -1942,7 +1942,7 @@ void sequence_channel_process_script(struct SequenceChannel *seqChannel) {
break;
case 0xec:
seqChannel->vibratoExtentTarget = 0;
seqChannel->vibratoExtentTarget = VIBRATO_DISABLED_VALUE;
seqChannel->vibratoExtentStart = 0;
seqChannel->vibratoExtentChangeDelay = 0;
seqChannel->vibratoRateTarget = 0;