Fixed some MPU-401 bugs, including the IRQ being cleared where it should not have been, fixes the music on Princess Maker 2, fixes #3233.

This commit is contained in:
OBattler
2023-08-18 16:39:26 +02:00
parent 565421a252
commit 975ae1f005

View File

@@ -18,6 +18,7 @@
* Copyright 2016-2020 Miran Grca. * Copyright 2016-2020 Miran Grca.
* Copyright 2016-2020 TheCollector1995. * Copyright 2016-2020 TheCollector1995.
*/ */
#include <inttypes.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
@@ -104,12 +105,23 @@ MPU401_ReCalcClock(mpu_t *mpu)
} }
} }
static void
MPU401_ReStartClock(mpu_t *mpu)
{
if (mpu->clock.active) {
timer_disable(&mpu->mpu401_event_callback);
timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC);
}
}
static void static void
MPU401_StartClock(mpu_t *mpu) MPU401_StartClock(mpu_t *mpu)
{ {
mpu401_log("MPU401_StartClock(): %i, %i, %i, %i\n", mpu->clock.active, mpu->state.clock_to_host,
mpu->state.playing, (mpu->state.rec == M_RECON));
if (mpu->clock.active) if (mpu->clock.active)
return; return;
if (!(mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON))) if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON))
return; return;
mpu->clock.active = 1; mpu->clock.active = 1;
@@ -119,7 +131,7 @@ MPU401_StartClock(mpu_t *mpu)
static void static void
MPU401_StopClock(mpu_t *mpu) MPU401_StopClock(mpu_t *mpu)
{ {
if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON)) if (!mpu->state.clock_to_host && !mpu->state.playing && (mpu->state.rec == M_RECOFF))
return; return;
mpu->clock.active = 0; mpu->clock.active = 0;
timer_disable(&mpu->mpu401_event_callback); timer_disable(&mpu->mpu401_event_callback);
@@ -132,8 +144,8 @@ MPU401_RunClock(mpu_t *mpu)
timer_disable(&mpu->mpu401_event_callback); timer_disable(&mpu->mpu401_event_callback);
return; return;
} }
timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); timer_advance_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC);
mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); // mpu401_log("Next event after %" PRIu64 " us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT);
} }
static void static void
@@ -411,15 +423,16 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val)
} }
switch (val & 0xc) { /* Playing */ switch (val & 0xc) { /* Playing */
case 0x4: /* Stop */ case 0x4: /* Stop */
mpu->state.playing = 0;
MPU401_StopClock(mpu); MPU401_StopClock(mpu);
mpu->state.playing = 0;
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
MPU401_NotesOff(mpu, i); MPU401_NotesOff(mpu, i);
mpu->filter.prchg_mask = 0; mpu->filter.prchg_mask = 0;
break; break;
case 0x8: /* Start */ case 0x8: /* Start */
mpu->state.playing = 1;
MPU401_StartClock(mpu); MPU401_StartClock(mpu);
mpu->state.playing = 1;
MPU401_ClrQueue(mpu);
break; break;
default: default:
@@ -429,14 +442,14 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val)
case 0: /* check if it waited for MIDI RT command */ case 0: /* check if it waited for MIDI RT command */
if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB)) if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB))
break; break;
mpu->state.rec = M_RECON;
MPU401_StartClock(mpu); MPU401_StartClock(mpu);
mpu->state.rec = M_RECON;
if (mpu->filter.prchg_mask) if (mpu->filter.prchg_mask)
send_prchg = 1; send_prchg = 1;
break; break;
case 0x10: /* Stop */ case 0x10: /* Stop */
mpu->state.rec = M_RECOFF;
MPU401_StopClock(mpu); MPU401_StopClock(mpu);
mpu->state.rec = M_RECOFF;
MPU401_QueueByte(mpu, MSG_MPU_ACK); MPU401_QueueByte(mpu, MSG_MPU_ACK);
MPU401_QueueByte(mpu, mpu->clock.rec_counter); MPU401_QueueByte(mpu, mpu->clock.rec_counter);
MPU401_QueueByte(mpu, MSG_MPU_END); MPU401_QueueByte(mpu, MSG_MPU_END);
@@ -579,12 +592,12 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val)
mpu->filter.rt_affection = !!(val & 1); mpu->filter.rt_affection = !!(val & 1);
break; break;
case 0x94: /* Clock to host */ case 0x94: /* Clock to host */
mpu->state.clock_to_host = 0;
MPU401_StopClock(mpu); MPU401_StopClock(mpu);
mpu->state.clock_to_host = 0;
break; break;
case 0x95: case 0x95:
mpu->state.clock_to_host = 1;
MPU401_StartClock(mpu); MPU401_StartClock(mpu);
mpu->state.clock_to_host = 1;
break; break;
case 0x96: case 0x96:
case 0x97: /* Sysex input allow */ case 0x97: /* Sysex input allow */
@@ -659,6 +672,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val)
case 0xc8: case 0xc8:
mpu->clock.timebase = MPUClockBase[val - 0xc2]; mpu->clock.timebase = MPUClockBase[val - 0xc2];
MPU401_ReCalcClock(mpu); MPU401_ReCalcClock(mpu);
MPU401_ReStartClock(mpu);
break; break;
case 0xdf: /* Send system message */ case 0xdf: /* Send system message */
mpu->state.wsd = 0; mpu->state.wsd = 0;
@@ -733,16 +747,19 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val)
else else
mpu->clock.tempo = val; mpu->clock.tempo = val;
MPU401_ReCalcClock(mpu); MPU401_ReCalcClock(mpu);
MPU401_ReStartClock(mpu);
return; return;
case 0xe1: /* Set relative tempo */ case 0xe1: /* Set relative tempo */
mpu->state.command_byte = 0; mpu->state.command_byte = 0;
mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; mpu->clock.old_tempo_rel = mpu->clock.tempo_rel;
mpu->clock.tempo_rel = val; mpu->clock.tempo_rel = val;
MPU401_ReCalcClock(mpu); MPU401_ReCalcClock(mpu);
MPU401_ReStartClock(mpu);
return; return;
case 0xe2: /* Set gradation for relative tempo */ case 0xe2: /* Set gradation for relative tempo */
mpu->clock.tempo_grad = val; mpu->clock.tempo_grad = val;
MPU401_ReCalcClock(mpu); MPU401_ReCalcClock(mpu);
MPU401_ReStartClock(mpu);
return; return;
case 0xe4: /* Set MIDI clocks for metronome ticks */ case 0xe4: /* Set MIDI clocks for metronome ticks */
mpu->state.command_byte = 0; mpu->state.command_byte = 0;
@@ -1079,25 +1096,6 @@ UpdateTrack(mpu_t *mpu, uint8_t track)
} }
} }
#if 0
static void
UpdateConductor(mpu_t *mpu)
{
if (mpu->condbuf.value[0] == 0xfc) {
mpu->condbuf.value[0] = 0;
mpu->state.conductor = 0;
mpu->state.req_mask &= ~(1 << 9);
if (mpu->state.amask == 0)
mpu->state.req_mask |= (1 << 12);
return;
}
mpu->condbuf.vlength = 0;
mpu->condbuf.counter = 0xf0;
mpu->state.req_mask |= (1 << 9);
}
#endif
/* Updates counters and requests new data on "End of Input" */ /* Updates counters and requests new data on "End of Input" */
static void static void
MPU401_EOIHandler(void *priv) MPU401_EOIHandler(void *priv)
@@ -1121,16 +1119,15 @@ MPU401_EOIHandler(void *priv)
if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) if (mpu->state.rec_copy || !mpu->state.sysex_in_finished)
return; return;
if (!mpu->state.req_mask || !mpu->clock.active)
return;
if (mpu->ext_irq_update) if (mpu->ext_irq_update)
mpu->ext_irq_update(mpu->priv, 0); mpu->ext_irq_update(mpu->priv, 0);
else { else {
mpu->state.irq_pending = 0; mpu->state.irq_pending = 0;
picintc(1 << mpu->irq);
} }
if (!(mpu->state.req_mask && mpu->clock.active))
return;
i = 0; i = 0;
do { do {
if (mpu->state.req_mask & (1 << i)) { if (mpu->state.req_mask & (1 << i)) {
@@ -1381,7 +1378,7 @@ MPU401_Event(void *priv)
} }
} }
if (MPU401_IRQPending(mpu) && mpu->state.req_mask) if (!MPU401_IRQPending(mpu) && mpu->state.req_mask)
MPU401_EOIHandler(mpu); MPU401_EOIHandler(mpu);
next_event: next_event:
@@ -1599,6 +1596,7 @@ MPU401_InputMsg(void *p, uint8_t *msg, uint32_t len)
mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick); mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick);
} }
MPU401_ReCalcClock(mpu); MPU401_ReCalcClock(mpu);
MPU401_ReStartClock(mpu);
} }
mpu->clock.ticks_in = 0; mpu->clock.ticks_in = 0;
} }