From 975ae1f0057e2e133ef632ac584715c8f3ecf47b Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 18 Aug 2023 16:39:26 +0200 Subject: [PATCH] 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. --- src/sound/snd_mpu401.c | 66 ++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index f4c12f2f6..0f693115e 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -18,6 +18,7 @@ * Copyright 2016-2020 Miran Grca. * Copyright 2016-2020 TheCollector1995. */ +#include #include #include #include @@ -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 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) 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; mpu->clock.active = 1; @@ -119,7 +131,7 @@ MPU401_StartClock(mpu_t *mpu) static void 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; mpu->clock.active = 0; timer_disable(&mpu->mpu401_event_callback); @@ -132,8 +144,8 @@ MPU401_RunClock(mpu_t *mpu) timer_disable(&mpu->mpu401_event_callback); return; } - timer_set_delay_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); + timer_advance_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + // 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 @@ -411,15 +423,16 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) } switch (val & 0xc) { /* Playing */ case 0x4: /* Stop */ - mpu->state.playing = 0; MPU401_StopClock(mpu); + mpu->state.playing = 0; for (i = 0; i < 16; i++) MPU401_NotesOff(mpu, i); mpu->filter.prchg_mask = 0; break; case 0x8: /* Start */ - mpu->state.playing = 1; MPU401_StartClock(mpu); + mpu->state.playing = 1; + MPU401_ClrQueue(mpu); break; default: @@ -429,14 +442,14 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) case 0: /* check if it waited for MIDI RT command */ if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB)) break; - mpu->state.rec = M_RECON; MPU401_StartClock(mpu); + mpu->state.rec = M_RECON; if (mpu->filter.prchg_mask) send_prchg = 1; break; case 0x10: /* Stop */ - mpu->state.rec = M_RECOFF; MPU401_StopClock(mpu); + mpu->state.rec = M_RECOFF; MPU401_QueueByte(mpu, MSG_MPU_ACK); MPU401_QueueByte(mpu, mpu->clock.rec_counter); MPU401_QueueByte(mpu, MSG_MPU_END); @@ -579,12 +592,12 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->filter.rt_affection = !!(val & 1); break; case 0x94: /* Clock to host */ - mpu->state.clock_to_host = 0; MPU401_StopClock(mpu); + mpu->state.clock_to_host = 0; break; case 0x95: - mpu->state.clock_to_host = 1; MPU401_StartClock(mpu); + mpu->state.clock_to_host = 1; break; case 0x96: case 0x97: /* Sysex input allow */ @@ -659,6 +672,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) case 0xc8: mpu->clock.timebase = MPUClockBase[val - 0xc2]; MPU401_ReCalcClock(mpu); + MPU401_ReStartClock(mpu); break; case 0xdf: /* Send system message */ mpu->state.wsd = 0; @@ -733,16 +747,19 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) else mpu->clock.tempo = val; MPU401_ReCalcClock(mpu); + MPU401_ReStartClock(mpu); return; case 0xe1: /* Set relative tempo */ mpu->state.command_byte = 0; mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; mpu->clock.tempo_rel = val; MPU401_ReCalcClock(mpu); + MPU401_ReStartClock(mpu); return; case 0xe2: /* Set gradation for relative tempo */ mpu->clock.tempo_grad = val; MPU401_ReCalcClock(mpu); + MPU401_ReStartClock(mpu); return; case 0xe4: /* Set MIDI clocks for metronome ticks */ 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" */ static void MPU401_EOIHandler(void *priv) @@ -1121,16 +1119,15 @@ MPU401_EOIHandler(void *priv) if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) return; + if (!mpu->state.req_mask || !mpu->clock.active) + return; + if (mpu->ext_irq_update) mpu->ext_irq_update(mpu->priv, 0); else { mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); } - if (!(mpu->state.req_mask && mpu->clock.active)) - return; - i = 0; do { 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); 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); } MPU401_ReCalcClock(mpu); + MPU401_ReStartClock(mpu); } mpu->clock.ticks_in = 0; }