Supporting additional VSU edge cases

This commit is contained in:
Guy Perfect 2025-02-18 15:09:15 -06:00
parent 155a3aa678
commit 10505e9e98
2 changed files with 53 additions and 18 deletions

View File

@ -29,6 +29,7 @@ typedef struct {
/* Other state */
uint32_t clocks; /* Clocks until modification */
uint8_t modmask; /* Modifications masked */
uint8_t reload; /* Automatic reload value */
} env;
@ -360,6 +361,7 @@ struct VB {
/* Other state */
uint32_t clocks; /* Clocks until modification */
uint8_t modmask; /* Modifications masked */
uint16_t next; /* Next frequency value */
int sample; /* Current sample index */
} freqmod;

View File

@ -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,18 +70,34 @@ 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)
/* Last modulation sample processed */
else {
sim->vsu.freqmod.modmask = 1;
if (sim->vsu.freqmod.rep)
sim->vsu.freqmod.sample = 0;
}
}
/* Configure state */
sim->vsu.freqmod.next = next;
}
@ -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,6 +270,7 @@ 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.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;