From 0ea3a1307cf8501ff135e2c79ea93befd1980b5a Mon Sep 17 00:00:00 2001 From: OBattler Date: Tue, 11 Sep 2018 22:41:14 +0200 Subject: [PATCH] Fixed the MCA MPU-401 and gave it its correct name; Sound Blaster 16/AWE32 MPU-401 is now always the less-functional variant like it would be on real hardware and its IRQ is always shared with the sound card; Standalone MPU-401 is now always the fully functional intelligent mode variant; Standalone MPU-401 is now always available, even when Sound Blaster 16/AWE32 is in use; Cleaned up sound/midi.c and win/win_midi.c. --- src/plat_midi.h | 7 +- src/sound/midi.c | 394 ++++++++++++++------------- src/sound/snd_mpu401.c | 585 ++++++++++++++++++++--------------------- src/sound/snd_mpu401.h | 111 ++++---- src/sound/snd_sb.c | 100 +------ src/sound/sound.c | 40 +-- src/win/win_midi.c | 200 +++++++------- src/win/win_settings.c | 32 ++- 8 files changed, 697 insertions(+), 772 deletions(-) diff --git a/src/plat_midi.h b/src/plat_midi.h index 1d167c475..5070de68a 100644 --- a/src/plat_midi.h +++ b/src/plat_midi.h @@ -1,8 +1,9 @@ extern void plat_midi_init(void); extern void plat_midi_close(void); -extern void plat_midi_play_msg(uint8_t* val); -extern void plat_midi_play_sysex(uint8_t* data, unsigned int len); +extern void plat_midi_play_msg(uint8_t *msg); +extern void plat_midi_play_sysex(uint8_t *sysex, unsigned int len); extern int plat_midi_write(uint8_t val); -extern int plat_midi_get_num_devs(); + +extern int plat_midi_get_num_devs(void); extern void plat_midi_get_dev_name(int num, char *s); diff --git a/src/sound/midi.c b/src/sound/midi.c index d49eb6b29..197189de7 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -1,3 +1,25 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * MIDI device core module. + * + * Version: @(#)midi.c 1.0.0 2018/09/06 + * + * Authors: Sarah Walker, + * Miran Grca, + * Bit, + * DOSBox Team, + * + * Copyright 2008-2018 Sarah Walker. + * Copyright 2016-2018 Miran Grca. + * Copyright 2016-2018 Bit. + * Copyright 2008-2018 DOSBox Team. + */ #include #include #include @@ -17,244 +39,248 @@ #endif +#define SYSEX_SIZE 1024 +#define RAWBUF 1024 + int midi_device_current = 0; static int midi_device_last = 0; typedef struct { - const char *name; - const char *internal_name; - const device_t *device; + uint8_t midi_rt_buf[1024], midi_cmd_buf[1024], + midi_status, midi_sysex_data[1026]; + int midi_cmd_pos, midi_cmd_len; + unsigned int midi_sysex_start, midi_sysex_delay, + midi_pos; + midi_device_t* m_device; +} midi_t; + +static midi_t *midi = NULL; + +static uint8_t MIDI_evt_len[256] = { + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x00 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x10 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x20 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x30 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x40 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x50 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x60 */ + 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, /* 0x70 */ + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0x80 */ + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0x90 */ + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xa0 */ + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xb0 */ + + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* 0xc0 */ + 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, /* 0xd0 */ + + 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, /* 0xe0 */ + + 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 /* 0xf0 */ +}; + +typedef struct +{ + const char *name, *internal_name; + const device_t *device; } MIDI_DEVICE; static const MIDI_DEVICE devices[] = { - {"None", "none", NULL}, + {"None", "none", NULL}, #ifdef USE_FLUIDSYNTH - {"FluidSynth", "fluidsynth", &fluidsynth_device}, + {"FluidSynth", "fluidsynth", &fluidsynth_device}, #endif #ifdef USE_MUNT - {"Roland MT-32 Emulation", "mt32", &mt32_device}, - {"Roland CM-32L Emulation", "cm32l", &cm32l_device}, + {"Roland MT-32 Emulation", "mt32", &mt32_device}, + {"Roland CM-32L Emulation", "cm32l", &cm32l_device}, #endif - {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, - {"", "", NULL} + {SYSTEM_MIDI_NAME, SYSTEM_MIDI_INTERNAL_NAME, &system_midi_device}, + {"", "", NULL} }; -static midi_device_t* m_device = NULL; -int midi_device_available(int card) +int +midi_device_available(int card) { - if (devices[card].device) - return device_available(devices[card].device); + if (devices[card].device) + return device_available(devices[card].device); - return 1; + return 1; } -char *midi_device_getname(int card) + +char * +midi_device_getname(int card) { - return (char *) devices[card].name; + return (char *) devices[card].name; } -const device_t *midi_device_getdevice(int card) + +const device_t * +midi_device_getdevice(int card) { - return devices[card].device; + return devices[card].device; } -int midi_device_has_config(int card) -{ - if (!devices[card].device) - return 0; - return devices[card].device->config ? 1 : 0; -} -char *midi_device_get_internal_name(int card) +int +midi_device_has_config(int card) { - return (char *) devices[card].internal_name; -} - -int midi_device_get_from_internal_name(char *s) -{ - int c = 0; - - while (strlen(devices[c].internal_name)) - { - if (!strcmp(devices[c].internal_name, s)) - return c; - c++; - } - + if (!devices[card].device) return 0; + return devices[card].device->config ? 1 : 0; } -void midi_device_init() + +char * +midi_device_get_internal_name(int card) { - if (devices[midi_device_current].device) - device_add(devices[midi_device_current].device); - midi_device_last = midi_device_current; + return (char *) devices[card].internal_name; } -static uint8_t midi_rt_buf[1024]; -static uint8_t midi_cmd_buf[1024]; -static int midi_cmd_pos = 0; -static int midi_cmd_len = 0; -static uint8_t midi_status = 0; -static unsigned int midi_sysex_start = 0; -static unsigned int midi_sysex_delay = 0; -uint8_t MIDI_evt_len[256] = { - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x00 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x10 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x20 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x30 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x40 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x50 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x60 - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, // 0x70 - - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x80 - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0x90 - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xa0 - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xb0 - - 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xc0 - 2,2,2,2, 2,2,2,2, 2,2,2,2, 2,2,2,2, // 0xd0 - - 3,3,3,3, 3,3,3,3, 3,3,3,3, 3,3,3,3, // 0xe0 - - 0,2,3,2, 0,0,1,0, 1,0,1,1, 1,0,1,0 // 0xf0 -}; - -static unsigned int midi_pos; -static uint8_t midi_sysex_data[1024+2]; - -void midi_init(midi_device_t* device) +int +midi_device_get_from_internal_name(char *s) { - memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); - memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + int c = 0; - midi_cmd_pos = midi_cmd_len = 0; - midi_status = 0; - - midi_sysex_start = midi_sysex_delay = 0; - - m_device = device; + while (strlen(devices[c].internal_name)) { + if (!strcmp(devices[c].internal_name, s)) + return c; + c++; + } + return 0; } -void midi_close() + +void +midi_device_init() { - m_device = NULL; + if (devices[midi_device_current].device) + device_add(devices[midi_device_current].device); + midi_device_last = midi_device_current; } -void midi_poll() + +void +midi_init(midi_device_t* device) { - if (m_device && m_device->poll) m_device->poll(); + midi = (midi_t *) malloc(sizeof(midi_t)); + memset(midi, 0, sizeof(midi_t)); + + midi->m_device = device; } -void play_msg(uint8_t *msg) + +void +midi_close(void) { - if (m_device->play_msg) m_device->play_msg(msg); + if (midi) { + free(midi); + midi = NULL; + } } -void play_sysex(uint8_t *sysex, unsigned int len) +void +midi_poll(void) { - if (m_device->play_sysex) m_device->play_sysex(sysex, len); + if (midi && midi->m_device && midi->m_device->poll) + midi->m_device->poll(); } -#define SYSEX_SIZE 1024 -#define RAWBUF 1024 -void midi_write(uint8_t val) +void +play_msg(uint8_t *msg) { - if (!m_device) return; - - if (m_device->write && m_device->write(val)) return; - - uint32_t passed_ticks; - - if (midi_sysex_start) - { - passed_ticks = plat_get_ticks() - midi_sysex_start; - if (passed_ticks < midi_sysex_delay) - { - plat_delay_ms(midi_sysex_delay - passed_ticks); - } - } - - /* Test for a realtime MIDI message */ - if (val >= 0xf8) - { - midi_rt_buf[0] = val; - play_msg(midi_rt_buf); - return; - } - - /* Test for a active sysex transfer */ - - if (midi_status == 0xf0) - { - if (!(val & 0x80)) - { - if (midi_pos < (SYSEX_SIZE-1)) midi_sysex_data[midi_pos++] = val; - return; - } - else - { - midi_sysex_data[midi_pos++] = 0xf7; - - if ((midi_sysex_start) && (midi_pos >= 4) && (midi_pos <= 9) && (midi_sysex_data[1] == 0x41) && (midi_sysex_data[3] == 0x16)) - { - /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ - } - else - { - play_sysex(midi_sysex_data, midi_pos); - if (midi_sysex_start) - { - if (midi_sysex_data[5] == 0x7f) - { - midi_sysex_delay = 290; /* All parameters reset */ - } - else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x04)) - { - midi_sysex_delay = 145; /* Viking Child */ - } - else if ((midi_sysex_data[5] == 0x10) && (midi_sysex_data[6] == 0x00) && (midi_sysex_data[7] == 0x01)) - { - midi_sysex_delay = 30; /* Dark Sun 1 */ - } - else - midi_sysex_delay = (unsigned int) (((float) (midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; - - midi_sysex_start = plat_get_ticks(); - } - } - } - } - - - if (val & 0x80) - { - midi_status = val; - midi_cmd_pos = 0; - midi_cmd_len = MIDI_evt_len[val]; - if (midi_status == 0xf0) - { - midi_sysex_data[0] = 0xf0; - midi_pos = 1; - } - } - - if (midi_cmd_len) - { - midi_cmd_buf[midi_cmd_pos++] = val; - if (midi_cmd_pos >= midi_cmd_len) - { - play_msg(midi_cmd_buf); - midi_cmd_pos = 1; - } - } + if (midi->m_device->play_msg) + midi->m_device->play_msg(msg); +} + + +void +play_sysex(uint8_t *sysex, unsigned int len) +{ + if (midi->m_device->play_sysex) + midi->m_device->play_sysex(sysex, len); +} + + +void +midi_write(uint8_t val) +{ + uint32_t passed_ticks; + + if (!midi || !midi->m_device) + return; + + if (midi->m_device->write && midi->m_device->write(val)) + return; + + if (midi->midi_sysex_start) { + passed_ticks = plat_get_ticks() - midi->midi_sysex_start; + if (passed_ticks < midi->midi_sysex_delay) + plat_delay_ms(midi->midi_sysex_delay - passed_ticks); + } + + /* Test for a realtime MIDI message */ + if (val >= 0xf8) { + midi->midi_rt_buf[0] = val; + play_msg(midi->midi_rt_buf); + return; + } + + /* Test for a active sysex transfer */ + if (midi->midi_status == 0xf0) { + if (!(val & 0x80)) { + if (midi->midi_pos < (SYSEX_SIZE-1)) + midi->midi_sysex_data[midi->midi_pos++] = val; + return; + } else { + midi->midi_sysex_data[midi->midi_pos++] = 0xf7; + + if ((midi->midi_sysex_start) && (midi->midi_pos >= 4) && (midi->midi_pos <= 9) && + (midi->midi_sysex_data[1] == 0x41) && (midi->midi_sysex_data[3] == 0x16)) { + /* pclog("MIDI: Skipping invalid MT-32 SysEx MIDI message\n"); */ + } else { + play_sysex(midi->midi_sysex_data, midi->midi_pos); + if (midi->midi_sysex_start) { + if (midi-> midi_sysex_data[5] == 0x7f) + midi->midi_sysex_delay = 290; /* All parameters reset */ + else if ((midi->midi_sysex_data[5] == 0x10) && (midi->midi_sysex_data[6] == 0x00) && + (midi->midi_sysex_data[7] == 0x04)) + midi->midi_sysex_delay = 145; /* Viking Child */ + else if ((midi->midi_sysex_data[5] == 0x10) && (midi->midi_sysex_data[6] == 0x00) && + (midi->midi_sysex_data[7] == 0x01)) + midi->midi_sysex_delay = 30; /* Dark Sun 1 */ + else + midi->midi_sysex_delay = (unsigned int) (((float) (midi->midi_pos) * 1.25f) * 1000.0f / 3125.0f) + 2; + + midi->midi_sysex_start = plat_get_ticks(); + } + } + } + } + + if (val & 0x80) { + midi->midi_status = val; + midi->midi_cmd_pos = 0; + midi->midi_cmd_len = MIDI_evt_len[val]; + if (midi->midi_status == 0xf0) { + midi->midi_sysex_data[0] = 0xf0; + midi->midi_pos = 1; + } + } + + if (midi->midi_cmd_len) { + midi->midi_cmd_buf[midi->midi_cmd_pos++] = val; + if (midi->midi_cmd_pos >= midi->midi_cmd_len) { + play_msg(midi->midi_cmd_buf); + midi->midi_cmd_pos = 1; + } + } } diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 8a9d4503b..979b41854 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -8,7 +8,7 @@ * * Roland MPU-401 emulation. * - * Version: @(#)snd_mpu401.c 1.0.12 2018/09/04 + * Version: @(#)snd_mpu401.c 1.0.14 2018/09/11 * * Authors: Sarah Walker, * DOSBox Team, @@ -80,13 +80,12 @@ static void QueueByte(mpu_t *mpu, uint8_t data) { if (mpu->state.block_ack) { - mpu->state.block_ack=0; + mpu->state.block_ack = 0; return; } if ((mpu->queue_used == 0) && (mpu->mode == M_INTELLIGENT)) { - // if (mpu->queue_used == 0 && mpu->intelligent) { - mpu->state.irq_pending=1; + mpu->state.irq_pending = 1; picint(1 << mpu->irq); } if (mpu->queue_used < MPU401_QUEUE) { @@ -99,7 +98,7 @@ QueueByte(mpu_t *mpu, uint8_t data) pos-=MPU401_QUEUE; mpu->queue_used++; - mpu->queue[pos]=data; + mpu->queue[pos] = data; } else mpu401_log("MPU401:Data queue full\n"); } @@ -120,7 +119,7 @@ MPU401_Reset(mpu_t *mpu) picintc(1 << mpu->irq); - mpu->mode = (mpu->intelligent ? M_INTELLIGENT : M_UART); + mpu->mode = M_INTELLIGENT; mpu->state.eoi_scheduled = 0; mpu->state.wsd = 0; mpu->state.wsm = 0; @@ -166,10 +165,10 @@ MPU401_ResetDone(void *priv) mpu401_reset_callback = 0LL; - mpu->state.reset=0; + mpu->state.reset = 0; if (mpu->state.cmd_pending) { - MPU401_WriteCommand(mpu, mpu->state.cmd_pending-1); - mpu->state.cmd_pending=0; + MPU401_WriteCommand(mpu, mpu->state.cmd_pending - 1); + mpu->state.cmd_pending = 0; } } @@ -177,11 +176,13 @@ MPU401_ResetDone(void *priv) static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) { - uint8_t i; + uint8_t i, was_uart; - if (mpu->state.reset) { - mpu->state.cmd_pending=val+1; - } + if (mpu->state.reset) + mpu->state.cmd_pending = val + 1; + + if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent) + return; if (val <= 0x2f) { switch (val&3) { /* MIDI stop, start, continue */ @@ -203,7 +204,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->state.playing = 0; mpu401_event_callback = 0LL; - for (i=0xb0; i<0xbf; i++) { + for (i = 0xb0; i < 0xbf; i++) { /* All notes off */ midi_write(i); midi_write(0x7b); @@ -217,9 +218,10 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) ClrQueue(mpu); break; } - } else if (val>=0xa0 && val<=0xa7) { /* Request play counter */ - if (mpu->state.cmask&(1<<(val&7))) QueueByte(mpu, mpu->playbuf[val&7].counter); - } else if (val>=0xd0 && val<=0xd7) { /* Send data */ + } else if ((val >= 0xa0) && (val <= 0xa7)) { /* Request play counter */ + if (mpu->state.cmask & (1 << (val&7))) + QueueByte(mpu, mpu->playbuf[val&7].counter); + } else if ((val >= 0xd0) && (val <= 0xd7)) { /* Send data */ mpu->state.old_chan = mpu->state.channel; mpu->state.channel= val & 7; mpu->state.wsd = 1; @@ -241,44 +243,44 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) break; case 0x94: /* Clock to host */ - mpu->clock.clock_to_host=0; + mpu->clock.clock_to_host = 0; break; case 0x95: - mpu->clock.clock_to_host=1; + mpu->clock.clock_to_host = 1; break; case 0xc2: /* Internal timebase */ - mpu->clock.timebase=48; + mpu->clock.timebase = 48; break; case 0xc3: - mpu->clock.timebase=72; + mpu->clock.timebase = 72; break; case 0xc4: - mpu->clock.timebase=96; + mpu->clock.timebase = 96; break; case 0xc5: - mpu->clock.timebase=120; + mpu->clock.timebase = 120; break; case 0xc6: - mpu->clock.timebase=144; + mpu->clock.timebase = 144; break; case 0xc7: - mpu->clock.timebase=168; + mpu->clock.timebase = 168; break; case 0xc8: - mpu->clock.timebase=192; + mpu->clock.timebase = 192; break; /* Commands with data byte */ case 0xe0: case 0xe1: case 0xe2: case 0xe4: case 0xe6: case 0xe7: case 0xec: case 0xed: case 0xee: case 0xef: - mpu->state.command_byte=val; + mpu->state.command_byte = val; break; /* Commands 0xa# returning data */ @@ -303,49 +305,49 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) return; case 0xb1: /* Reset relative tempo */ - mpu->clock.old_tempo_rel=mpu->clock.tempo_rel; - mpu->clock.tempo_rel=40; + mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; + mpu->clock.tempo_rel = 40; break; case 0xb9: /* Clear play map */ case 0xb8: /* Clear play counters */ - for (i=0xb0;i<0xbf;i++) { + for (i = 0xb0; i < 0xbf; i++) { /* All notes off */ midi_write(i); midi_write(0x7b); midi_write(0); } - for (i=0;i<8;i++) { - mpu->playbuf[i].counter=0; - mpu->playbuf[i].type=T_OVERFLOW; + for (i = 0; i < 8; i++) { + mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; } - mpu->condbuf.counter=0; - mpu->condbuf.type=T_OVERFLOW; + mpu->condbuf.counter = 0; + mpu->condbuf.type = T_OVERFLOW; if (!(mpu->state.conductor=mpu->state.cond_set)) - mpu->state.cond_req=0; - mpu->state.amask=mpu->state.tmask; - mpu->state.req_mask=0; - mpu->state.irq_pending=1; + mpu->state.cond_req = 0; + mpu->state.amask = mpu->state.tmask; + mpu->state.req_mask = 0; + mpu->state.irq_pending = 1; break; case 0xff: /* Reset MPU-401 */ mpu401_log("MPU-401:Reset %X\n",val); mpu401_reset_callback = MPU401_RESETBUSY * 33LL * TIMER_USEC; - mpu->state.reset=1; + mpu->state.reset = 1; + was_uart = (mpu->mode == M_UART); MPU401_Reset(mpu); -#if 0 - if (mpu->mode==M_UART) return;//do not send ack in UART mode -#endif + if (was_uart) + return; /* do not send ack in UART mode */ break; case 0x3f: /* UART mode */ mpu401_log("MPU-401:Set UART mode %X\n",val); QueueByte(mpu, MSG_MPU_ACK); - mpu->mode=M_UART; + mpu->mode = M_UART; return; - default:; - //mpu401_log("MPU-401:Unhandled command %X",val); + /* default: + mpu401_log("MPU-401:Unhandled command %X",val); */ } QueueByte(mpu, MSG_MPU_ACK); @@ -355,80 +357,85 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) static void MPU401_WriteData(mpu_t *mpu, uint8_t val) { - if (mpu->mode==M_UART) {midi_write(val); return;} + static int length, cnt, posd; + + if (mpu->mode == M_UART) { + midi_write(val); + return; + } + + if (!mpu->intelligent) { + mpu->state.command_byte = 0; + return; + } switch (mpu->state.command_byte) { /* 0xe# command data */ case 0x00: break; case 0xe0: /* Set tempo */ - mpu->state.command_byte=0; - mpu->clock.tempo=val; + mpu->state.command_byte = 0; + mpu->clock.tempo = val; 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; + mpu->state.command_byte = 0; + mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; + mpu->clock.tempo_rel = val; return; case 0xe7: /* Set internal clock to host interval */ - mpu->state.command_byte=0; - mpu->clock.cth_rate=val>>2; + mpu->state.command_byte = 0; + mpu->clock.cth_rate = val >> 2; return; case 0xec: /* Set active track mask */ - mpu->state.command_byte=0; - mpu->state.tmask=val; + mpu->state.command_byte = 0; + mpu->state.tmask = val; return; case 0xed: /* Set play counter mask */ - mpu->state.command_byte=0; - mpu->state.cmask=val; + mpu->state.command_byte = 0; + mpu->state.cmask = val; return; case 0xee: /* Set 1-8 MIDI channel mask */ - mpu->state.command_byte=0; - mpu->state.midi_mask&=0xff00; - mpu->state.midi_mask|=val; + mpu->state.command_byte = 0; + mpu->state.midi_mask &= 0xff00; + mpu->state.midi_mask |= val; return; case 0xef: /* Set 9-16 MIDI channel mask */ - mpu->state.command_byte=0; - mpu->state.midi_mask&=0x00ff; - mpu->state.midi_mask|=((uint16_t)val)<<8; + mpu->state.command_byte = 0; + mpu->state.midi_mask &= 0x00ff; + mpu->state.midi_mask |= ((uint16_t) val) << 8; return; - //case 0xe2: /* Set graduation for relative tempo */ - //case 0xe4: /* Set metronome */ - //case 0xe6: /* Set metronome measure length */ default: - mpu->state.command_byte=0; + mpu->state.command_byte = 0; return; } - static int length,cnt,posd; - if (mpu->state.wsd) { /* Directly send MIDI message */ if (mpu->state.wsd_start) { - mpu->state.wsd_start=0; - cnt=0; - switch (val&0xf0) { - case 0xc0:case 0xd0: - mpu->playbuf[mpu->state.channel].value[0]=val; - length=2; + mpu->state.wsd_start = 0; + cnt = 0; + switch (val & 0xf0) { + case 0xc0: case 0xd0: + mpu->playbuf[mpu->state.channel].value[0] = val; + length = 2; break; - case 0x80:case 0x90:case 0xa0:case 0xb0:case 0xe0: - mpu->playbuf[mpu->state.channel].value[0]=val; - length=3; + case 0x80: case 0x90: case 0xa0: case 0xb0:case 0xe0: + mpu->playbuf[mpu->state.channel].value[0] = val; + length = 3; break; case 0xf0: - //mpu401_log("MPU-401:Illegal WSD byte\n"); - mpu->state.wsd=0; - mpu->state.channel=mpu->state.old_chan; + /* mpu401_log("MPU-401:Illegal WSD byte\n"); */ + mpu->state.wsd = 0; + mpu->state.channel = mpu->state.old_chan; return; default: /* MIDI with running status */ @@ -437,49 +444,57 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) } } - if (cntstate.wsd=0; - mpu->state.channel=mpu->state.old_chan; + if (cnt == length) { + mpu->state.wsd = 0; + mpu->state.channel = mpu->state.old_chan; } return; } if (mpu->state.wsm) { /* Directly send system message */ - if (val==MSG_EOX) {midi_write(MSG_EOX);mpu->state.wsm=0;return;} + if (val == MSG_EOX) { + midi_write(MSG_EOX); + mpu->state.wsm = 0; + return; + } if (mpu->state.wsd_start) { - mpu->state.wsd_start=0; - cnt=0; + mpu->state.wsd_start = 0; + cnt = 0; switch (val) { case 0xf2: - length=3; + length = 3; break; case 0xf3: - length=2; + length = 2; break; case 0xf6: - length=1; + length = 1; break; case 0xf0: - length=0; + length = 0; break; default: - length=0; + length = 0; } } - if (!length || cntstate.wsm=0; + if (cnt == length) + mpu->state.wsm = 0; return; } @@ -491,27 +506,29 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) return; case 0: /* Timing byte */ - mpu->condbuf.vlength=0; - if (val<0xf0) mpu->state.data_onoff++; - else { - mpu->state.data_onoff=-1; + mpu->condbuf.vlength = 0; + if (val < 0xf0) + mpu->state.data_onoff++; + else { + mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); return; } - if (val==0) mpu->state.send_now=1; - else mpu->state.send_now=0; - mpu->condbuf.counter=val; + mpu->state.send_now = !val ? 1 : 0; + mpu->condbuf.counter = val; break; case 1: /* Command byte #1 */ - mpu->condbuf.type=T_COMMAND; - if (val==0xf8 || val==0xf9) - mpu->condbuf.type=T_OVERFLOW; - mpu->condbuf.value[mpu->condbuf.vlength]=val; + mpu->condbuf.type = T_COMMAND; + if ((val == 0xf8) || (val == 0xf9)) + mpu->condbuf.type = T_OVERFLOW; + mpu->condbuf.value[mpu->condbuf.vlength] = val; mpu->condbuf.vlength++; - if ((val&0xf0)!=0xe0) MPU401_EOIHandlerDispatch(mpu); - else mpu->state.data_onoff++; + if ((val & 0xf0) != 0xe0) + MPU401_EOIHandlerDispatch(mpu); + else + mpu->state.data_onoff++; break; case 2:/* Command byte #2 */ @@ -529,55 +546,55 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) return; case 0: /* Timing byte */ - if (val<0xf0) mpu->state.data_onoff=1; - else { - mpu->state.data_onoff=-1; + if (val < 0xf0) + mpu->state.data_onoff = 1; + else { + mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); return; } - if (val==0) mpu->state.send_now=1; - else mpu->state.send_now=0; - mpu->playbuf[mpu->state.channel].counter=val; + mpu->state.send_now = !val ? 1 : 0; + mpu->playbuf[mpu->state.channel].counter = val; break; case 1: /* MIDI */ mpu->playbuf[mpu->state.channel].vlength++; posd=mpu->playbuf[mpu->state.channel].vlength; - if (posd==1) switch (val&0xf0) { + if (posd == 1) switch (val&0xf0) { case 0xf0: /* System message or mark */ - if (val>0xf7) { - mpu->playbuf[mpu->state.channel].type=T_MARK; - mpu->playbuf[mpu->state.channel].sys_val=val; - length=1; + if (val > 0xf7) { + mpu->playbuf[mpu->state.channel].type = T_MARK; + mpu->playbuf[mpu->state.channel].sys_val = val; } else { - //LOG(LOG_MISC,LOG_ERROR)("MPU-401:Illegal message"); - mpu->playbuf[mpu->state.channel].type=T_MIDI_SYS; - mpu->playbuf[mpu->state.channel].sys_val=val; - length=1; + /* mpu401_log("MPU-401:Illegal message"); */ + mpu->playbuf[mpu->state.channel].type = T_MIDI_SYS; + mpu->playbuf[mpu->state.channel].sys_val = val; } + length = 1; break; case 0xc0: case 0xd0: /* MIDI Message */ - mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; - length=mpu->playbuf[mpu->state.channel].length=2; + mpu->playbuf[mpu->state.channel].type = T_MIDI_NORM; + length = mpu->playbuf[mpu->state.channel].length = 2; break; case 0x80: case 0x90: case 0xa0: case 0xb0: case 0xe0: - mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; - length=mpu->playbuf[mpu->state.channel].length=3; + mpu->playbuf[mpu->state.channel].type = T_MIDI_NORM; + length = mpu->playbuf[mpu->state.channel].length = 3; break; default: /* MIDI data with running status */ posd++; mpu->playbuf[mpu->state.channel].vlength++; - mpu->playbuf[mpu->state.channel].type=T_MIDI_NORM; - length=mpu->playbuf[mpu->state.channel].length; + mpu->playbuf[mpu->state.channel].type = T_MIDI_NORM; + length = mpu->playbuf[mpu->state.channel].length; break; } - if (!(posd==1 && val>=0xf0)) - mpu->playbuf[mpu->state.channel].value[posd-1]=val; - if (posd==length) MPU401_EOIHandlerDispatch(mpu); + if (!((posd == 1) && (val >= 0xf0))) + mpu->playbuf[mpu->state.channel].value[posd-1] = val; + if (posd == length) + MPU401_EOIHandlerDispatch(mpu); } } @@ -596,13 +613,13 @@ MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) val=mpu->playbuf[chan].sys_val; if (val==0xfc) { midi_write(val); - mpu->state.amask&=~(1<state.req_mask&=~(1<state.amask &= ~(1<state.req_mask &= ~(1<playbuf[chan].vlength;i++) + for (i = 0; i < mpu->playbuf[chan].vlength; i++) midi_write(mpu->playbuf[chan].value[i]); break; @@ -618,13 +635,13 @@ UpdateTrack(mpu_t *mpu, uint8_t chan) MPU401_IntelligentOut(mpu, chan); if (mpu->state.amask&(1<playbuf[chan].vlength=0; - mpu->playbuf[chan].type=T_OVERFLOW; - mpu->playbuf[chan].counter=0xf0; - mpu->state.req_mask|=(1<playbuf[chan].vlength = 0; + mpu->playbuf[chan].type = T_OVERFLOW; + mpu->playbuf[chan].counter = 0xf0; + mpu->state.req_mask |= (1 << chan); } else { - if (mpu->state.amask==0 && !mpu->state.conductor) - mpu->state.req_mask|=(1<<12); + if ((mpu->state.amask == 0) && !mpu->state.conductor) + mpu->state.req_mask |= (1 << 12); } } @@ -632,22 +649,22 @@ UpdateTrack(mpu_t *mpu, uint8_t chan) 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); + 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); + mpu->condbuf.vlength = 0; + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); } -//Updates counters and requests new data on "End of Input" +/* Updates counters and requests new data on "End of Input" */ static void MPU401_EOIHandler(void *priv) { @@ -657,25 +674,26 @@ MPU401_EOIHandler(void *priv) mpu401_log("MPU-401 end of input callback\n"); mpu401_eoi_callback = 0LL; - mpu->state.eoi_scheduled=0; + mpu->state.eoi_scheduled = 0; if (mpu->state.send_now) { - mpu->state.send_now=0; + mpu->state.send_now = 0; if (mpu->state.cond_req) UpdateConductor(mpu); else UpdateTrack(mpu, mpu->state.channel); } - mpu->state.irq_pending=0; + mpu->state.irq_pending = 0; - if (!mpu->state.playing || !mpu->state.req_mask) return; + if (!mpu->state.playing || !mpu->state.req_mask) + return; - i=0; + i = 0; do { - if (mpu->state.req_mask&(1<state.req_mask&=~(1<state.req_mask & (1 << i)) { + QueueByte(mpu, 0xf0 + i); + mpu->state.req_mask &= ~(1 << i); break; } - } while ((i++)<16); + } while ((i++) < 16); } @@ -686,7 +704,7 @@ MPU401_EOIHandlerDispatch(void *priv) mpu401_log("EOI handler dispatch\n"); if (mpu->state.send_now) { - mpu->state.eoi_scheduled=1; + mpu->state.eoi_scheduled = 1; mpu401_eoi_callback = 60LL * TIMER_USEC; /* Possible a bit longer */ } else if (!mpu->state.eoi_scheduled) MPU401_EOIHandler(mpu); @@ -707,36 +725,41 @@ MPU401_ReadData(mpu_t *mpu) 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--; + if (mpu->queue_pos >= MPU401_QUEUE) + mpu->queue_pos -= MPU401_QUEUE; + ret = mpu->queue[mpu->queue_pos]; + mpu->queue_pos++; + mpu->queue_used--; } - if (!mpu->intelligent) return ret; + /* Shouldn't this check mpu->mode? */ + if (mpu->mode == M_UART) + return ret; - if (mpu->queue_used == 0) picintc(1 << mpu->irq); + if (mpu->queue_used == 0) + picintc(1 << mpu->irq); - if (ret>=0xf0 && ret<=0xf7) { + if ((ret >= 0xf0) && (ret <= 0xf7)) { /* MIDI data request */ - mpu->state.channel=ret&7; - mpu->state.data_onoff=0; - mpu->state.cond_req=0; + mpu->state.channel = ret & 7; + mpu->state.data_onoff = 0; + mpu->state.cond_req = 0; } - 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; + 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; + mpu->condbuf.type = T_OVERFLOW; } - if (ret==MSG_MPU_END || ret==MSG_MPU_CLOCK || ret==MSG_MPU_ACK) { - mpu->state.data_onoff=-1; + if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK)) { + mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); } @@ -771,12 +794,12 @@ mpu401_read(uint16_t addr, void *priv) uint8_t ret = 0; switch (addr & 1) { - case 0: //Read Data + case 0: /* Read Data */ ret = MPU401_ReadData(mpu); mpu401_log("Read Data (0x330) %X\n", ret); break; - case 1: //Read Status + 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; @@ -799,44 +822,43 @@ MPU401_Event(void *priv) mpu401_log("MPU-401 event callback\n"); - if (mpu->mode==M_UART) { + if (mpu->mode == M_UART) { mpu401_event_callback = 0LL; return; } if (mpu->state.irq_pending) goto next_event; - for (i=0;i<8;i++) { /* Decrease counters */ - if (mpu->state.amask&(1<state.amask & (1 << i)) { mpu->playbuf[i].counter--; - if (mpu->playbuf[i].counter<=0) UpdateTrack(mpu, i); + if (mpu->playbuf[i].counter <= 0) UpdateTrack(mpu, i); } } if (mpu->state.conductor) { mpu->condbuf.counter--; - if (mpu->condbuf.counter<=0) UpdateConductor(mpu); + if (mpu->condbuf.counter <= 0) UpdateConductor(mpu); } if (mpu->clock.clock_to_host) { mpu->clock.cth_counter++; if (mpu->clock.cth_counter >= mpu->clock.cth_rate) { - mpu->clock.cth_counter=0; - mpu->state.req_mask|=(1<<13); + mpu->clock.cth_counter = 0; + mpu->state.req_mask |= (1 << 13); } } if (!mpu->state.irq_pending && mpu->state.req_mask) - MPU401_EOIHandler(mpu); + MPU401_EOIHandler(mpu); next_event: - /* mpu401_event_callback = 0LL; */ - new_time = ((mpu->clock.tempo * mpu->clock.timebase * mpu->clock.tempo_rel)/0x40); + new_time = ((mpu->clock.tempo * mpu->clock.timebase * mpu->clock.tempo_rel) / 0x40); if (new_time == 0) { mpu401_event_callback = 0LL; return; } else { - mpu401_event_callback += (MPU401_TIMECONSTANT/new_time) * 1000LL * TIMER_USEC; + mpu401_event_callback += (MPU401_TIMECONSTANT / new_time) * 1000LL * TIMER_USEC; mpu401_log("Next event after %i us (time constant: %i)\n", (int) ((MPU401_TIMECONSTANT/new_time) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); } } @@ -851,6 +873,10 @@ mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) mpu->queue_pos = 0; mpu->mode = M_UART; + /* Expalantion: + MPU-401 starting in intelligent mode = Full MPU-401 intelligent mode capability; + MPU-401 starting in UART mode = Reduced MPU-401 intelligent mode capability seen on the Sound Blaster 16/AWE32, + only supporting commands 3F (set UART mode) and FF (reset). */ mpu->intelligent = (mode == M_INTELLIGENT) ? 1 : 0; mpu401_log("Starting as %s (mode is %s)\n", mpu->intelligent ? "INTELLIGENT" : "UART", (mode == M_INTELLIGENT) ? "INTELLIGENT" : "UART"); @@ -858,8 +884,9 @@ mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) mpu401_eoi_callback = 0LL; mpu401_reset_callback = 0LL; - io_sethandler(addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + if (addr) + io_sethandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); io_sethandler(0x2A20, 16, NULL, NULL, NULL, imf_write, NULL, NULL, mpu); timer_add(MPU401_Event, &mpu401_event_callback, &mpu401_event_callback, mpu); @@ -878,52 +905,55 @@ mpu401_device_add(void) if (!mpu401_standalone_enable) return; n = sound_card_get_internal_name(sound_card_current); - if (n != NULL) - { - if (!strcmp(n, "ncraudio")) - mca_version = 1; - else - mca_version = 0; - - if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32") || !strcmp(n, "replysb16")) return; + if (n != NULL) { + if (!strcmp(n, "ncraudio")) + mca_version = 1; + else + mca_version = 0; + + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32") || !strcmp(n, "replysb16")) return; } if (mca_version) - device_add(&mpu401_mca_device); - else - device_add(&mpu401_device); + device_add(&mpu401_mca_device); + else + device_add(&mpu401_device); } -static uint8_t mpu401_mca_read(int port, void *p) -{ - mpu_t *mpu = (mpu_t *)p; - - return mpu->pos_regs[port & 7]; -} -static void mpu401_mca_write(int port, uint8_t val, void *p) +static uint8_t +mpu401_mca_read(int port, void *p) { mpu_t *mpu = (mpu_t *)p; - uint16_t addr; - - if (port < 0x102) - return; - - addr = (mpu->pos_regs[2] & 2) ? 0x0330 : 0x1330; - - io_removehandler(addr, 2, - mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); - io_removehandler(0x2A20, 16, - NULL, NULL, NULL, imf_write, NULL, NULL, mpu); - - mpu->pos_regs[port & 7] = val; - - if (mpu->pos_regs[2] & 1) - { - addr = (mpu->pos_regs[2] & 2) ? 0x0330 : 0x1330; - - mpu401_init(mpu, addr, device_get_config_int("irq"), device_get_config_int("mode")); - } + + return mpu->pos_regs[port & 7]; +} + + +static void +mpu401_mca_write(int port, uint8_t val, void *p) +{ + mpu_t *mpu = (mpu_t *)p; + uint16_t addr; + + if (port < 0x102) + return; + + addr = (mpu->pos_regs[2] & 2) ? 0x0330 : 0x1330; + + port &= 7; + + mpu->pos_regs[port] = val; + + if (port == 2) { + io_removehandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + + addr = (mpu->pos_regs[2] & 2) ? 0x1330 : 0x0330; + + io_sethandler(addr, 2, + mpu401_read, NULL, NULL, mpu401_write, NULL, NULL, mpu); + } } @@ -931,22 +961,28 @@ static void * mpu401_standalone_init(const device_t *info) { mpu_t *mpu; + int irq; + uint16_t base; mpu = malloc(sizeof(mpu_t)); memset(mpu, 0, sizeof(mpu_t)); mpu401_log("mpu_init\n"); - - if (info->flags & DEVICE_MCA) - { - mca_add(mpu401_mca_read, mpu401_mca_write, mpu); - mpu->pos_regs[0] = 0x0F; - mpu->pos_regs[1] = 0x6C; - } - else - mpu401_init(mpu, device_get_config_hex16("base"), device_get_config_int("irq"), device_get_config_int("mode")); - return(mpu); + if (info->flags & DEVICE_MCA) { + mca_add(mpu401_mca_read, mpu401_mca_write, mpu); + mpu->pos_regs[0] = 0x0F; + mpu->pos_regs[1] = 0x6C; + base = 0; /* Tell mpu401_init() that this is the MCA variant. */ + irq = 2; /* According to @6c0f.adf, the IRQ is fixed to 2. */ + } else { + base = device_get_config_hex16("base"); + irq = device_get_config_int("irq"); + } + + mpu401_init(mpu, base, irq, M_INTELLIGENT); + + return(mpu); } @@ -1001,73 +1037,12 @@ static const device_config_t mpu401_standalone_config[] = } } }, - { - "mode", "Mode", CONFIG_SELECTION, "", 1, - { - { - "UART", M_UART - }, - { - "Intelligent", M_INTELLIGENT - }, - { - "" - } - } - }, { "", "", -1 } }; -static const device_config_t mpu401_mca_standalone_config[] = -{ - { - "irq", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, - { - { - "IRQ 9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, - { - "mode", "Mode", CONFIG_SELECTION, "", 1, - { - { - "UART", M_UART - }, - { - "Intelligent", M_INTELLIGENT - }, - { - "" - } - } - }, - { - "", "", -1 - } -}; - const device_t mpu401_device = { "MPU-401 (Standalone)", DEVICE_ISA, 0, @@ -1079,11 +1054,11 @@ const device_t mpu401_device = { }; const device_t mpu401_mca_device = { - "MPU-401 MCA (Standalone)", + "Roland MPU-IMC", DEVICE_MCA, 0, mpu401_standalone_init, mpu401_standalone_close, NULL, NULL, NULL, NULL, - mpu401_mca_standalone_config + NULL }; diff --git a/src/sound/snd_mpu401.h b/src/sound/snd_mpu401.h index 835594db4..d7f8be21b 100644 --- a/src/sound/snd_mpu401.h +++ b/src/sound/snd_mpu401.h @@ -8,7 +8,7 @@ * * Roland MPU-401 emulation. * - * Version: @(#)sound_mpu401.h 1.0.1 2018/03/18 + * Version: @(#)sound_mpu401.h 1.0.2 2018/09/16 * * Author: Sarah Walker, * DOSBox Team, @@ -26,8 +26,22 @@ #define MPU401_TIMECONSTANT (60000000/1000.0f) #define MPU401_RESETBUSY 27.0f -typedef enum MpuMode { M_UART,M_INTELLIGENT } MpuMode; -typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} MpuDataType; +typedef enum MpuMode +{ + M_UART, + M_INTELLIGENT +} MpuMode; + +#define M_MCA 0x10 + +typedef enum MpuDataType +{ + T_OVERFLOW, + T_MARK, + T_MIDI_SYS, + T_MIDI_NORM, + T_COMMAND +} MpuDataType; /* Messages sent to MPU-401 from host */ #define MSG_EOX 0xf7 @@ -43,55 +57,50 @@ typedef enum MpuDataType {T_OVERFLOW,T_MARK,T_MIDI_SYS,T_MIDI_NORM,T_COMMAND} Mp typedef struct mpu_t { - int uart_mode; - uint8_t rx_data; - int intelligent; - MpuMode mode; - int irq; - uint8_t status; - uint8_t queue[MPU401_QUEUE]; - int queue_pos,queue_used; - struct track - { - int counter; - uint8_t value[8],sys_val; - uint8_t vlength,length; - MpuDataType type; - } playbuf[8],condbuf; - struct { - int conductor,cond_req,cond_set, block_ack; - int playing,reset; - int wsd,wsm,wsd_start; - int run_irq,irq_pending; - int send_now; - int eoi_scheduled; - int data_onoff; - uint32_t command_byte,cmd_pending; - uint8_t tmask,cmask,amask; - uint16_t midi_mask; - uint16_t req_mask; - uint8_t channel,old_chan; - } state; - struct { - uint8_t timebase,old_timebase; - uint8_t tempo,old_tempo; - uint8_t tempo_rel,old_tempo_rel; - uint8_t tempo_grad; - uint8_t cth_rate,cth_counter; - int clock_to_host,cth_active; - } clock; - - uint8_t pos_regs[8]; + int uart_mode, intelligent, + irq, + queue_pos, queue_used; + uint8_t rx_data, is_mca, + status, + queue[MPU401_QUEUE], pos_regs[8]; + MpuMode mode; + struct track + { + int counter; + uint8_t value[8], sys_val, + vlength,length; + MpuDataType type; + } playbuf[8], condbuf; + struct { + int conductor, cond_req, + cond_set, block_ack, + playing, reset, + wsd, wsm, wsd_start, + run_irq, irq_pending, + send_now, eoi_scheduled, + data_onoff; + uint8_t tmask, cmask, + amask, + channel, old_chan; + uint16_t midi_mask, req_mask; + uint32_t command_byte, cmd_pending; + } state; + struct { + uint8_t timebase, old_timebase, + tempo, old_tempo, + tempo_rel, old_tempo_rel, + tempo_grad, + cth_rate, cth_counter; + int clock_to_host,cth_active; + } clock; } mpu_t; -uint8_t MPU401_ReadData(mpu_t *mpu); +extern int mca_version; +extern int mpu401_standalone_enable; +extern const device_t mpu401_device; +extern const device_t mpu401_mca_device; -void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); - -extern int mca_version; -extern int mpu401_standalone_enable; - -void mpu401_device_add(void); -const device_t mpu401_device; -const device_t mpu401_mca_device; +extern uint8_t MPU401_ReadData(mpu_t *mpu); +extern void mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode); +extern void mpu401_device_add(void); diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index af3a013d3..1e8d9d268 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -8,7 +8,7 @@ * * Sound Blaster emulation. * - * Version: @(#)sound_sb.c 1.0.10 2018/09/04 + * Version: @(#)sound_sb.c 1.0.11 2018/09/11 * * Authors: Sarah Walker, * Miran Grca, @@ -1272,7 +1272,6 @@ void *sb_pro_mcv_init() void *sb_16_init() { - int mpu_irq; sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); memset(sb, 0, sizeof(sb_t)); @@ -1296,10 +1295,7 @@ void *sb_16_init() #if 0 sound_add_process_handler(sb_process_buffer_sb16, sb); #endif - mpu_irq = device_get_config_int("irq401"); - if (mpu_irq == 255) - mpu_irq = device_get_config_int("irq"); - mpu401_init(&sb->mpu, device_get_config_hex16("base401"), mpu_irq, device_get_config_int("mode401")); + mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART); sb_dsp_set_mpu(&sb->mpu); #if 0 memcpy(&sb->temp_mixer_sb16, &sb->mixer_sb16, sizeof(sb_ct1745_mixer_t)); @@ -1315,7 +1311,6 @@ int sb_awe32_available() void *sb_awe32_init() { - int mpu_irq; sb_t *sb = malloc(sizeof(sb_t)); uint16_t addr = device_get_config_hex16("base"); uint16_t emu_addr = device_get_config_hex16("emu_base"); @@ -1344,10 +1339,7 @@ void *sb_awe32_init() #if 0 sound_add_process_handler(sb_process_buffer_sb16, sb); #endif - mpu_irq = device_get_config_int("irq401"); - if (mpu_irq == 255) - mpu_irq = device_get_config_int("irq"); - mpu401_init(&sb->mpu, device_get_config_hex16("base401"), mpu_irq, device_get_config_int("mode401")); + mpu401_init(&sb->mpu, device_get_config_hex16("base401"), device_get_config_int("irq"), M_UART); sb_dsp_set_mpu(&sb->mpu); emu8k_init(&sb->emu8k, emu_addr, onboard_ram); #if 0 @@ -1606,35 +1598,6 @@ static const device_config_t sb_16_config[] = } } }, - { - "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, - { - { - "Use main IRQ", 255 - }, - { - "IRQ 9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, { "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, { @@ -1669,20 +1632,6 @@ static const device_config_t sb_16_config[] = } } }, - { - "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, - { - { - "UART", M_UART - }, - { - "Intelligent", M_INTELLIGENT - }, - { - "" - } - } - }, { "opl", "Enable OPL", CONFIG_BINARY, "", 1 }, @@ -1767,35 +1716,6 @@ static const device_config_t sb_awe32_config[] = } } }, - { - "irq401", "MPU-401 IRQ", CONFIG_SELECTION, "", 9, - { - { - "Use main IRQ", 255 - }, - { - "IRQ 9", 9 - }, - { - "IRQ 3", 3 - }, - { - "IRQ 4", 4 - }, - { - "IRQ 5", 5 - }, - { - "IRQ 7", 7 - }, - { - "IRQ 10", 10 - }, - { - "" - } - } - }, { "dma", "Low DMA channel", CONFIG_SELECTION, "", 1, { @@ -1830,20 +1750,6 @@ static const device_config_t sb_awe32_config[] = } } }, - { - "mode401", "MPU-401 mode", CONFIG_SELECTION, "", 1, - { - { - "UART", M_UART - }, - { - "Intelligent", M_INTELLIGENT - }, - { - "" - } - } - }, { "onboard_ram", "Onboard RAM", CONFIG_SELECTION, "", 512, { diff --git a/src/sound/sound.c b/src/sound/sound.c index 53ada44d7..035f01665 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -8,7 +8,7 @@ * * Sound emulation core. * - * Version: @(#)sound.c 1.0.18 2018/08/11 + * Version: @(#)sound.c 1.0.19 2018/09/11 * * Authors: Sarah Walker, * Miran Grca, @@ -85,27 +85,27 @@ static volatile int cdaudioon = 0; static const SOUND_CARD sound_cards[] = { - { "None", "none", NULL }, - { "[ISA] Adlib", "adlib", &adlib_device }, - { "[ISA] Adlib Gold", "adlibgold",&adgold_device }, - { "[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, - { "[ISA] Sound Blaster 1.5", "sb1.5", &sb_15_device }, - { "[ISA] Sound Blaster 2.0", "sb2.0", &sb_2_device }, - { "[ISA] Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device }, - { "[ISA] Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device }, - { "[ISA] Sound Blaster 16", "sb16", &sb_16_device }, - { "[ISA] Sound Blaster AWE32", "sbawe32", &sb_awe32_device }, + { "None", "none", NULL }, + { "[ISA] Adlib", "adlib", &adlib_device }, + { "[ISA] Adlib Gold", "adlibgold", &adgold_device }, + { "[ISA] Sound Blaster 1.0", "sb", &sb_1_device }, + { "[ISA] Sound Blaster 1.5", "sb1.5", &sb_15_device }, + { "[ISA] Sound Blaster 2.0", "sb2.0", &sb_2_device }, + { "[ISA] Sound Blaster Pro v1", "sbprov1", &sb_pro_v1_device }, + { "[ISA] Sound Blaster Pro v2", "sbprov2", &sb_pro_v2_device }, + { "[ISA] Sound Blaster 16", "sb16", &sb_16_device }, + { "[ISA] Sound Blaster AWE32", "sbawe32", &sb_awe32_device }, #if defined(DEV_BRANCH) && defined(USE_PAS16) - { "[ISA] Pro Audio Spectrum 16","pas16", &pas16_device }, + { "[ISA] Pro Audio Spectrum 16", "pas16", &pas16_device }, #endif - { "[ISA] Windows Sound System", "wss", &wss_device }, - { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, - { "[MCA] NCR Business Audio","ncraudio", &ncr_business_audio_device }, - { "[MCA] Sound Blaster MCV", "sbmcv", &sb_mcv_device }, - { "[MCA] Sound Blaster Pro MCV","sbpromcv", &sb_pro_mcv_device }, - { "[PCI] Ensoniq AudioPCI (ES1371)","es1371", &es1371_device}, - { "[PCI] Sound Blaster PCI 128", "sbpci128", &es1371_device}, - { "", "", NULL } + { "[ISA] Windows Sound System", "wss", &wss_device }, + { "[MCA] Adlib", "adlib_mca", &adlib_mca_device }, + { "[MCA] NCR Business Audio", "ncraudio", &ncr_business_audio_device }, + { "[MCA] Sound Blaster MCV", "sbmcv", &sb_mcv_device }, + { "[MCA] Sound Blaster Pro MCV", "sbpromcv", &sb_pro_mcv_device }, + { "[PCI] Ensoniq AudioPCI (ES1371)", "es1371", &es1371_device }, + { "[PCI] Sound Blaster PCI 128", "sbpci128", &es1371_device }, + { "", "", NULL } }; diff --git a/src/win/win_midi.c b/src/win/win_midi.c index 6df91ca5d..706db3acb 100644 --- a/src/win/win_midi.c +++ b/src/win/win_midi.c @@ -11,117 +11,127 @@ #include "../plat_midi.h" -int midi_id = 0; -HANDLE m_event; - -static HMIDIOUT midi_out_device = NULL; -static uint8_t midi_rt_buf[1024]; -static uint8_t midi_cmd_buf[1024]; -static int midi_cmd_pos = 0; -static int midi_cmd_len = 0; -static uint8_t midi_status = 0; -static unsigned int midi_sysex_start = 0; -static unsigned int midi_sysex_delay = 0; - -void plat_midi_init() +typedef struct { - /* This is for compatibility with old configuration files. */ - midi_id = config_get_int("Sound", "midi_host_device", -1); - if (midi_id == -1) - { - midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); - } - else - { - config_delete_var("Sound", "midi_host_device"); - config_set_int(SYSTEM_MIDI_NAME, "midi", midi_id); - } + int midi_id; - MMRESULT hr = MMSYSERR_NOERROR; + HANDLE m_event; - memset(midi_rt_buf, 0, sizeof(midi_rt_buf)); - memset(midi_cmd_buf, 0, sizeof(midi_cmd_buf)); + HMIDIOUT midi_out_device; - midi_cmd_pos = midi_cmd_len = 0; - midi_status = 0; + MIDIHDR m_hdr; +} plat_midi_t; - midi_sysex_start = midi_sysex_delay = 0; +plat_midi_t *pm = NULL; - m_event = CreateEvent(NULL, TRUE, TRUE, NULL); - hr = midiOutOpen(&midi_out_device, midi_id, (uintptr_t) m_event, - 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n",hr); - midi_id = 0; - hr = midiOutOpen(&midi_out_device, midi_id, (uintptr_t) m_event, - 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n",hr); - return; - } - } - - midiOutReset(midi_out_device); -} - -void plat_midi_close() +void +plat_midi_init(void) { - if (midi_out_device != NULL) - { - midiOutReset(midi_out_device); - midiOutClose(midi_out_device); - /* midi_out_device = NULL; */ - CloseHandle(m_event); - } -} + MMRESULT hr; -int plat_midi_get_num_devs() -{ - return midiOutGetNumDevs(); -} -void plat_midi_get_dev_name(int num, char *s) -{ - MIDIOUTCAPS caps; + pm = (plat_midi_t *) malloc(sizeof(plat_midi_t)); + memset(pm, 0, sizeof(plat_midi_t)); - midiOutGetDevCaps(num, &caps, sizeof(caps)); - strcpy(s, caps.szPname); -} + pm->midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); -void plat_midi_play_msg(uint8_t *msg) -{ - midiOutShortMsg(midi_out_device, *(uint32_t *) msg); -} + hr = MMSYSERR_NOERROR; -MIDIHDR m_hdr; + pm->m_event = CreateEvent(NULL, TRUE, TRUE, NULL); -void plat_midi_play_sysex(uint8_t *sysex, unsigned int len) -{ - MMRESULT result; - - if (WaitForSingleObject(m_event, 2000) == WAIT_TIMEOUT) - return; - - midiOutUnprepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); - - m_hdr.lpData = (char *) sysex; - m_hdr.dwBufferLength = len; - m_hdr.dwBytesRecorded = len; - m_hdr.dwUser = 0; - - result = midiOutPrepareHeader(midi_out_device, &m_hdr, sizeof(m_hdr)); - - if (result != MMSYSERR_NOERROR) return; - ResetEvent(m_event); - result = midiOutLongMsg(midi_out_device, &m_hdr, sizeof(m_hdr)); - if (result != MMSYSERR_NOERROR) - { - SetEvent(m_event); + hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, + (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n", hr); + pm->midi_id = 0; + hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, + (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n", hr); return; } + } + + midiOutReset(pm->midi_out_device); } -int plat_midi_write(uint8_t val) + +void +plat_midi_close(void) { - return 0; + if (pm) { + if (pm->midi_out_device != NULL) { + midiOutReset(pm->midi_out_device); + midiOutClose(pm->midi_out_device); + CloseHandle(pm->m_event); + } + + free(pm); + pm = NULL; + } +} + + +int +plat_midi_get_num_devs(void) +{ + return midiOutGetNumDevs(); +} + + +void +plat_midi_get_dev_name(int num, char *s) +{ + MIDIOUTCAPS caps; + + midiOutGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} + + +void +plat_midi_play_msg(uint8_t *msg) +{ + if (!pm) + return; + + midiOutShortMsg(pm->midi_out_device, *(uint32_t *) msg); +} + + +void +plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +{ + MMRESULT result; + + if (!pm) + return; + + if (WaitForSingleObject(pm->m_event, 2000) == WAIT_TIMEOUT) + return; + + midiOutUnprepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); + + pm->m_hdr.lpData = (char *) sysex; + pm->m_hdr.dwBufferLength = len; + pm->m_hdr.dwBytesRecorded = len; + pm->m_hdr.dwUser = 0; + + result = midiOutPrepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); + + if (result != MMSYSERR_NOERROR) + return; + ResetEvent(pm->m_event); + result = midiOutLongMsg(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); + if (result != MMSYSERR_NOERROR) { + SetEvent(pm->m_event); + return; + } +} + + +int +plat_midi_write(uint8_t val) +{ + return 0; } diff --git a/src/win/win_settings.c b/src/win/win_settings.c index fcdf27d09..8b536bf56 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -8,7 +8,7 @@ * * Windows 86Box Settings dialog handler. * - * Version: @(#)win_settings.c 1.0.57 2018/09/06 + * Version: @(#)win_settings.c 1.0.58 2018/09/11 * * Authors: Miran Grca, * David Hrdlička, @@ -1092,13 +1092,15 @@ win_settings_input_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) static int mpu401_present(void) { +#if 0 char *n; n = sound_card_get_internal_name(temp_sound_card); if (n != NULL) { - if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32") || !strcmp(n, "replysb16")) + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) return 1; } +#endif return temp_mpu401 ? 1 : 0; } @@ -1107,14 +1109,22 @@ mpu401_present(void) int mpu401_standalone_allow(void) { +#if 0 char *n, *md; +#else + char *md; +#endif +#if 0 n = sound_card_get_internal_name(temp_sound_card); +#endif md = midi_device_get_internal_name(temp_midi_device); +#if 0 if (n != NULL) { - if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32") || !strcmp(n, "replysb16")) + if (!strcmp(n, "sb16") || !strcmp(n, "sbawe32")) return 0; } +#endif if (md != NULL) { if (!strcmp(md, "none")) @@ -1294,22 +1304,10 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; case IDC_CONFIGURE_MPU401: - { - char *n; - - n = sound_card_get_internal_name(sound_card_current); - - if (n != NULL) - { - if (!strcmp(n, "ncraudio")) - mca_version = 1; - else - mca_version = 0; - } + mca_version = !!(machines[temp_machine].flags & MACHINE_MCA); temp_deviceconfig |= deviceconfig_open(hdlg, mca_version ? (void *)&mpu401_mca_device : (void *)&mpu401_device); - } - break; + break; } return FALSE;