From 10505e9e984ff6d40f1b1140be0431ea8f0c68a5 Mon Sep 17 00:00:00 2001 From: Guy Perfect Date: Tue, 18 Feb 2025 15:09:15 -0600 Subject: [PATCH] Supporting additional VSU edge cases --- core/vb.c | 12 ++++++----- core/vsu.c | 59 ++++++++++++++++++++++++++++++++++++++++++------------ 2 files changed, 53 insertions(+), 18 deletions(-) diff --git a/core/vb.c b/core/vb.c index e22cb37..d0dfe96 100644 --- a/core/vb.c +++ b/core/vb.c @@ -28,8 +28,9 @@ typedef struct { uint8_t value; /* Master output level */ /* Other state */ - uint32_t clocks; /* Clocks until modification */ - uint8_t reload; /* Automatic reload value */ + uint32_t clocks; /* Clocks until modification */ + uint8_t modmask; /* Modifications masked */ + uint8_t reload; /* Automatic reload value */ } env; /* Frequency */ @@ -359,9 +360,10 @@ struct VB { uint8_t shift; /* Sweep shift amount */ /* Other state */ - uint32_t clocks; /* Clocks until modification */ - uint16_t next; /* Next frequency value */ - int sample; /* Current sample index */ + uint32_t clocks; /* Clocks until modification */ + uint8_t modmask; /* Modifications masked */ + uint16_t next; /* Next frequency value */ + int sample; /* Current sample index */ } freqmod; /* Channel 6 noise generator */ diff --git a/core/vsu.c b/core/vsu.c index 9e4b23a..8ed69e7 100644 --- a/core/vsu.c +++ b/core/vsu.c @@ -45,9 +45,22 @@ static void vsuOnSamples(VB *sim) { /***************************** Module Functions ******************************/ +/* Determine while frequency modifications should be processed */ +static uint8_t vsuCheckFreqMod(VB *sim) { + return + sim->vsu.freqmod.enb && + sim->vsu.freqmod.interval != 0 && ( + !sim->vsu.freqmod.modmask || ( + sim->vsu.freqmod.func == 1 && + sim->vsu.freqmod.rep + ) + ) + ; +} + /* Stage the next frequency modification value */ static void vsuNextFreqMod(VB *sim, Channel *chan) { - uint16_t next; + int32_t next; /* Sweep */ if (sim->vsu.freqmod.func == 0) { @@ -57,16 +70,32 @@ static void vsuNextFreqMod(VB *sim, Channel *chan) { else next = chan->freq.current + next; if (next > 2047) chan->int_.enb = 0; + if (next < 0) + next = 0; } /* Modulation */ else { - next = (chan->freq.written + - sim->vsu.modulation[sim->vsu.freqmod.sample]) & 2047; + + /* Compute the modulated value */ + next = (int32_t) chan->freq.written + + sim->vsu.modulation[sim->vsu.freqmod.sample]; + if (next < 0) + next = 0; + if (next > 2047) + next = 2047; + + /* Not the final modulation sample */ if (sim->vsu.freqmod.sample != 31) sim->vsu.freqmod.sample++; - else if (sim->vsu.freqmod.rep) - sim->vsu.freqmod.sample = 0; + + /* Last modulation sample processed */ + else { + sim->vsu.freqmod.modmask = 1; + if (sim->vsu.freqmod.rep) + sim->vsu.freqmod.sample = 0; + } + } /* Configure state */ @@ -106,13 +135,14 @@ static void vsuEmulateChannel(VB *sim, Channel *chan) { } /* Envelope modification */ - if (chan->env.enb && chan->env.clocks == 0) { + if (chan->env.enb && !chan->env.modmask && chan->env.clocks == 0) { if (chan->env.dir == 0 && chan->env.value != 0) chan->env.value--; else if (chan->env.dir == 1 && chan->env.value != 15) chan->env.value++; else if (chan->env.rep) chan->env.value = chan->env.reload; + else chan->env.modmask = 1; chan->env.clocks = ((uint32_t) chan->env.interval + 1) * 307220; } @@ -186,9 +216,8 @@ static void vsuWriteEV1(VB *sim, int index, uint8_t value) { sim->vsu.freqmod.enb = value >> 6 & 1; sim->vsu.freqmod.func = value >> 4 & 1; sim->vsu.freqmod.rep = value >> 5 & 1; + chan->freqmod = vsuCheckFreqMod(sim); vsuNextFreqMod(sim, chan); - chan->freqmod = - sim->vsu.freqmod.enb && sim->vsu.freqmod.interval != 0; break; case 5: /* Channel 6 */ @@ -228,6 +257,7 @@ static void vsuWriteINT(VB *sim, int index, uint8_t value) { /* Update state */ chan->int_.clocks = 76805 * ((uint32_t) chan->int_.interval + 1); + chan->env.modmask = 0; if (chan->env.enb) chan->env.clocks = 307220 * ((uint32_t) chan->env.interval + 1); if (index != 5) { @@ -240,7 +270,8 @@ static void vsuWriteINT(VB *sim, int index, uint8_t value) { if (index == 4) { sim->vsu.freqmod.clocks = (uint32_t) sim->vsu.freqmod.interval * (sim->vsu.freqmod.clk == 0 ? 19200 : 153600); - sim->vsu.freqmod.sample = 0; + sim->vsu.freqmod.modmask = 0; + sim->vsu.freqmod.sample = 0; } } @@ -272,8 +303,7 @@ static void vsuWriteSWP(VB *sim, uint8_t value) { (sim->vsu.freqmod.clk == 0 ? 19200 : 153600); if (clocks < sim->vsu.freqmod.clocks) sim->vsu.freqmod.clocks = clocks; - sim->vsu.channels[4].freqmod = - sim->vsu.freqmod.enb && sim->vsu.freqmod.interval != 0; + sim->vsu.channels[4].freqmod = vsuCheckFreqMod(sim); } @@ -315,7 +345,8 @@ static void vsuEmulate(VB *sim, uint32_t clocks) { /* Clocks until next state change */ chan->until = chan->clocks; - if (chan->env.enb && chan->env.clocks < chan->until) + if (chan->env.enb && !chan->env.modmask && + chan->env.clocks < chan->until) chan->until = chan->env.clocks; if (chan->int_.auto_ && chan->int_.clocks < chan->until) chan->until = chan->int_.clocks; @@ -324,7 +355,7 @@ static void vsuEmulate(VB *sim, uint32_t clocks) { /* Manage clocks */ chan->clocks -= chan->until; - if (chan->env.enb) + if (chan->env.enb && !chan->env.modmask) chan->env.clocks -= chan->until; if (chan->int_.auto_) chan->int_.clocks -= chan->until; @@ -427,6 +458,7 @@ static void vsuReset(VB *sim) { chan->env.enb = 0; chan->env.dir = 0; chan->env.interval = 0; + chan->env.modmask = 0; chan->env.reload = 0; chan->env.rep = 0; chan->env.value = 0; @@ -449,6 +481,7 @@ static void vsuReset(VB *sim) { sim->vsu.freqmod.enb = 0; sim->vsu.freqmod.func = 0; sim->vsu.freqmod.interval = 0; + sim->vsu.freqmod.modmask = 0; sim->vsu.freqmod.next = 0; sim->vsu.freqmod.rep = 0; sim->vsu.freqmod.sample = 0;