From 6979b6a6c09add333ed1f0550eb56446103c88c8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 4 Aug 2024 05:13:24 +0200 Subject: [PATCH] Assorted MIDI and MPU-401 intelligent mode fixes, fixes #4419. --- src/include/86box/midi.h | 2 + src/include/86box/snd_mpu401.h | 9 +- src/sound/midi.c | 9 +- src/sound/snd_mpu401.c | 988 ++++++++++++++++----------------- src/sound/snd_sb_dsp.c | 2 +- 5 files changed, 486 insertions(+), 524 deletions(-) diff --git a/src/include/86box/midi.h b/src/include/86box/midi.h index 7f7ad89ae..57a20ae5c 100644 --- a/src/include/86box/midi.h +++ b/src/include/86box/midi.h @@ -32,6 +32,7 @@ typedef struct midi_device_t { void (*play_sysex)(uint8_t *sysex, unsigned int len); void (*play_msg)(uint8_t *msg); void (*poll)(void); + void (*reset)(void); int (*write)(uint8_t val); } midi_device_t; @@ -77,6 +78,7 @@ extern void midi_raw_out_thru_rt_byte(uint8_t val); extern void midi_raw_out_byte(uint8_t val); extern void midi_clear_buffer(void); extern void midi_poll(void); +extern void midi_reset(void); extern void midi_in_handler(int set, void (*msg)(void *priv, uint8_t *msg, uint32_t len), int (*sysex)(void *priv, uint8_t *buffer, uint32_t len, int abort), void *priv); extern void midi_in_handlers_clear(void); diff --git a/src/include/86box/snd_mpu401.h b/src/include/86box/snd_mpu401.h index 8cd275af8..6dd99379e 100644 --- a/src/include/86box/snd_mpu401.h +++ b/src/include/86box/snd_mpu401.h @@ -26,9 +26,9 @@ #define MPU401_VERSION 0x15 #define MPU401_REVISION 0x01 -#define MPU401_QUEUE 1024 +#define MPU401_QUEUE 32 #define MPU401_INPUT_QUEUE 1024 -#define MPU401_TIMECONSTANT (60000000 / 1000.0f) +#define MPU401_TIMECONSTANT (60000000.0 / 1000.0) #define MPU401_RESETBUSY 27.0f /*helpers*/ @@ -89,7 +89,7 @@ typedef struct mpu_t { uint32_t ch_toref[16]; struct track { int counter; - uint8_t value[3]; + uint8_t value[8]; uint8_t sys_val; uint8_t vlength; uint8_t length; @@ -106,7 +106,6 @@ typedef struct mpu_t { int wsm; int wsd_start; int run_irq; - int irq_pending; int track_req; int send_now; int eoi_scheduled; @@ -116,9 +115,11 @@ typedef struct mpu_t { int sysex_in_finished; int rec_copy; RecState rec; + uint8_t irq_pending; uint8_t tmask; uint8_t cmask; uint8_t amask; + uint8_t queued_eois; uint8_t last_rtcmd; uint16_t midi_mask; uint16_t req_mask; diff --git a/src/sound/midi.c b/src/sound/midi.c index 18fad1886..bf92249c4 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -341,7 +341,7 @@ midi_raw_out_byte(uint8_t val) else if ((midi_out->midi_sysex_data[5] == 0x10) && (midi_out->midi_sysex_data[6] == 0x00) && (midi_out->midi_sysex_data[7] == 0x01)) midi_out->midi_sysex_delay = 30; /* Dark Sun 1 */ else - midi_out->midi_sysex_delay = (unsigned int) (((float) (midi_out->midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; + midi_out->midi_sysex_delay = (unsigned int) (((double) (midi_out->midi_pos) * 1.25) / 3.125) + 2; midi_out->midi_sysex_start = plat_get_ticks(); } @@ -584,3 +584,10 @@ midi_in_sysex(uint8_t *buffer, uint32_t len) break; } } + +void +midi_reset(void) +{ + if (midi_out && midi_out->m_out_device && midi_out->m_out_device->reset) + midi_out->m_out_device->reset(); +} diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index a8c9d3e3c..40853d98b 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -8,15 +8,13 @@ * * Roland MPU-401 emulation. * - * - * * Authors: DOSBox Team, * Miran Grca, * TheCollector1995, * - * Copyright 2008-2020 DOSBox Team. - * Copyright 2016-2020 Miran Grca. - * Copyright 2016-2020 TheCollector1995. + * Copyright 2008-2024 DOSBox Team. + * Copyright 2016-2024 Miran Grca. + * Copyright 2016-2024 TheCollector1995. */ #include #include @@ -51,10 +49,11 @@ enum { int mpu401_standalone_enable = 0; static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val); +static void MPU401_WriteData(mpu_t *mpu, uint8_t val); static void MPU401_IntelligentOut(mpu_t *mpu, uint8_t track); static void MPU401_EOIHandler(void *priv); static void MPU401_EOIHandlerDispatch(void *priv); -static void MPU401_NotesOff(mpu_t *mpu, int i); +static __inline void MPU401_NotesOff(mpu_t *mpu, unsigned int i); #ifdef ENABLE_MPU401_LOG int mpu401_do_log = ENABLE_MPU401_LOG; @@ -74,11 +73,26 @@ mpu401_log(const char *fmt, ...) # define mpu401_log(fmt, ...) #endif +static void +MPU401_UpdateIRQ(mpu_t *mpu, int set) +{ + /* Clear IRQ. */ + if ((mpu->irq > 0) && (mpu->irq <= 15)) { + mpu401_log("MPU401_UpdateIRQ(): Int IRQ %i %s.\n", mpu->irq, set ? "set" : "cleared"); + picint_common(1 << mpu->irq, PIC_IRQ_EDGE, set, NULL); + } + + if (mpu->ext_irq_update) { + mpu401_log("MPU401_UpdateIRQ(): Ext IRQ %s.\n", set ? "set" : "cleared"); + mpu->ext_irq_update(mpu->priv, set); + } +} + static void MPU401_ReCalcClock(mpu_t *mpu) { int32_t mintempo = 16; - int32_t maxtempo = 240; + int32_t maxtempo = 240; int32_t freq; if (mpu->clock.timebase < 72) { @@ -96,10 +110,11 @@ MPU401_ReCalcClock(mpu_t *mpu) } mpu->clock.freq = ((uint32_t) (mpu->clock.tempo * 2 * mpu->clock.tempo_rel)) >> 6; - mpu->clock.freq = mpu->clock.timebase * (mpu->clock.freq < (mintempo * 2) ? mintempo : ((mpu->clock.freq / 2) < maxtempo ? (mpu->clock.freq / 2) : maxtempo)); + mpu->clock.freq = mpu->clock.timebase * (mpu->clock.freq < (mintempo * 2) ? + mintempo : ((mpu->clock.freq / 2) < maxtempo ? (mpu->clock.freq / 2) : maxtempo)); if (mpu->state.sync_in) { - freq = (int32_t) ((float) (mpu->clock.freq) * mpu->clock.freq_mod); + freq = (int32_t) ((double) (mpu->clock.freq) * mpu->clock.freq_mod); if ((freq > (mpu->clock.timebase * mintempo)) && (freq < (mpu->clock.timebase * maxtempo))) mpu->clock.freq = freq; } @@ -110,135 +125,109 @@ 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); + timer_set_delay_u64(&mpu->mpu401_event_callback, + (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + mpu401_log("MPU-401: Clock restarted\n"); } } -static void +static __inline 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)) - return; - - mpu->clock.active = 1; - timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + if (!mpu->clock.active && (mpu->state.playing || + mpu->state.clock_to_host || (mpu->state.rec == M_RECON))) { + mpu->clock.active = 1; + timer_set_delay_u64(&mpu->mpu401_event_callback, + (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + mpu401_log("MPU-401: Clock started\n"); + } } -static void +static __inline void MPU401_StopClock(mpu_t *mpu) { - 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); + if (mpu->clock.active && !mpu->state.playing && + !mpu->state.clock_to_host && (mpu->state.rec != M_RECON)) { + mpu->clock.active = 0; + timer_disable(&mpu->mpu401_event_callback); + mpu401_log("MPU-401: Clock stopped\n"); + } } -static void +static __inline void MPU401_RunClock(mpu_t *mpu) { - if (!mpu->clock.active) { + if (mpu->clock.active) + timer_advance_u64(&mpu->mpu401_event_callback, + (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + else timer_disable(&mpu->mpu401_event_callback); - return; - } - timer_advance_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); -#if 0 - mpu401_log("Next event after %" PRIu64 " us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); -#endif } static void -MPU401_QueueByteEx(mpu_t *mpu, uint8_t data, UNUSED(int irq)) +MPU401_QueueByte(mpu_t *mpu, uint8_t data) { if (mpu->state.block_ack) { mpu->state.block_ack = 0; return; } - if (mpu->queue_used == 0) { - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 1); - else { - mpu->state.irq_pending = 1; - picint(1 << mpu->irq); - } + mpu401_log("QueueByte Used=%d.\n", mpu->queue_used); + if (!mpu->queue_used) { + mpu->state.irq_pending = 1; + MPU401_UpdateIRQ(mpu, 1); } if (mpu->queue_used < MPU401_QUEUE) { - int pos = mpu->queue_used + mpu->queue_pos; - + if (mpu->queue_pos > MPU401_QUEUE) fatal("MPU queue overflow\n"); + uint8_t pos = mpu->queue_used + mpu->queue_pos; if (mpu->queue_pos >= MPU401_QUEUE) mpu->queue_pos -= MPU401_QUEUE; if (pos >= MPU401_QUEUE) pos -= MPU401_QUEUE; mpu->queue_used++; + if (pos >= MPU401_QUEUE) fatal("MPU position overflow\n"); mpu->queue[pos] = data; } } static void -MPU401_QueueByte(mpu_t *mpu, uint8_t data) +MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, unsigned int len) { - MPU401_QueueByteEx(mpu, data, 1); -} - -static int -MPU401_IRQPending(mpu_t *mpu) -{ - int irq_pending; - - if (mpu->ext_irq_pending) - irq_pending = mpu->ext_irq_pending(mpu->priv); - else - irq_pending = mpu->state.irq_pending; - - return irq_pending; -} - -static void -MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, UNUSED(int block)) -{ - uint32_t cnt = 0; - int pos; + unsigned int cnt = 0; while (cnt < len) { if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) { - pos = mpu->rec_queue_used + mpu->rec_queue_pos; + unsigned int pos = mpu->rec_queue_used + mpu->rec_queue_pos; if (pos >= MPU401_INPUT_QUEUE) pos -= MPU401_INPUT_QUEUE; mpu->rec_queue[pos] = buf[cnt]; mpu->rec_queue_used++; - if ((!mpu->state.sysex_in_finished) && (buf[cnt] == MSG_EOX)) { - /* finish sysex */ + if (!mpu->state.sysex_in_finished && (buf[cnt] == MSG_EOX)) { + /* Finish SysEx */ mpu->state.sysex_in_finished = 1; break; } cnt++; } } - - if (mpu->queue_used == 0) { - if (mpu->state.rec_copy || MPU401_IRQPending(mpu)) { - if (MPU401_IRQPending(mpu)) { - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); - } + if (!mpu->queue_used) { + if (mpu->state.rec_copy || mpu->state.irq_pending) { + if (mpu->state.irq_pending) { + mpu->state.irq_pending = 0; + MPU401_UpdateIRQ(mpu, 0); } return; } + mpu->state.rec_copy = 1; if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; + MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); - mpu->rec_queue_used--; - mpu->rec_queue_pos++; + mpu->rec_queue_used--; + mpu->rec_queue_pos++; } } @@ -250,12 +239,8 @@ MPU401_ClrQueue(mpu_t *mpu) mpu->rec_queue_used = 0; mpu->rec_queue_pos = 0; mpu->state.sysex_in_finished = 1; - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); - } + mpu->state.irq_pending = 0; + MPU401_UpdateIRQ(mpu, 0); } static void @@ -263,86 +248,85 @@ MPU401_Reset(mpu_t *mpu) { uint8_t i; -#ifdef DOSBOX_CODE - if (mpu->mode == M_INTELLIGENT) { - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); - } + midi_reset(); + /* Clear MIDI buffers, terminate notes. */ + midi_clear_buffer(); + for (i = 0xb0; i <= 0xbf; i++) { + midi_raw_out_byte(i); + midi_raw_out_byte(0x7b); + midi_raw_out_byte(0); } -#else - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); - } -#endif - mpu->mode = M_INTELLIGENT; - mpu->midi_thru = 0; - mpu->state.rec = M_RECOFF; - mpu->state.eoi_scheduled = 0; - mpu->state.wsd = 0; - mpu->state.wsm = 0; - mpu->state.conductor = 0; - mpu->state.cond_req = 0; - mpu->state.cond_set = 0; - mpu->state.playing = 0; - mpu->state.run_irq = 0; - mpu->state.cmask = 0xff; - mpu->state.amask = mpu->state.tmask = 0; - mpu->state.midi_mask = 0xffff; - mpu->state.command_byte = 0; - mpu->state.block_ack = 0; - mpu->clock.tempo = mpu->clock.old_tempo = 100; - mpu->clock.timebase = mpu->clock.old_timebase = 120; + mpu->state.irq_pending = 0; + MPU401_UpdateIRQ(mpu, 0); + + timer_disable(&mpu->mpu401_event_callback); + + mpu->mode = M_INTELLIGENT; + mpu->midi_thru = 0; + mpu->state.rec = M_RECOFF; + mpu->state.eoi_scheduled = 0; + mpu->state.wsd = 0; + mpu->state.wsm = 0; + mpu->state.conductor = 0; + mpu->state.cond_req = 0; + mpu->state.cond_set = 0; + mpu->state.playing = 0; + mpu->state.run_irq = 0; + mpu->state.cmask = 0xff; + mpu->state.amask = mpu->state.tmask = 0; + mpu->state.midi_mask = 0xffff; + mpu->state.command_byte = 0; + mpu->state.block_ack = 0; + mpu->clock.tempo = mpu->clock.old_tempo = 100; + mpu->clock.timebase = mpu->clock.old_timebase = 120; mpu->clock.tempo_rel = mpu->clock.old_tempo_rel = 0x40; mpu->clock.freq_mod = 1.0; mpu->clock.tempo_grad = 0; + mpu->state.clock_to_host = 0; MPU401_StopClock(mpu); MPU401_ReCalcClock(mpu); for (i = 0; i < 4; i++) - mpu->clock.cth_rate[i] = 60; + mpu->clock.cth_rate[i] = 60; - mpu->clock.cth_counter = 0; - mpu->clock.midimetro = 12; - mpu->clock.metromeas = 8; - mpu->filter.rec_measure_end = 1; - mpu->filter.rt_out = 1; - mpu->filter.rt_affection = 1; - mpu->filter.allnotesoff_out = 1; - mpu->filter.all_thru = 1; - mpu->filter.midi_thru = 1; - mpu->filter.commonmsgs_thru = 1; + mpu->clock.cth_counter = 0; + mpu->clock.midimetro = 12; + mpu->clock.metromeas = 8; + mpu->filter.rec_measure_end = 1; + mpu->filter.rt_out = 1; + mpu->filter.rt_affection = 1; + mpu->filter.allnotesoff_out = 1; + mpu->filter.all_thru = 1; + mpu->filter.midi_thru = 1; + mpu->filter.commonmsgs_thru = 1; /* Reset channel reference and input tables. */ for (i = 0; i < 4; i++) { - mpu->chanref[i].on = 1; - mpu->chanref[i].chan = i; - mpu->ch_toref[i] = i; + mpu->chanref[i].on = 1; + mpu->chanref[i].chan = i; + + mpu->ch_toref[i] = i; } for (i = 0; i < 16; i++) { - mpu->inputref[i].on = 1; - mpu->inputref[i].chan = i; + mpu->inputref[i].on = 1; + mpu->inputref[i].chan = i; if (i > 3) - mpu->ch_toref[i] = 4; /* Dummy reftable. */ + mpu->ch_toref[i] = 4; /* Dummy reftable. */ } MPU401_ClrQueue(mpu); - mpu->state.data_onoff = -1; + mpu->state.data_onoff = -1; - mpu->state.req_mask = 0; - mpu->condbuf.counter = 0; - mpu->condbuf.type = T_OVERFLOW; + mpu->state.req_mask = 0; + mpu->condbuf.counter = 0; + + mpu->condbuf.type = T_OVERFLOW; for (i = 0; i < 8; i++) { - mpu->playbuf[i].type = T_OVERFLOW; - mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; + mpu->playbuf[i].counter = 0; } /* Clear MIDI buffers, terminate notes. */ @@ -355,15 +339,22 @@ MPU401_Reset(mpu_t *mpu) } } +static uint8_t +MPU401_ReadStatus(mpu_t *mpu) +{ + uint8_t ret = 0x3f; + if (mpu->state.cmd_pending) + ret |= STATUS_OUTPUT_NOT_READY; + if (!mpu->queue_used) + ret |= STATUS_INPUT_NOT_READY; + return ret; +} + static void MPU401_ResetDone(void *priv) { mpu_t *mpu = (mpu_t *) priv; - mpu401_log("MPU-401 reset callback\n"); - - timer_disable(&mpu->mpu401_reset_callback); - mpu->state.reset = 0; if (mpu->state.cmd_pending) { @@ -387,6 +378,15 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) if ((val != 0xff) && (mpu->mode == M_UART)) return; + if (mpu->state.reset) { + if (mpu->state.cmd_pending || (val != 0xff)) { + mpu->state.cmd_pending = val + 1; + return; + } + timer_disable(&mpu->mpu401_reset_callback); + mpu->state.reset = 0; + } + /* In Intelligent mode, UART-only variants of the MPU-401 only support commands 0x3F and 0xFF. */ if (!mpu->intelligent && (val != 0x3f) && (val != 0xff)) return; @@ -425,15 +425,15 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) } switch (val & 0xc) { /* Playing */ case 0x4: /* Stop */ - MPU401_StopClock(mpu); mpu->state.playing = 0; + MPU401_StopClock(mpu); for (i = 0; i < 16; i++) MPU401_NotesOff(mpu, i); mpu->filter.prchg_mask = 0; break; case 0x8: /* Start */ - MPU401_StartClock(mpu); mpu->state.playing = 1; + MPU401_StartClock(mpu); MPU401_ClrQueue(mpu); break; @@ -444,14 +444,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; - MPU401_StartClock(mpu); mpu->state.rec = M_RECON; + MPU401_StartClock(mpu); if (mpu->filter.prchg_mask) send_prchg = 1; break; case 0x10: /* Stop */ - MPU401_StopClock(mpu); mpu->state.rec = M_RECOFF; + MPU401_StopClock(mpu); MPU401_QueueByte(mpu, MSG_MPU_ACK); MPU401_QueueByte(mpu, mpu->clock.rec_counter); MPU401_QueueByte(mpu, MSG_MPU_END); @@ -480,7 +480,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) /* record counter hack: needed by Prism, but sent only on cmd 0x20/0x26 (or breaks Ballade) */ uint8_t rec_cnt = mpu->clock.rec_counter; if (((val == 0x20) || (val == 0x26)) && (mpu->state.rec == M_RECON)) - MPU401_RecQueueBuffer(mpu, &rec_cnt, 1, 0); + MPU401_RecQueueBuffer(mpu, &rec_cnt, 1); if (send_prchg) { for (i = 0; i < 16; i++) { @@ -488,11 +488,12 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) recmsg[0] = mpu->clock.rec_counter; recmsg[1] = 0xc0 | i; recmsg[2] = mpu->filter.prchg_buf[i]; - MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); + MPU401_RecQueueBuffer(mpu, recmsg, 3); mpu->filter.prchg_mask &= ~(1 << i); } } } + return; } else if ((val >= 0xa0) && (val <= 0xa7)) /* Request play counter */ MPU401_QueueByte(mpu, mpu->playbuf[val & 7].counter); else if ((val >= 0xd0) && (val <= 0xd7)) { /* Send data */ @@ -552,7 +553,8 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) return; case 0x80: /* Internal clock */ if (mpu->clock.active && mpu->state.sync_in) { - timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + timer_set_delay_u64(&mpu->mpu401_event_callback, + (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); mpu->clock.freq_mod = 1.0; } mpu->state.sync_in = 0; @@ -594,12 +596,12 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->filter.rt_affection = !!(val & 1); break; case 0x94: /* Clock to host */ - MPU401_StopClock(mpu); mpu->state.clock_to_host = 0; + MPU401_StopClock(mpu); break; case 0x95: - MPU401_StartClock(mpu); mpu->state.clock_to_host = 1; + MPU401_StartClock(mpu); break; case 0x96: case 0x97: /* Sysex input allow */ @@ -650,6 +652,8 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->state.conductor = mpu->state.cond_set; mpu->clock.cth_counter = mpu->clock.cth_old = 0; mpu->clock.measure_counter = mpu->clock.meas_old = 0; + mpu->state.req_mask = 0; + mpu->state.irq_pending = 1; break; case 0xb9: /* Clear play map */ for (i = 0; i < 16; i++) @@ -661,6 +665,8 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->state.last_rtcmd = 0; mpu->clock.cth_counter = mpu->clock.cth_old = 0; mpu->clock.measure_counter = mpu->clock.meas_old = 0; + mpu->state.req_mask = 0; + mpu->state.irq_pending = 1; break; case 0xba: /* Clear record counter */ mpu->clock.rec_counter = 0; @@ -704,38 +710,106 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) return; break; - default: + default: #if 0 - mpu401_log("MPU-401:Unhandled command %X",val); + mpu401_log("MPU-401:Unhandled command %X",val); #endif - break; + break; } MPU401_QueueByte(mpu, MSG_MPU_ACK); } +void +MPU401_ReadRaiseIRQ(mpu_t *mpu) +{ + /* Clear IRQ. */ + MPU401_UpdateIRQ(mpu, 0); + + if (mpu->queue_used) + MPU401_UpdateIRQ(mpu, 1); +} + +uint8_t +MPU401_ReadData(mpu_t *mpu) +{ + uint8_t ret = MSG_MPU_ACK; + + if (mpu->queue_used) { + mpu->queue_pos -= (mpu->queue_pos >= MPU401_QUEUE) ? MPU401_QUEUE : 0; + ret = mpu->queue[mpu->queue_pos]; + mpu->queue_pos++; + mpu->queue_used--; + } + + /* Shouldn't this check mpu->mode? */ + if (!mpu->intelligent || (mpu->mode == M_UART)) { + MPU401_ReadRaiseIRQ(mpu); + return ret; + } + + mpu401_log("QueueUsed=%d.\n", mpu->queue_used); + if (!mpu->queue_used) + MPU401_UpdateIRQ(mpu, 0); + + if (mpu->state.rec_copy && !mpu->rec_queue_used) { + MPU401_ReadRaiseIRQ(mpu); + mpu->state.rec_copy = 0; + MPU401_EOIHandler(mpu); + return ret; + } + + /* Copy from recording buffer. */ + if (!mpu->queue_used && mpu->rec_queue_used) { + mpu->state.rec_copy = 1; + if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) + mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; + + MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); + mpu->rec_queue_pos++; + mpu->rec_queue_used--; + } + + MPU401_ReadRaiseIRQ(mpu); + + if ((ret >= 0xf0) && (ret <= 0xf7)) { /* MIDI data request */ + mpu->state.track = ret & 7; + mpu->state.data_onoff = 0; + mpu->state.cond_req = 0; + mpu->state.track_req = 1; + } + + if (ret == MSG_MPU_COMMAND_REQ) { + mpu->state.data_onoff = 0; + mpu->state.cond_req = 1; + if (mpu->condbuf.type != T_OVERFLOW) { + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, mpu->condbuf.value[0]); + if (mpu->state.command_byte) + MPU401_WriteData(mpu, mpu->condbuf.value[1]); + mpu->condbuf.type = T_OVERFLOW; + } + } + + if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK) || (ret == MSG_MPU_OVERFLOW)) + MPU401_EOIHandlerDispatch(mpu); + + return ret; +} + static void MPU401_WriteData(mpu_t *mpu, uint8_t val) { - static int length; - static int cnt; + static unsigned int length; + static unsigned int cnt; + static unsigned int posd; -#ifdef DOSBOX_CODE - if (mpu->mode == M_UART) { - midi_raw_out_byte(val); - return; - } - - if (!mpu->intelligent) { - mpu->state.command_byte = 0; - return; - } -#else if (!mpu->intelligent || (mpu->mode == M_UART)) { midi_raw_out_byte(val); + if (val == 0xff) + midi_reset(); return; } -#endif switch (mpu->state.command_byte) { /* 0xe# command data */ case 0x00: @@ -759,6 +833,7 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) MPU401_ReStartClock(mpu); return; case 0xe2: /* Set gradation for relative tempo */ + mpu->state.command_byte = 0; mpu->clock.tempo_grad = val; MPU401_ReCalcClock(mpu); MPU401_ReStartClock(mpu); @@ -844,6 +919,7 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) } if (cnt == length) { + mpu->playbuf[mpu->state.track].vlength = cnt; MPU401_IntelligentOut(mpu, mpu->state.track); mpu->state.wsd = 0; mpu->state.track = mpu->state.old_track; @@ -874,8 +950,9 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) break; default: + length = 0; mpu->state.wsm = 0; - return; + break; } } else if (val & 0x80) { midi_raw_out_byte(MSG_EOX); @@ -900,38 +977,36 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) case -1: return; case 0: /* Timing byte */ - mpu->condbuf.length = 0; + mpu->condbuf.vlength = 0; if (val < 0xf0) mpu->state.data_onoff++; else { - mpu->state.cond_req = 0; mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); - break; + return; } - mpu->state.send_now = !val ? 1 : 0; + /* A timing value of 0 means send it now! */ + mpu->state.send_now = (val == 0); mpu->condbuf.counter = val; break; case 1: /* Command byte #1 */ mpu->condbuf.type = T_COMMAND; if ((val == 0xf8) || (val == 0xf9) || (val == 0xfc)) mpu->condbuf.type = T_OVERFLOW; - mpu->condbuf.value[mpu->condbuf.length] = val; - mpu->condbuf.length++; - if ((val & 0xf0) != 0xe0) { /*no cmd data byte*/ - MPU401_EOIHandler(mpu); - mpu->state.data_onoff = -1; - mpu->state.cond_req = 0; - } else + + mpu->condbuf.value[mpu->condbuf.vlength] = val; + mpu->condbuf.vlength++; + + if ((val & 0xf0) != 0xe0) + MPU401_EOIHandlerDispatch(mpu); + else mpu->state.data_onoff++; break; case 2: /* Command byte #2 */ - mpu->condbuf.value[mpu->condbuf.length] = val; - mpu->condbuf.length++; - MPU401_EOIHandler(mpu); - mpu->state.data_onoff = -1; - mpu->state.cond_req = 0; + mpu->condbuf.value[mpu->condbuf.vlength] = val; + mpu->condbuf.vlength++; + MPU401_EOIHandlerDispatch(mpu); break; default: @@ -939,103 +1014,95 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) } return; } - switch (mpu->state.data_onoff) { /* Data */ case -1: - break; + return; case 0: /* Timing byte */ if (val < 0xf0) - mpu->state.data_onoff++; + mpu->state.data_onoff = 1; else { mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); mpu->state.track_req = 0; return; } - mpu->state.send_now = !val ? 1 : 0; + mpu->state.send_now = (val == 0); mpu->playbuf[mpu->state.track].counter = val; break; case 1: /* MIDI */ - cnt = 0; - mpu->state.data_onoff++; - switch (val & 0xf0) { - case 0xc0: - case 0xd0: /* MIDI Message */ - length = mpu->playbuf[mpu->state.track].length = 2; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; - case 0x80: - case 0x90: - case 0xa0: - case 0xb0: - case 0xe0: - length = mpu->playbuf[mpu->state.track].length = 3; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; - case 0xf0: /* System message or mark */ - mpu->playbuf[mpu->state.track].sys_val = val; - if (val > 0xf7) { - mpu->playbuf[mpu->state.track].type = T_MARK; - if (val == 0xf9) - mpu->clock.measure_counter = 0; - } else { -#if 0 - mpu401_log("MPU-401:Illegal message"); -#endif - mpu->playbuf[mpu->state.track].type = T_OVERFLOW; - } - mpu->state.data_onoff = -1; - MPU401_EOIHandler(mpu); - mpu->state.track_req = 0; - return; - default: /* MIDI with running status */ - cnt++; - length = mpu->playbuf[mpu->state.track].length; - mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; - break; - } - break; - case 2: - if (cnt < length) { - mpu->playbuf[mpu->state.track].value[cnt] = val; - cnt++; - } - if (cnt == length) { - mpu->state.data_onoff = -1; - mpu->state.track_req = 0; - MPU401_EOIHandler(mpu); - } - break; + mpu->playbuf[mpu->state.track].vlength++; + posd = mpu->playbuf[mpu->state.track].vlength; + + if (posd == 1) { + switch (val & 0xf0) { + case 0xc0: + case 0xd0: /* MIDI Message */ + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + length = mpu->playbuf[mpu->state.track].length = 2; + break; + case 0x80: + case 0x90: + case 0xa0: + case 0xb0: + case 0xe0: + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + length = mpu->playbuf[mpu->state.track].length = 3; + break; + case 0xf0: /* System message or mark */ + mpu->playbuf[mpu->state.track].sys_val = val; + if (val > 0xf7) { + mpu->playbuf[mpu->state.track].type = T_MARK; + if (val == 0xf9) + mpu->clock.measure_counter = 0; + } else + mpu->playbuf[mpu->state.track].type = T_OVERFLOW; - default: + length = 1; + break; + + default: /* MIDI with running status */ + posd++; + length = mpu->playbuf[mpu->state.track].length; + mpu->playbuf[mpu->state.track].vlength++; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; + break; + } + } + + if (!((posd == 1) && (val >= 0xf0))) + mpu->playbuf[mpu->state.track].value[posd - 1] = val; + + if (posd == length) { + MPU401_EOIHandlerDispatch(mpu); + mpu->state.track_req = 0; + } break; } - - return; } static void MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) { - uint8_t chan; - uint8_t chrefnum; - uint8_t key; - uint8_t msg; - int send; - int retrigger; + unsigned int chan; + unsigned int chrefnum; + uint8_t key; + uint8_t msg; + uint8_t val; + int send; + int retrigger; switch (mpu->playbuf[track].type) { case T_OVERFLOW: break; - case T_MARK: - if (mpu->playbuf[track].sys_val == 0xfc) { - midi_raw_out_rt_byte(mpu->playbuf[track].sys_val); + val = mpu->playbuf[track].sys_val; + if (val == 0xfc) { + midi_raw_out_rt_byte(val); mpu->state.amask &= ~(1 << track); + mpu->state.req_mask &= ~(1 << track); } break; - case T_MIDI_NORM: chan = mpu->playbuf[track].value[0] & 0xf; key = mpu->playbuf[track].value[1] & 0x7f; @@ -1043,18 +1110,20 @@ MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) send = 1; retrigger = 0; switch (msg = mpu->playbuf[track].value[0] & 0xf0) { - case 0x80: /* note off */ + case 0x80: /* Note off */ if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) send = 0; if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) send = 0; + mpu->chanref[chrefnum].M_DELKEY; break; - case 0x90: /* note on */ + case 0x90: /* Note on */ if (mpu->inputref[chan].on && (mpu->inputref[chan].M_GETKEY)) retrigger = 1; if (mpu->chanref[chrefnum].on && (!(mpu->chanref[chrefnum].M_GETKEY))) retrigger = 1; + mpu->chanref[chrefnum].M_SETKEY; break; case 0xb0: @@ -1063,7 +1132,6 @@ MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) return; } break; - default: break; } @@ -1073,7 +1141,7 @@ MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) midi_raw_out_byte(0); } if (send) { - for (uint8_t i = 0; i < mpu->playbuf[track].length; i++) + for (uint8_t i = 0; i < mpu->playbuf[track].vlength; ++i) midi_raw_out_byte(mpu->playbuf[track].value[i]); } break; @@ -1087,8 +1155,8 @@ static void UpdateTrack(mpu_t *mpu, uint8_t track) { MPU401_IntelligentOut(mpu, track); - if (mpu->state.amask & (1 << track)) { + mpu->playbuf[track].vlength = 0; mpu->playbuf[track].type = T_OVERFLOW; mpu->playbuf[track].counter = 0xf0; mpu->state.req_mask |= (1 << track); @@ -1098,46 +1166,78 @@ UpdateTrack(mpu_t *mpu, uint8_t track) } } -/* Updates counters and requests new data on "End of Input" */ static void -MPU401_EOIHandler(void *priv) +MPU401_Event(void *priv) { mpu_t *mpu = (mpu_t *) priv; - uint8_t i; - mpu401_log("MPU-401 end of input callback\n"); - - timer_disable(&mpu->mpu401_eoi_callback); - mpu->state.eoi_scheduled = 0; - if (mpu->state.send_now) { - mpu->state.send_now = 0; - if (mpu->state.cond_req) { - mpu->condbuf.counter = 0xf0; - mpu->state.req_mask |= (1 << 9); - } else - UpdateTrack(mpu, mpu->state.track); - } - - if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) + if (!mpu->intelligent || (mpu->mode == M_UART)) return; - if (!mpu->state.req_mask || !mpu->clock.active) - return; + if (mpu->state.irq_pending) + goto next_event; - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - } - - i = 0; - do { - if (mpu->state.req_mask & (1 << i)) { - MPU401_QueueByte(mpu, 0xf0 + i); - mpu->state.req_mask &= ~(1 << i); - break; + if (mpu->state.playing) { + /* Decrease counters. */ + for (uint8_t i = 0; i < 8; i++) { + if (mpu->state.amask & (1 << i)) { + if (mpu->playbuf[i].counter) + mpu->playbuf[i].counter--; + if (!mpu->playbuf[i].counter) + UpdateTrack(mpu, i); + } } - } while ((i++) < 16); + if (mpu->state.conductor) { + if (mpu->condbuf.counter) + mpu->condbuf.counter--; + if (!mpu->condbuf.counter) { + mpu->condbuf.vlength = 0; + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } + } + } + + if (mpu->state.clock_to_host) { + mpu->clock.cth_counter++; + if (mpu->clock.cth_counter >= mpu->clock.cth_rate[mpu->clock.cth_mode]) { + mpu->clock.cth_counter = 0; + ++mpu->clock.cth_mode; + mpu->clock.cth_mode %= 4; + mpu->state.req_mask |= (1 << 13); + } + } + + /* Recording */ + if (mpu->state.rec == M_RECON) { + mpu->clock.rec_counter++; + if (mpu->clock.rec_counter >= 240) { + mpu->clock.rec_counter = 0; + mpu->state.req_mask |= (1 << 8); + } + } + + if (mpu->state.playing || (mpu->state.rec == M_RECON)) { + int max_meascnt = (mpu->clock.timebase * mpu->clock.midimetro * mpu->clock.metromeas) / 24; + if (max_meascnt != 0) { /* Measure end */ + if (++mpu->clock.measure_counter >= max_meascnt) { + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xf8); + + mpu->clock.measure_counter=0; + if (mpu->filter.rec_measure_end && (mpu->state.rec == M_RECON)) + mpu->state.req_mask |= (1 << 12); + } + } + } + + if (!mpu->state.irq_pending && mpu->state.req_mask) + MPU401_EOIHandler(mpu); + +next_event: + MPU401_RunClock(mpu); + if (mpu->state.sync_in) + mpu->clock.ticks_in++; } static void @@ -1148,111 +1248,78 @@ MPU401_EOIHandlerDispatch(void *priv) mpu401_log("EOI handler dispatch\n"); if (mpu->state.send_now) { mpu->state.eoi_scheduled = 1; - timer_advance_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */ + timer_set_delay_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */ } else if (!mpu->state.eoi_scheduled) MPU401_EOIHandler(mpu); } +/* Updates counters and requests new data on "End of Input" */ +static void +MPU401_EOIHandler(void *priv) +{ + mpu_t *mpu = (mpu_t *) priv; + + mpu401_log("MPU-401 end of input callback\n"); + + mpu->state.eoi_scheduled = 0; + if (mpu->state.send_now) { + mpu->state.send_now = 0; + if (mpu->state.cond_req) { + mpu->condbuf.vlength = 0; + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } else + UpdateTrack(mpu, mpu->state.track); + } + if (mpu->state.rec_copy || !mpu->state.sysex_in_finished) + return; + + mpu->state.irq_pending = 0; + + if (!mpu->state.req_mask || !mpu->clock.active) + return; + + uint8_t i = 0; + do { + if (mpu->state.req_mask & (1 << i)) { + MPU401_QueueByte(mpu, 0xf0 + i); + mpu->state.req_mask &= ~(1 << i); + break; + } + } while ((i++) < 16); +} + +static __inline void +MPU401_NotesOff(mpu_t *mpu, unsigned int i) +{ + if (mpu->filter.allnotesoff_out && !(mpu->inputref[i].on && + (mpu->inputref[i].key[0] | mpu->inputref[i].key[1] | + mpu->inputref[i].key[2] | mpu->inputref[i].key[3]))) { + for (uint8_t j = 0;j < 4; j++) + mpu->chanref[mpu->ch_toref[i]].key[j] = 0; + + midi_raw_out_byte(0xb0 | i); + midi_raw_out_byte(123); + midi_raw_out_byte(0); + } else if (mpu->chanref[mpu->ch_toref[i]].on) { + for (uint8_t key = 0; key < 128; key++) { + if ((mpu->chanref[mpu->ch_toref[i]].M_GETKEY) && + !(mpu->inputref[i].on && (mpu->inputref[i].M_GETKEY))) { + midi_raw_out_byte(0x80 | i); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + mpu->chanref[mpu->ch_toref[i]].M_DELKEY; + } + } +} + static void imf_write(UNUSED(uint16_t addr), UNUSED(uint8_t val), UNUSED(void *priv)) { mpu401_log("IMF:Wr %4X,%X\n", addr, val); } -void -MPU401_ReadRaiseIRQ(mpu_t *mpu) -{ - /* Clear IRQ. */ - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 0); - else { - mpu->state.irq_pending = 0; - picintc(1 << mpu->irq); - } - - if (mpu->queue_used) { - /* Bytes remaining in queue, raise IRQ again. */ - if (mpu->ext_irq_update) - mpu->ext_irq_update(mpu->priv, 1); - else { - mpu->state.irq_pending = 1; - picint(1 << mpu->irq); - } - } -} - -uint8_t -MPU401_ReadData(mpu_t *mpu) -{ - uint8_t ret; - - ret = MSG_MPU_ACK; - - if (mpu->queue_used) { - if (mpu->queue_pos >= MPU401_QUEUE) - mpu->queue_pos -= MPU401_QUEUE; - ret = mpu->queue[mpu->queue_pos]; - mpu->queue_pos++; - mpu->queue_used--; - } - - /* Shouldn't this check mpu->mode? */ -#ifdef DOSBOX_CODE - if (mpu->mode == M_UART) { - MPU401_ReadRaiseIRQ(mpu); - return ret; - } -#else - if (!mpu->intelligent || (mpu->mode == M_UART)) { - MPU401_ReadRaiseIRQ(mpu); - return ret; - } -#endif - - if (mpu->state.rec_copy && !mpu->rec_queue_used) { - mpu->state.rec_copy = 0; - MPU401_EOIHandler(mpu); - return ret; - } - - /* Copy from recording buffer. */ - if (!mpu->queue_used && mpu->rec_queue_used) { - mpu->state.rec_copy = 1; - if (mpu->rec_queue_pos >= MPU401_INPUT_QUEUE) - mpu->rec_queue_pos -= MPU401_INPUT_QUEUE; - MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); - mpu->rec_queue_pos++; - mpu->rec_queue_used--; - } - - MPU401_ReadRaiseIRQ(mpu); - - if ((ret >= 0xf0) && (ret <= 0xf7)) { - /* MIDI data request */ - mpu->state.track = ret & 7; - mpu->state.data_onoff = 0; - mpu->state.cond_req = 0; - mpu->state.track_req = 1; - } - - if (ret == MSG_MPU_COMMAND_REQ) { - mpu->state.data_onoff = 0; - mpu->state.cond_req = 1; - if (mpu->condbuf.type != T_OVERFLOW) { - mpu->state.block_ack = 1; - MPU401_WriteCommand(mpu, mpu->condbuf.value[0]); - if (mpu->state.command_byte) - MPU401_WriteData(mpu, mpu->condbuf.value[1]); - mpu->condbuf.type = T_OVERFLOW; - } - } - - if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK) || (ret == MSG_MPU_OVERFLOW)) - MPU401_EOIHandlerDispatch(mpu); - - return ret; -} - void mpu401_write(uint16_t addr, uint8_t val, void *priv) { @@ -1288,12 +1355,7 @@ mpu401_read(uint16_t addr, void *priv) break; case 1: /* Read Status */ - if (mpu->state.cmd_pending) - ret = STATUS_OUTPUT_NOT_READY; - if (!mpu->queue_used) - ret = STATUS_INPUT_NOT_READY; - ret |= 0x3f; - + ret = MPU401_ReadStatus(mpu); mpu401_log("Read Status (0x331) %x\n", ret); break; @@ -1305,111 +1367,6 @@ mpu401_read(uint16_t addr, void *priv) return ret; } -static void -MPU401_Event(void *priv) -{ - mpu_t *mpu = (mpu_t *) priv; - int max_meascnt; - - mpu401_log("MPU-401 event callback\n"); - -#ifdef DOSBOX_CODE - if (mpu->mode == M_UART) { - timer_disable(&mpu->mpu401_event_callback); - return; - } -#else - if (!mpu->intelligent || (mpu->mode == M_UART)) { - timer_disable(&mpu->mpu401_event_callback); - return; - } -#endif - - if (MPU401_IRQPending(mpu)) - goto next_event; - - if (mpu->state.playing) { - for (uint8_t i = 0; i < 8; i++) { - /* Decrease counters. */ - if (mpu->state.amask & (1 << i)) { - mpu->playbuf[i].counter--; - if (mpu->playbuf[i].counter <= 0) - UpdateTrack(mpu, i); - } - } - - if (mpu->state.conductor) { - mpu->condbuf.counter--; - if (mpu->condbuf.counter <= 0) { - mpu->condbuf.counter = 0xf0; - mpu->state.req_mask |= (1 << 9); - } - } - } - - if (mpu->state.clock_to_host) { - mpu->clock.cth_counter++; - if (mpu->clock.cth_counter >= mpu->clock.cth_rate[mpu->clock.cth_mode]) { - mpu->clock.cth_counter = 0; - mpu->clock.cth_mode++; - mpu->clock.cth_mode %= 4; - mpu->state.req_mask |= (1 << 13); - } - } - - if (mpu->state.rec == M_RECON) { - /* Recording. */ - mpu->clock.rec_counter++; - if (mpu->clock.rec_counter >= 240) { - mpu->clock.rec_counter = 0; - mpu->state.req_mask |= (1 << 8); - } - } - - if (mpu->state.playing || (mpu->state.rec == M_RECON)) { - max_meascnt = (mpu->clock.timebase * mpu->clock.midimetro * mpu->clock.metromeas) / 24; - if (max_meascnt != 0) { - /* Measure end. */ - if (++mpu->clock.measure_counter >= max_meascnt) { - if (mpu->filter.rt_out) - midi_raw_out_rt_byte(0xf8); - mpu->clock.measure_counter = 0; - if (mpu->filter.rec_measure_end && (mpu->state.rec == M_RECON)) - mpu->state.req_mask |= (1 << 12); - } - } - } - - if (!MPU401_IRQPending(mpu) && mpu->state.req_mask) - MPU401_EOIHandler(mpu); - -next_event: - MPU401_RunClock(mpu); - if (mpu->state.sync_in) - mpu->clock.ticks_in++; -} - -static void -MPU401_NotesOff(mpu_t *mpu, int i) -{ - if (mpu->filter.allnotesoff_out && !(mpu->inputref[i].on && (mpu->inputref[i].key[0] | mpu->inputref[i].key[1] | mpu->inputref[i].key[2] | mpu->inputref[i].key[3]))) { - for (uint8_t j = 0; j < 4; j++) - mpu->chanref[mpu->ch_toref[i]].key[j] = 0; - midi_raw_out_byte(0xb0 | i); - midi_raw_out_byte(123); - midi_raw_out_byte(0); - } else if (mpu->chanref[mpu->ch_toref[i]].on) { - for (uint8_t key = 0; key < 128; key++) { - if ((mpu->chanref[mpu->ch_toref[i]].M_GETKEY) && !(mpu->inputref[i].on && (mpu->inputref[i].M_GETKEY))) { - midi_raw_out_byte(0x80 | i); - midi_raw_out_byte(key); - midi_raw_out_byte(0); - } - mpu->chanref[mpu->ch_toref[i]].M_DELKEY; - } - } -} - /*Input handler for SysEx */ int MPU401_InputSysex(void *priv, uint8_t *buffer, uint32_t len, int abort) @@ -1420,14 +1377,12 @@ MPU401_InputSysex(void *priv, uint8_t *buffer, uint32_t len, int abort) mpu401_log("MPU401 Input Sysex\n"); -#ifdef DOSBOX_CODE - if (mpu->mode == M_UART) { -#else if (!mpu->intelligent || mpu->mode == M_UART) { -#endif /* UART mode input. */ for (i = 0; i < len; i++) MPU401_QueueByte(mpu, buffer[i]); + + MPU401_ReadRaiseIRQ(mpu); return 0; } @@ -1440,7 +1395,7 @@ MPU401_InputSysex(void *priv, uint8_t *buffer, uint32_t len, int abort) if (mpu->state.sysex_in_finished) { if (mpu->rec_queue_used >= MPU401_INPUT_QUEUE) return len; - MPU401_RecQueueBuffer(mpu, &val_ff, 1, 1); + MPU401_RecQueueBuffer(mpu, &val_ff, 1); mpu->state.sysex_in_finished = 0; mpu->clock.rec_counter = 0; } @@ -1449,10 +1404,10 @@ MPU401_InputSysex(void *priv, uint8_t *buffer, uint32_t len, int abort) int available = MPU401_INPUT_QUEUE - mpu->rec_queue_used; if (available >= len) { - MPU401_RecQueueBuffer(mpu, buffer, len, 1); + MPU401_RecQueueBuffer(mpu, buffer, len); return 0; } else { - MPU401_RecQueueBuffer(mpu, buffer, available, 1); + MPU401_RecQueueBuffer(mpu, buffer, available); if (mpu->state.sysex_in_finished) return 0; return (len - available); @@ -1490,11 +1445,7 @@ MPU401_InputMsg(void *priv, uint8_t *msg, uint32_t len) mpu401_log("MPU401 Input Msg\n"); -#ifdef DOSBOX_CODE - if (mpu->mode == M_INTELLIGENT) { -#else if (mpu->intelligent && (mpu->mode == M_INTELLIGENT)) { -#endif if (msg[0] < 0x80) { /* Expand running status */ msg[2] = msg[1]; @@ -1606,7 +1557,7 @@ MPU401_InputMsg(void *priv, uint8_t *msg, uint32_t len) if (!(mpu->filter.rt_in && (msg[0] <= 0xfc) && (msg[0] >= 0xfa))) { recdata[0] = 0xff; recdata[1] = msg[0]; - MPU401_RecQueueBuffer(mpu, recdata, 2, 1); + MPU401_RecQueueBuffer(mpu, recdata, 2); send = 0; } } else { /* Common or system. */ @@ -1624,7 +1575,7 @@ MPU401_InputMsg(void *priv, uint8_t *msg, uint32_t len) recmsg[1] = msg[0]; recmsg[2] = msg[1]; recmsg[3] = msg[2]; - MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + MPU401_RecQueueBuffer(mpu, recmsg, len + 1); } if (mpu->filter.rt_affection) { switch (msg[0]) { @@ -1678,7 +1629,7 @@ MPU401_InputMsg(void *priv, uint8_t *msg, uint32_t len) recmsg[1] = msg[0]; recmsg[2] = msg[1]; recmsg[3] = msg[2]; - MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + MPU401_RecQueueBuffer(mpu, recmsg, len + 1); mpu->clock.rec_counter = 0; } else if (mpu->filter.data_in_stop) { if (mpu->filter.timing_in_stop) { @@ -1686,13 +1637,13 @@ MPU401_InputMsg(void *priv, uint8_t *msg, uint32_t len) recmsg[1] = msg[0]; recmsg[2] = msg[1]; recmsg[3] = msg[2]; - MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + MPU401_RecQueueBuffer(mpu, recmsg, len + 1); } else { recmsg[0] = msg[0]; recmsg[1] = msg[1]; recmsg[2] = msg[2]; recmsg[3] = 0; - MPU401_RecQueueBuffer(mpu, recmsg, len, 1); + MPU401_RecQueueBuffer(mpu, recmsg, len); } } } @@ -1702,6 +1653,8 @@ MPU401_InputMsg(void *priv, uint8_t *msg, uint32_t len) /* UART mode input. */ for (i = 0; i < len; i++) MPU401_QueueByte(mpu, msg[i]); + + MPU401_ReadRaiseIRQ(mpu); } void @@ -1823,8 +1776,7 @@ mpu401_standalone_init(const device_t *info) int irq; uint16_t base; - mpu = malloc(sizeof(mpu_t)); - memset(mpu, 0, sizeof(mpu_t)); + mpu = calloc(1, sizeof(mpu_t)); mpu401_log("mpu_init\n"); diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index f51ff4d25..2513d36f6 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -442,7 +442,7 @@ sb_dsp_set_mpu(sb_dsp_t *dsp, mpu_t *mpu) { dsp->mpu = mpu; - if (mpu != NULL) + if (IS_NOT_ESS(dsp) && (mpu != NULL)) mpu401_irq_attach(mpu, sb_dsp_irq_update, sb_dsp_irq_pending, dsp); }