From 9562a20a6365aa2e7f99309398aa20116386d7f3 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 1 Jan 2020 20:20:16 +0100 Subject: [PATCH 01/10] Initial commit of MIDI IN. --- src/config.c | 11 + src/device.h | 1 + src/plat_midi.h | 6 + src/sound/midi.c | 173 +++++- src/sound/midi.h | 40 +- src/sound/midi_input.h | 1 + src/sound/midi_system.c | 78 +++ src/sound/snd_audiopci.c | 120 +++- src/sound/snd_mpu401.c | 1173 ++++++++++++++++++++++++++++++-------- src/sound/snd_mpu401.h | 64 ++- src/sound/snd_sb.c | 47 ++ src/sound/snd_sb_dsp.c | 98 +++- src/sound/snd_sb_dsp.h | 18 +- src/sound/sound.c | 2 +- src/win/86Box.rc | 33 +- src/win/resource.h | 15 +- src/win/win_devconf.c | 34 ++ src/win/win_midi.c | 125 +++- src/win/win_settings.c | 72 ++- 19 files changed, 1752 insertions(+), 359 deletions(-) create mode 100644 src/sound/midi_input.h diff --git a/src/config.c b/src/config.c index 583605583..2b9026989 100644 --- a/src/config.c +++ b/src/config.c @@ -649,6 +649,12 @@ load_sound(void) else midi_device_current = 0; + p = config_get_string(cat, "midi_in_device", NULL); + if (p != NULL) + midi_input_device_current = midi_in_device_get_from_internal_name(p); + else + midi_input_device_current = 0; + mpu401_standalone_enable = !!config_get_int(cat, "mpu401_standalone", 0); SSI2001 = !!config_get_int(cat, "ssi2001", 0); @@ -1531,6 +1537,11 @@ save_sound(void) else config_set_string(cat, "midi_device", midi_device_get_internal_name(midi_device_current)); + if (!strcmp(midi_in_device_get_internal_name(midi_input_device_current), "none")) + config_delete_var(cat, "midi_in_device"); + else + config_set_string(cat, "midi_in_device", midi_in_device_get_internal_name(midi_input_device_current)); + if (mpu401_standalone_enable == 0) config_delete_var(cat, "mpu401_standalone"); else diff --git a/src/device.h b/src/device.h index e59952205..dbf9976a2 100644 --- a/src/device.h +++ b/src/device.h @@ -50,6 +50,7 @@ #define CONFIG_HEX16 7 #define CONFIG_HEX20 8 #define CONFIG_MAC 9 +#define CONFIG_MIDI_IN 10 enum { diff --git a/src/plat_midi.h b/src/plat_midi.h index 5070de68a..933e49ee6 100644 --- a/src/plat_midi.h +++ b/src/plat_midi.h @@ -7,3 +7,9 @@ extern int plat_midi_write(uint8_t val); extern int plat_midi_get_num_devs(void); extern void plat_midi_get_dev_name(int num, char *s); + +extern void plat_midi_input_init(void); +extern void plat_midi_input_close(void); + +extern int plat_midi_in_get_num_devs(void); +extern void plat_midi_in_get_dev_name(int num, char *s); diff --git a/src/sound/midi.c b/src/sound/midi.c index 1f5f0ed47..7648c8c92 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -8,7 +8,7 @@ * * MIDI device core module. * - * Version: @(#)midi.c 1.0.1 2018/10/10 + * Version: @(#)midi.c 1.0.2 2018/12/31 * * Authors: Sarah Walker, * Miran Grca, @@ -37,28 +37,22 @@ #ifdef USE_MUNT # include "midi_mt32.h" #endif +#include "midi_input.h" -#define SYSEX_SIZE 1024 -#define RAWBUF 1024 - int midi_device_current = 0; static int midi_device_last = 0; +int midi_input_device_current = 0; +static int midi_input_device_last = 0; +midi_t *midi = NULL; -typedef struct -{ - 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; +void (*input_msg)(uint8_t *msg); +int (*input_sysex)(uint8_t *buffer, uint32_t len, int abort); -static midi_t *midi = NULL; +uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; -static uint8_t MIDI_evt_len[256] = { +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 */ @@ -85,7 +79,7 @@ typedef struct { const char *name, *internal_name; const device_t *device; -} MIDI_DEVICE; +} MIDI_DEVICE, MIDI_IN_DEVICE; static const MIDI_DEVICE devices[] = { @@ -101,6 +95,12 @@ static const MIDI_DEVICE devices[] = {"", "", NULL} }; +static const MIDI_IN_DEVICE midi_in_devices[] = +{ + {"None", "none", NULL}, + {MIDI_INPUT_NAME, MIDI_INPUT_INTERNAL_NAME, &midi_input_device}, + {"", "", NULL} +}; int midi_device_available(int card) @@ -172,16 +172,39 @@ midi_init(midi_device_t* device) midi = (midi_t *) malloc(sizeof(midi_t)); memset(midi, 0, sizeof(midi_t)); - midi->m_device = device; + midi->m_out_device = device; +} + +void +midi_in_init(midi_device_t* device, midi_t **mididev) +{ + *mididev = (midi_t *)malloc(sizeof(midi_t)); + memset(*mididev, 0, sizeof(midi_t)); + + (*mididev)->m_in_device = device; } void midi_close(void) { - if (midi && midi->m_device) { - free(midi->m_device); - midi->m_device = NULL; + if (midi && midi->m_out_device) { + free(midi->m_out_device); + midi->m_out_device = NULL; + } + + if (midi) { + free(midi); + midi = NULL; + } +} + +void +midi_in_close(void) +{ + if (midi && midi->m_in_device) { + free(midi->m_in_device); + midi->m_in_device = NULL; } if (midi) { @@ -194,36 +217,119 @@ midi_close(void) void midi_poll(void) { - if (midi && midi->m_device && midi->m_device->poll) - midi->m_device->poll(); + if (midi && midi->m_out_device && midi->m_out_device->poll) + midi->m_out_device->poll(); } void play_msg(uint8_t *msg) { - if (midi->m_device->play_msg) - midi->m_device->play_msg(msg); + if (midi->m_out_device->play_msg) + midi->m_out_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); + if (midi->m_out_device->play_sysex) + midi->m_out_device->play_sysex(sysex, len); } +int +midi_in_device_available(int card) +{ + if (midi_in_devices[card].device) + return device_available(midi_in_devices[card].device); + + return 1; +} + +char * +midi_in_device_getname(int card) +{ + return (char *) midi_in_devices[card].name; +} + +const device_t * +midi_in_device_getdevice(int card) +{ + return midi_in_devices[card].device; +} + +int +midi_in_device_has_config(int card) +{ + if (!midi_in_devices[card].device) + return 0; + return midi_in_devices[card].device->config ? 1 : 0; +} + + +char * +midi_in_device_get_internal_name(int card) +{ + return (char *) midi_in_devices[card].internal_name; +} + + +int +midi_in_device_get_from_internal_name(char *s) +{ + int c = 0; + + while (strlen(midi_in_devices[c].internal_name)) { + if (!strcmp(midi_in_devices[c].internal_name, s)) + return c; + c++; + } + + return 0; +} + void -midi_write(uint8_t val) +midi_in_device_init() +{ + if (midi_in_devices[midi_input_device_current].device) + device_add(midi_in_devices[midi_input_device_current].device); + midi_input_device_last = midi_input_device_current; +} + +void +midi_raw_out_rt_byte(uint8_t val) +{ + if (!midi || !midi->m_out_device || !midi->m_in_device) + return; + + if (!midi->midi_realtime) + return; + + if ((!midi->midi_clockout && (val == 0xf8))) + return; + + midi->midi_cmd_r = val << 24; + pclog("Play RT Byte msg\n"); + play_msg((uint8_t *)&midi->midi_cmd_r); +} + +void +midi_raw_out_thru_rt_byte(uint8_t val) +{ + if (midi->thruchan) + midi_raw_out_rt_byte(val); +} + +void +midi_raw_out_byte(uint8_t val) { uint32_t passed_ticks; - if (!midi || !midi->m_device) + if (!midi || !midi->m_out_device) return; - if (midi->m_device->write && midi->m_device->write(val)) + if ((midi->m_out_device->write && midi->m_out_device->write(val))) return; if (midi->midi_sysex_start) { @@ -289,3 +395,12 @@ midi_write(uint8_t val) } } } + +void +midi_clear_buffer(void) +{ + midi->midi_pos = 0; + midi->midi_status = 0x00; + midi->midi_cmd_pos = 0; + midi->midi_cmd_len = 0; +} \ No newline at end of file diff --git a/src/sound/midi.h b/src/sound/midi.h index 6268a0e0c..21441646c 100644 --- a/src/sound/midi.h +++ b/src/sound/midi.h @@ -2,18 +2,34 @@ # define EMU_SOUND_MIDI_H -extern int midi_device_current; +#define SYSEX_SIZE 8192 +extern uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; +extern uint8_t MIDI_evt_len[256]; + +extern int midi_device_current; +extern int midi_input_device_current; + +extern void (*input_msg)(uint8_t *msg); +extern int (*input_sysex)(uint8_t *buffer, uint32_t len, int abort); int midi_device_available(int card); +int midi_in_device_available(int card); char *midi_device_getname(int card); +char *midi_in_device_getname(int card); #ifdef EMU_DEVICE_H const device_t *midi_device_getdevice(int card); +const device_t *midi_in_device_getdevice(int card); #endif int midi_device_has_config(int card); +int midi_in_device_has_config(int card); char *midi_device_get_internal_name(int card); +char *midi_in_device_get_internal_name(int card); int midi_device_get_from_internal_name(char *s); +int midi_in_device_get_from_internal_name(char *s); void midi_device_init(); +void midi_in_device_init(); + typedef struct midi_device_t { @@ -23,9 +39,27 @@ typedef struct midi_device_t int (*write)(uint8_t val); } midi_device_t; +typedef struct midi_t +{ + uint8_t midi_rt_buf[8], midi_cmd_buf[8], + midi_status, midi_sysex_data[SYSEX_SIZE]; + int midi_cmd_pos, midi_cmd_len, midi_cmd_r, + midi_realtime, thruchan, midi_clockout; + unsigned int midi_sysex_start, midi_sysex_delay, + midi_pos; + midi_device_t *m_out_device, *m_in_device; +} midi_t; + +extern midi_t *midi; + void midi_init(midi_device_t* device); +void midi_in_init(midi_device_t* device, midi_t **mididev); void midi_close(); -void midi_write(uint8_t val); +void midi_in_close(void); +void midi_raw_out_rt_byte(uint8_t val); +void midi_raw_out_thru_rt_byte(uint8_t val); +void midi_raw_out_byte(uint8_t val); +void midi_clear_buffer(void); void midi_poll(); #if 0 @@ -41,5 +75,7 @@ void midi_poll(); #define SYSTEM_MIDI_INTERNAL_NAME "system_midi" #endif +#define MIDI_INPUT_NAME "MIDI Input Device" +#define MIDI_INPUT_INTERNAL_NAME "midi_in" #endif /*EMU_SOUND_MIDI_H*/ diff --git a/src/sound/midi_input.h b/src/sound/midi_input.h new file mode 100644 index 000000000..163d6fa91 --- /dev/null +++ b/src/sound/midi_input.h @@ -0,0 +1 @@ +extern const device_t midi_input_device; diff --git a/src/sound/midi_system.c b/src/sound/midi_system.c index d9a15c6a9..f3ace5c69 100644 --- a/src/sound/midi_system.c +++ b/src/sound/midi_system.c @@ -9,6 +9,7 @@ #include "../plat_midi.h" #include "midi.h" #include "midi_system.h" +#include "midi_input.h" void* system_midi_init(const device_t *info) @@ -16,6 +17,8 @@ void* system_midi_init(const device_t *info) midi_device_t* dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); + pclog("MIDI Output\n"); + dev->play_msg = plat_midi_play_msg; dev->play_sysex = plat_midi_play_sysex; dev->write = plat_midi_write; @@ -27,6 +30,24 @@ void* system_midi_init(const device_t *info) return dev; } +void* midi_input_init(const device_t *info) +{ + midi_device_t* dev = malloc(sizeof(midi_device_t)); + memset(dev, 0, sizeof(midi_device_t)); + + pclog("MIDI Input\n"); + + plat_midi_input_init(); + + midi_in_init(dev, &midi); + + midi->midi_realtime = device_get_config_int("realtime"); + midi->thruchan = device_get_config_int("thruchan"); + midi->midi_clockout = device_get_config_int("clockout"); + + return dev; +} + void system_midi_close(void* p) { plat_midi_close(); @@ -34,11 +55,23 @@ void system_midi_close(void* p) midi_close(); } +void midi_input_close(void* p) +{ + plat_midi_input_close(); + + midi_close(); +} + int system_midi_available(void) { return plat_midi_get_num_devs(); } +int midi_input_available(void) +{ + return plat_midi_in_get_num_devs(); +} + static const device_config_t system_midi_config[] = { { @@ -52,6 +85,37 @@ static const device_config_t system_midi_config[] = } }; +static const device_config_t midi_input_config[] = +{ + { + .name = "midi_input", + .description = "MIDI in device", + .type = CONFIG_MIDI_IN, + .default_int = 0 + }, + { + .name = "realtime", + .description = "MIDI Real time", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "thruchan", + .description = "MIDI Thru", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "clockout", + .description = "MIDI Clockout", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + const device_t system_midi_device = { SYSTEM_MIDI_NAME, @@ -64,3 +128,17 @@ const device_t system_midi_device = NULL, system_midi_config }; + + +const device_t midi_input_device = +{ + MIDI_INPUT_NAME, + 0, 0, + midi_input_init, + midi_input_close, + NULL, + midi_input_available, + NULL, + NULL, + midi_input_config +}; \ No newline at end of file diff --git a/src/sound/snd_audiopci.c b/src/sound/snd_audiopci.c index c6bbefc6b..f24a383d3 100644 --- a/src/sound/snd_audiopci.c +++ b/src/sound/snd_audiopci.c @@ -13,6 +13,8 @@ #include "../pci.h" #include "../timer.h" #include "sound.h" +#include "midi.h" +#include "snd_mpu401.h" #include "snd_audiopci.h" @@ -23,6 +25,8 @@ static float low_fir_es1371_coef[ES1371_NCoef]; typedef struct { + mpu_t mpu; + uint8_t pci_command, pci_serr; uint32_t base_addr; @@ -116,14 +120,21 @@ typedef struct { #define INT_DAC1_EN (1<<6) #define INT_DAC2_EN (1<<5) +#define INT_UART_EN (1<<3) #define SI_P2_INTR_EN (1<<9) #define SI_P1_INTR_EN (1<<8) #define INT_STATUS_INTR (1<<31) +#define INT_STATUS_UART (1<<3) #define INT_STATUS_DAC1 (1<<2) #define INT_STATUS_DAC2 (1<<1) +#define UART_CTRL_TXINTEN (1<<5) + +#define UART_STATUS_TXINT (1<<2) +#define UART_STATUS_TXRDY (1<<1) + #define FORMAT_MONO_8 0 #define FORMAT_STEREO_8 1 #define FORMAT_MONO_16 2 @@ -164,8 +175,13 @@ static void es1371_update_irqs(es1371_t *es1371) if ((es1371->int_status & INT_STATUS_DAC1) && (es1371->si_cr & SI_P1_INTR_EN)) irq = 1; - if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) + if ((es1371->int_status & INT_STATUS_DAC2) && (es1371->si_cr & SI_P2_INTR_EN)) { irq = 1; + } + /*MIDI input is unsupported for now*/ + if ((es1371->int_status & INT_STATUS_UART) && (es1371->uart_status & UART_STATUS_TXINT)) { + irq = 1; + } if (irq) es1371->int_status |= INT_STATUS_INTR; @@ -219,10 +235,10 @@ static uint8_t es1371_inb(uint16_t port, void *p) case 0x07: ret = (es1371->int_status >> 24) & 0xff; break; - - + case 0x09: - ret = es1371->uart_status; + ret = es1371->uart_status & 0xc7; + audiopci_log("ES1371 UART Status = %02x\n", es1371->uart_status); break; case 0x0c: @@ -253,7 +269,7 @@ static uint8_t es1371_inb(uint16_t port, void *p) audiopci_log("Bad es1371_inb: port=%04x\n", port); } -// audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); + audiopci_log("es1371_inb: port=%04x ret=%02x\n", port, ret); // output = 3; return ret; } @@ -340,31 +356,51 @@ static uint32_t es1371_inl(uint16_t port, void *p) ret |= CODEC_READY; break; - case 0x34: - switch (es1371->mem_page) - { + case 0x30: + switch (es1371->mem_page) { + case 0xe: case 0xf: + audiopci_log("ES1371 0x30 read UART FIFO: val = %02x\n", ret & 0xff); + break; + } + break; + case 0x34: + switch (es1371->mem_page) { case 0xc: ret = es1371->dac[0].size | (es1371->dac[0].count << 16); break; case 0xd: - ret = es1371->adc.size | (es1371->adc.count << 16); break; + case 0xe: case 0xf: + audiopci_log("ES1371 0x34 read UART FIFO: val = %02x\n", ret & 0xff); + break; + default: audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); } break; + case 0x38: + switch (es1371->mem_page) { + case 0xe: case 0xf: + audiopci_log("ES1371 0x38 read UART FIFO: val = %02x\n", ret & 0xff); + break; + } + break; + case 0x3c: - switch (es1371->mem_page) - { + switch (es1371->mem_page) { case 0xc: ret = es1371->dac[1].size | (es1371->dac[1].count << 16); break; - + + case 0xe: case 0xf: + audiopci_log("ES1371 0x3c read UART FIFO: val = %02x\n", ret & 0xff); + break; + default: audiopci_log("Bad es1371_inl: mem_page=%x port=%04x\n", es1371->mem_page, port); } @@ -374,7 +410,7 @@ static uint32_t es1371_inl(uint16_t port, void *p) audiopci_log("Bad es1371_inl: port=%04x\n", port); } -// audiopci_log("es1371_inl: port=%04x ret=%08x %08x\n", port, ret, cpu_state.pc); + audiopci_log("es1371_inl: port=%04x ret=%08x\n", port, ret); return ret; } @@ -382,7 +418,7 @@ static void es1371_outb(uint16_t port, uint8_t val, void *p) { es1371_t *es1371 = (es1371_t *)p; -// audiopci_log("es1371_outb: port=%04x val=%02x %04x:%08x\n", port, val, cs, cpu_state.pc); + audiopci_log("es1371_outb: port=%04x val=%02x\n", port, val); switch (port & 0x3f) { case 0x00: @@ -412,8 +448,13 @@ static void es1371_outb(uint16_t port, uint8_t val, void *p) es1371->int_ctrl = (es1371->int_ctrl & 0x00ffffff) | (val << 24); break; + case 0x08: + midi_raw_out_byte(val); + break; + case 0x09: - es1371->uart_ctrl = val; + es1371->uart_ctrl = val & 0xe3; + audiopci_log("ES1371 UART Cntrl = %02x\n", es1371->uart_ctrl); break; case 0x0c: @@ -481,7 +522,7 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) { es1371_t *es1371 = (es1371_t *)p; -// audiopci_log("es1371_outl: port=%04x val=%08x %04x:%08x\n", port, val, CS, cpu_state.pc); + audiopci_log("es1371_outl: port=%04x val=%08x\n", port, val); switch (port & 0x3f) { case 0x04: @@ -593,6 +634,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) // audiopci_log("DAC1 addr %08x\n", val); break; + case 0xe: case 0xf: + audiopci_log("ES1371 0x30 write UART FIFO: val = %02x\n", val & 0xff); + break; + default: audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); } @@ -615,6 +660,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) es1371->adc.count = val >> 16; break; + case 0xe: case 0xf: + audiopci_log("ES1371 0x34 write UART FIFO: val = %02x\n", val & 0xff); + break; + default: audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); } @@ -633,6 +682,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0xd: break; + + case 0xe: case 0xf: + audiopci_log("ES1371 0x38 write UART FIFO: val = %02x\n", val & 0xff); + break; default: audiopci_log("Bad es1371_outl: mem_page=%x port=%04x val=%08x\n", es1371->mem_page, port, val); @@ -649,6 +702,10 @@ static void es1371_outl(uint16_t port, uint32_t val, void *p) case 0xc: es1371->dac[1].size = val & 0xffff; es1371->dac[1].count = val >> 16; + break; + + case 0xe: case 0xf: + audiopci_log("ES1371 0x3c write UART FIFO: val = %02x\n", val & 0xff); break; default: @@ -1107,10 +1164,33 @@ static void es1371_poll(void *p) timer_advance_u64(&es1371->dac[1].timer, es1371->dac[1].latch); - es1371_update(es1371); - - if (es1371->int_ctrl & INT_DAC1_EN) - { + es1371_update(es1371); + + if (es1371->int_ctrl & INT_UART_EN) { + audiopci_log("UART INT Enabled\n"); + if (es1371->uart_ctrl & 0x80) { /*We currently don't implement MIDI Input.*/ + /*But if anything sets MIDI Input and Output together we'd have to take account + of the MIDI Output case, and disable IRQ's and RX bits when MIDI Input is enabled as well but not in the MIDI Output portion*/ + if (es1371->uart_ctrl & UART_CTRL_TXINTEN) + es1371->int_status |= INT_STATUS_UART; + else + es1371->int_status &= ~INT_STATUS_UART; + } else if (!(es1371->uart_ctrl & 0x80) && ((es1371->uart_ctrl & UART_CTRL_TXINTEN))) { /*Or enable the UART IRQ and the respective TX bits only when the MIDI Output is enabled*/ + es1371->int_status |= INT_STATUS_UART; + } + + if (es1371->uart_ctrl & 0x80) { + if (es1371->uart_ctrl & UART_CTRL_TXINTEN) + es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); + else + es1371->uart_status &= ~(UART_STATUS_TXINT | UART_STATUS_TXRDY); + } else + es1371->uart_status |= (UART_STATUS_TXINT | UART_STATUS_TXRDY); + + es1371_update_irqs(es1371); + } + + if (es1371->int_ctrl & INT_DAC1_EN) { int frac = es1371->dac[0].ac & 0x7fff; int idx = es1371->dac[0].ac >> 15; int samp1_l = es1371->dac[0].filtered_l[idx]; diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 15105268f..f30517a2c 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -29,6 +29,7 @@ #define HAVE_STDARG_H #include "../86box.h" #include "../device.h" +#include "../plat.h" #include "../io.h" #include "../machine/machine.h" #include "../mca.h" @@ -38,6 +39,8 @@ #include "snd_mpu401.h" #include "midi.h" +static uint32_t MPUClockBase[8] = {48,72,96,120,144,168,192}; +static uint8_t cth_data[16] = {0,0,0,0,1,0,0,0,1,0,1,0,1,1,1,0}; enum { STATUS_OUTPUT_NOT_READY = 0x40, @@ -48,8 +51,13 @@ enum { int mpu401_standalone_enable = 0; static void MPU401_WriteCommand(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 *p); +static void MPU401_NotesOff(mpu_t *mpu, int i); +static mpu_t *mpuin; +static mutex_t *mpu_lock; #ifdef ENABLE_MPU401_LOG int mpu401_do_log = ENABLE_MPU401_LOG; @@ -71,8 +79,69 @@ mpu401_log(const char *fmt, ...) #endif +void +mpu401_set_midi_in(mpu_t *src_mpu_in) +{ + mpuin = src_mpu_in; +} + static void -QueueByte(mpu_t *mpu, uint8_t data) +MPU401_ReCalcClock(mpu_t *mpu) +{ + int32_t maxtempo = 240, mintempo = 16; + + if (mpu->clock.timebase >= 168) + maxtempo = 179; + if (mpu->clock.timebase == 144) + maxtempo = 208; + if (mpu->clock.timebase >= 120) + maxtempo = 8; + + 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)); + + if (mpu->state.sync_in) { + int32_t freq = (int32_t)((float)(mpu->clock.freq) * mpu->clock.freq_mod); + if ((freq > (mpu->clock.timebase * mintempo)) && (freq < (mpu->clock.timebase * maxtempo))) + mpu->clock.freq = freq; + } +} + +static void +MPU401_StartClock(mpu_t *mpu) +{ + 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); +} + +static void +MPU401_StopClock(mpu_t *mpu) +{ + if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON)) + return; + mpu->clock.active = 0; + timer_disable(&mpu->mpu401_event_callback); +} + +static void +MPU401_RunClock(mpu_t *mpu) +{ + if (!mpu->clock.active) { + timer_disable(&mpu->mpu401_event_callback); + return; + } + timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT/mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); +} + +static void +MPU401_QueueByte(mpu_t *mpu, uint8_t data) { if (mpu->state.block_ack) { mpu->state.block_ack = 0; @@ -88,22 +157,73 @@ QueueByte(mpu_t *mpu, uint8_t data) if (mpu->queue_pos >= MPU401_QUEUE) mpu->queue_pos -= MPU401_QUEUE; - if (pos>=MPU401_QUEUE) pos-=MPU401_QUEUE; mpu->queue_used++; mpu->queue[pos] = data; - } else - mpu401_log("MPU401:Data queue full\n"); + } } +static void +MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) +{ + uint32_t cnt; + + if (block) { + if (mpu_lock) + thread_wait_mutex(mpu_lock); + else + return; + } + + cnt = 0; + while (cnt < len) { + if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) { + 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*/ + mpu->state.sysex_in_finished = 1; + break; + } + cnt++; + } + } + + if (mpu->queue_used == 0) { + if (mpu->state.rec_copy || mpu->state.irq_pending) { + if (block && mpu_lock) + thread_release_mutex(mpu_lock); + if (mpu->state.irq_pending) { + picintc(1 << mpu->irq); + mpu->state.irq_pending = 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++; + } + + if (block && mpu_lock) + thread_release_mutex(mpu_lock); +} static void -ClrQueue(mpu_t *mpu) +MPU401_ClrQueue(mpu_t *mpu) { - mpu->queue_used=0; - mpu->queue_pos=0; + mpu->queue_used = 0; + mpu->queue_pos = 0; + mpu->rec_queue_used = 0; + mpu->rec_queue_pos = 0; + mpu->state.sysex_in_finished = 1; + mpu->state.irq_pending = 0; } @@ -116,8 +236,10 @@ MPU401_Reset(mpu_t *mpu) picintc(1 << mpu->irq); mpu->state.irq_pending = 0; } - + 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; @@ -129,27 +251,64 @@ MPU401_Reset(mpu_t *mpu) mpu->state.cmask = 0xff; mpu->state.amask = mpu->state.tmask = 0; mpu->state.midi_mask = 0xffff; - mpu->state.data_onoff = 0; 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 = 40; + mpu->clock.tempo_rel = mpu->clock.old_tempo_rel = 0x40; + mpu->clock.freq_mod = 1.0; mpu->clock.tempo_grad = 0; - mpu->clock.clock_to_host = 0; - mpu->clock.cth_rate = 60; + MPU401_StopClock(mpu); + MPU401_ReCalcClock(mpu); + + for (i = 0; i < 4; i++) + 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; - ClrQueue(mpu); + /*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; + } + + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = 1; + mpu->inputref[i].chan = i; + if (i > 3) + mpu->ch_toref[i] = 4;/*dummy reftable*/ + } + + MPU401_ClrQueue(mpu); + mpu->state.data_onoff = -1; mpu->state.req_mask = 0; - mpu->condbuf.counter = 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; } + + /*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); + } } @@ -163,6 +322,7 @@ MPU401_ResetDone(void *priv) timer_disable(&mpu->mpu401_reset_callback); mpu->state.reset = 0; + if (mpu->state.cmd_pending) { MPU401_WriteCommand(mpu, mpu->state.cmd_pending - 1); mpu->state.cmd_pending = 0; @@ -173,160 +333,281 @@ MPU401_ResetDone(void *priv) static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) { - uint8_t i, was_uart; + uint8_t i, j, was_uart; if (mpu->state.reset) mpu->state.cmd_pending = val + 1; if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent) - return; + return; - if (val <= 0x2f) { - switch (val&3) { /* MIDI stop, start, continue */ - case 1: - midi_write(0xfc); - break; + thread_wait_mutex(mpu_lock); - case 2: - midi_write(0xfa); - break; + /*hack:enable midi through after the first mpu401 command is written*/ + mpu->midi_thru = 1; - case 3: - midi_write(0xfb); - break; + if (val <= 0x2f) { /* Sequencer state */ + int send_prchg = 0; + if ((val & 0xf) < 0xc) { + switch (val & 3) { /* MIDI realtime messages */ + case 1: + mpu->state.last_rtcmd = 0xfc; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfc); + mpu->clock.meas_old = mpu->clock.measure_counter; + mpu->clock.cth_old = mpu->clock.cth_counter; + break; + case 2: + mpu->state.last_rtcmd = 0xfa; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfb); + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + break; + case 3: + mpu->state.last_rtcmd = 0xfc; + if (mpu->filter.rt_out) + midi_raw_out_rt_byte(0xfa); + mpu->clock.measure_counter = mpu->clock.meas_old; + mpu->clock.cth_counter = mpu->clock.cth_old; + break; + } + switch (val & 0xc) { /* Playing */ + case 0x4: /* Stop */ + 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 */ + mpu->state.playing = 1; + MPU401_StartClock(mpu); + break; + } + switch (val & 0x30) { /* Recording */ + case 0: /* check if it waited for MIDI RT command */ + if (((val & 3) < 2) || !mpu->filter.rt_affection || (mpu->state.rec != M_RECSTB)) + break; + mpu->state.rec = M_RECON; + MPU401_StartClock(mpu); + if (mpu->filter.prchg_mask) + send_prchg = 1; + break; + case 0x10: /* Stop */ + 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); + mpu->filter.prchg_mask = 0; + mpu->clock.rec_counter = 0; + thread_release_mutex(mpu_lock); + return; + case 0x20: /* Start */ + if (!(mpu->state.rec == M_RECON)) { + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECSTB; + } + if ((mpu->state.last_rtcmd == 0xfa) || (mpu->state.last_rtcmd == 0xfb)) { + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECON; + if (mpu->filter.prchg_mask) + send_prchg = 1; + MPU401_StartClock(mpu); + } + } } - - switch (val & 0xc) { - case 0x4: /* Stop */ - mpu->state.playing = 0; - timer_disable(&mpu->mpu401_event_callback); - - for (i = 0xb0; i < 0xbf; i++) { - /* All notes off */ - midi_write(i); - midi_write(0x7b); - midi_write(0); - } - break; - - case 0x8: /* Play */ - mpu->state.playing = 1; - timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / (mpu->clock.tempo*mpu->clock.timebase)) * 1000 * TIMER_USEC); - ClrQueue(mpu); - break; + MPU401_QueueByte(mpu, MSG_MPU_ACK); + /* 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); + + if (send_prchg) for (i = 0; i < 16; i++) + if (mpu->filter.prchg_mask & (1 << i)) { + uint8_t recmsg[3] = {mpu->clock.rec_counter, 0xc0 | i, mpu->filter.prchg_buf[i]}; + MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); + mpu->filter.prchg_mask &= ~(1 << i); } + thread_release_mutex(mpu_lock); } else if ((val >= 0xa0) && (val <= 0xa7)) { /* Request play counter */ - if (mpu->state.cmask & (1 << (val&7))) - QueueByte(mpu, mpu->playbuf[val&7].counter); + MPU401_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.old_track = mpu->state.track; + mpu->state.track= val & 7; mpu->state.wsd = 1; mpu->state.wsm = 0; mpu->state.wsd_start = 1; + } else if ((val < 0x80) && (val >= 0x40)) { /* Set reference table channel */ + mpu->chanref[(val >> 4) - 4].on = 1; + mpu->chanref[(val >> 4) - 4].chan = val & 0x0f; + mpu->chanref[(val >> 4) - 4].trmask = 0; + for (i = 0; i < 4; i++) + mpu->chanref[(val >> 4) - 4].key[i] = 0; + for (i = 0; i < 16; i++) { + if (mpu->ch_toref[i] == ((val >> 4) - 4)) + mpu->ch_toref[i] = 4; + } + mpu->ch_toref[val & 0x0f] = (val >> 4) - 4; } else switch (val) { - case 0xdf: /* Send system message */ - mpu->state.wsd = 0; - mpu->state.wsm = 1; - mpu->state.wsd_start = 1; + case 0x30: /* Configuration 0x30 - 0x39 */ + mpu->filter.allnotesoff_out = 0; break; - - case 0x8e: /* Conductor */ - mpu->state.cond_set = 0; + case 0x32: + mpu->filter.rt_out = 0; break; - - case 0x8f: - mpu->state.cond_set = 1; + case 0x33: + mpu->filter.all_thru = 0; + mpu->filter.commonmsgs_thru = 0; + mpu->filter.midi_thru = 0; + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = 0; + for (j = 0; i < 4; j++) + mpu->inputref[i].key[j] = 0; + } + break; + case 0x34: + mpu->filter.timing_in_stop = 1; + break; + case 0x35: + mpu->filter.modemsgs_in = 1; + break; + case 0x37: + mpu->filter.sysex_thru = 1; + break; + case 0x38: + mpu->filter.commonmsgs_in = 1; + break; + case 0x39: + mpu->filter.rt_in = 1; + break; + case 0x3f: /* UART mode */ + mpu401_log("MPU-401:Set UART mode %X\n",val); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + mpu->mode = M_UART; + 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); + mpu->clock.freq_mod = 1.0; + } + mpu->state.sync_in = 0; + break; + case 0x81: /* Sync to tape signal */ + case 0x82: /* Sync to MIDI */ + mpu->clock.ticks_in = 0; + mpu->state.sync_in = 1; + break; + case 0x86: case 0x87: /* Bender */ + mpu->filter.bender_in = !!(val & 1); + break; + case 0x88: case 0x89: /* MIDI through */ + mpu->filter.midi_thru = !!(val & 1); + for (i = 0; i < 16; i++) { + mpu->inputref[i].on = mpu->filter.midi_thru; + if (!(val & 1)) { + for (j = 0; j < 4; j++) + mpu->inputref[i].key[j] = 0; + } + } + break; + case 0x8a: case 0x8b: /* Data in stop */ + mpu->filter.data_in_stop = !!(val & 1); + break; + case 0x8c: case 0x8d: /* Send measure end */ + mpu->filter.rec_measure_end = !!(val & 1); + break; + case 0x8e: case 0x8f: /* Conductor */ + mpu->state.cond_set = !!(val & 1); + break; + case 0x90: case 0x91: /* Realtime affection */ + mpu->filter.rt_affection = !!(val & 1); break; - case 0x94: /* Clock to host */ - mpu->clock.clock_to_host = 0; + mpu->state.clock_to_host = 0; + MPU401_StopClock(mpu); break; - case 0x95: - mpu->clock.clock_to_host = 1; + mpu->state.clock_to_host = 1; + MPU401_StartClock(mpu); break; - - case 0xc2: /* Internal timebase */ - mpu->clock.timebase = 48; + case 0x96: case 0x97: /* Sysex input allow */ + mpu->filter.sysex_in = !!(val & 1); + if (val & 1) + mpu->filter.sysex_thru = 0; break; - - case 0xc3: - mpu->clock.timebase = 72; + case 0x98: case 0x99: case 0x9a: case 0x9b: /* Reference tables on/off */ + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + mpu->chanref[(val - 0x98) / 2].on = !!(val & 1); break; - - case 0xc4: - mpu->clock.timebase = 96; - break; - - case 0xc5: - mpu->clock.timebase = 120; - break; - - case 0xc6: - mpu->clock.timebase = 144; - break; - - case 0xc7: - mpu->clock.timebase = 168; - break; - case 0xc8: - 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; - break; - /* Commands 0xa# returning data */ case 0xab: /* Request and clear recording counter */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, 0); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, 0); + thread_release_mutex(mpu_lock); return; - case 0xac: /* Request version */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, MPU401_VERSION); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_VERSION); + thread_release_mutex(mpu_lock); return; - case 0xad: /* Request revision */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, MPU401_REVISION); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MPU401_REVISION); + thread_release_mutex(mpu_lock); return; - case 0xaf: /* Request tempo */ - QueueByte(mpu, MSG_MPU_ACK); - QueueByte(mpu, mpu->clock.tempo); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, mpu->clock.tempo); + thread_release_mutex(mpu_lock); return; - case 0xb1: /* Reset relative tempo */ mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; - mpu->clock.tempo_rel = 40; + mpu->clock.tempo_rel = 0x40; break; - - case 0xb9: /* Clear play map */ case 0xb8: /* Clear play counters */ - for (i = 0xb0; i < 0xbf; i++) { - /* All notes off */ - midi_write(i); - midi_write(0x7b); - midi_write(0); - } + mpu->state.last_rtcmd = 0; 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; - 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.conductor = mpu->state.cond_set; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + break; + case 0xb9: /* Clear play map */ + for (i = 0; i < 16; i++) + MPU401_NotesOff(mpu, i); + for (i = 0; i < 8; i++) { + mpu->playbuf[i].counter = 0; + mpu->playbuf[i].type = T_OVERFLOW; + } + mpu->state.last_rtcmd = 0; + mpu->clock.cth_counter = mpu->clock.cth_old = 0; + mpu->clock.measure_counter = mpu->clock.meas_old = 0; + break; + case 0xba: /* Clear record counter */ + mpu->clock.rec_counter = 0; + break; + case 0xc2: case 0xc3: case 0xc4: /* Internal timebase */ + case 0xc5: case 0xc6: case 0xc7: case 0xc8: + mpu->clock.timebase = MPUClockBase[val-0xc2]; + MPU401_ReCalcClock(mpu); + break; + case 0xdf: /* Send system message */ + mpu->state.wsd = 0; + mpu->state.wsm = 1; + mpu->state.wsd_start = 1; + 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; break; - case 0xff: /* Reset MPU-401 */ mpu401_log("MPU-401:Reset %X\n",val); timer_set_delay_u64(&mpu->mpu401_reset_callback, MPU401_RESETBUSY * 33LL * TIMER_USEC); @@ -337,27 +618,23 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) 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; - return; - /* default: mpu401_log("MPU-401:Unhandled command %X",val); */ } - QueueByte(mpu, MSG_MPU_ACK); + MPU401_QueueByte(mpu, MSG_MPU_ACK); + thread_release_mutex(mpu_lock); } static void MPU401_WriteData(mpu_t *mpu, uint8_t val) { - static int length, cnt, posd; + static int length, cnt; + uint8_t i; if (mpu->mode == M_UART) { - midi_write(val); + midi_raw_out_byte(val); return; } @@ -369,39 +646,55 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) switch (mpu->state.command_byte) { /* 0xe# command data */ case 0x00: break; - case 0xe0: /* Set tempo */ mpu->state.command_byte = 0; - mpu->clock.tempo = val; + if (mpu->clock.tempo < 8) + mpu->clock.tempo = 8; + else if (mpu->clock.tempo > 250) + mpu->clock.tempo = 250; + else + mpu->clock.tempo = val; + MPU401_ReCalcClock(mpu); return; - case 0xe1: /* Set relative tempo */ mpu->state.command_byte = 0; mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; mpu->clock.tempo_rel = val; + MPU401_ReCalcClock(mpu); return; - + case 0xe2: /* Set gradation for relative tempo */ + mpu->clock.tempo_grad = val; + MPU401_ReCalcClock(mpu); + return; + case 0xe4: /* Set MIDI clocks for metronome ticks */ + mpu->state.command_byte = 0; + mpu->clock.midimetro = val; + return; + case 0xe6: /* Set metronome ticks per measure */ + mpu->state.command_byte = 0; + mpu->clock.metromeas = val; + return; case 0xe7: /* Set internal clock to host interval */ mpu->state.command_byte = 0; - mpu->clock.cth_rate = val >> 2; + if (!val) + val = 64; + for (i = 0; i < 4; i++) + mpu->clock.cth_rate[i] = (val >> 2) + cth_data[(val & 3) * 4 + i]; + mpu->clock.cth_mode = 0; return; - case 0xec: /* Set active track mask */ 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; return; - case 0xee: /* Set 1-8 MIDI channel mask */ 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; @@ -413,53 +706,49 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) return; } - if (mpu->state.wsd) { + if (mpu->state.wsd && !mpu->state.track_req && !mpu->state.cond_req) { /* 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; + 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: - mpu->playbuf[mpu->state.channel].value[0] = val; - length = 3; + length = mpu->playbuf[mpu->state.track].length = 3; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; break; case 0xf0: /* mpu401_log("MPU-401:Illegal WSD byte\n"); */ mpu->state.wsd = 0; - mpu->state.channel = mpu->state.old_chan; + mpu->state.track = mpu->state.old_track; return; default: /* MIDI with running status */ cnt++; - midi_write(mpu->playbuf[mpu->state.channel].value[0]); + length = mpu->playbuf[mpu->state.track].length; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; } } if (cnt < length) { - midi_write(val); + mpu->playbuf[mpu->state.track].value[cnt] = val; cnt++; } if (cnt == length) { + MPU401_IntelligentOut(mpu, mpu->state.track); mpu->state.wsd = 0; - mpu->state.channel = mpu->state.old_chan; + mpu->state.track = mpu->state.old_track; } return; } - if (mpu->state.wsm) { /* Directly send system message */ - if (val == MSG_EOX) { - midi_write(MSG_EOX); - mpu->state.wsm = 0; - return; - } + if (mpu->state.wsm && !mpu->state.track_req && !mpu->state.cond_req) { /* Send system message */ if (mpu->state.wsd_start) { mpu->state.wsd_start = 0; cnt = 0; @@ -481,12 +770,17 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) break; default: - length = 0; + mpu->state.wsm = 0; + return; } + } else if (val & 0x80) { + midi_raw_out_byte(MSG_EOX); + mpu->state.wsm = 0; + return; } if (!length || (cnt < length)) { - midi_write(val); + midi_raw_out_byte(val); cnt++; } @@ -496,130 +790,179 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) return; } + thread_wait_mutex(mpu_lock); + if (mpu->state.cond_req) { /* Command */ switch (mpu->state.data_onoff) { case -1: + thread_release_mutex(mpu_lock); return; - case 0: /* Timing byte */ - mpu->condbuf.vlength = 0; + mpu->condbuf.length = 0; if (val < 0xf0) mpu->state.data_onoff++; else { + mpu->state.cond_req = 0; mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); - return; + break; } - 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)) + if ((val == 0xf8) || (val == 0xf9) || (val == 0xfc)) mpu->condbuf.type = T_OVERFLOW; - mpu->condbuf.value[mpu->condbuf.vlength] = val; - mpu->condbuf.vlength++; - if ((val & 0xf0) != 0xe0) - MPU401_EOIHandlerDispatch(mpu); - else + 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->state.data_onoff++; break; case 2:/* Command byte #2 */ - mpu->condbuf.value[mpu->condbuf.vlength]=val; - mpu->condbuf.vlength++; - MPU401_EOIHandlerDispatch(mpu); + mpu->condbuf.value[mpu->condbuf.length]=val; + mpu->condbuf.length++; + MPU401_EOIHandler(mpu); + mpu->state.data_onoff = -1; + mpu->state.cond_req = 0; break; } + thread_release_mutex(mpu_lock); return; } switch (mpu->state.data_onoff) { /* Data */ case -1: - return; - + break; case 0: /* Timing byte */ if (val < 0xf0) - mpu->state.data_onoff = 1; + mpu->state.data_onoff++; else { mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); + mpu->state.track_req = 0; + thread_release_mutex(mpu_lock); return; } mpu->state.send_now = !val ? 1 : 0; - mpu->playbuf[mpu->state.channel].counter = val; + mpu->playbuf[mpu->state.track].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) { + 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.channel].type = T_MARK; - mpu->playbuf[mpu->state.channel].sys_val = val; + mpu->playbuf[mpu->state.track].type = T_MARK; + if (val == 0xf9) + mpu->clock.measure_counter = 0; } else { /* mpu401_log("MPU-401:Illegal message"); */ - mpu->playbuf[mpu->state.channel].type = T_MIDI_SYS; - mpu->playbuf[mpu->state.channel].sys_val = val; + mpu->playbuf[mpu->state.track].type = T_OVERFLOW; } - 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; - 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; - 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->state.data_onoff = -1; + MPU401_EOIHandler(mpu); + mpu->state.track_req = 0; + thread_release_mutex(mpu_lock); + return; + default: /* MIDI with running status */ + cnt++; + length = mpu->playbuf[mpu->state.track].length; + mpu->playbuf[mpu->state.track].type = T_MIDI_NORM; break; } - - if (!((posd == 1) && (val >= 0xf0))) - mpu->playbuf[mpu->state.channel].value[posd-1] = val; - if (posd == length) - MPU401_EOIHandlerDispatch(mpu); + 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; } + + thread_release_mutex(mpu_lock); + return; } static void -MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) +MPU401_IntelligentOut(mpu_t *mpu, uint8_t track) { - uint8_t val; + uint8_t chan, chrefnum, key, msg; + int send, retrigger; uint8_t i; - switch (mpu->playbuf[chan].type) { + switch (mpu->playbuf[track].type) { case T_OVERFLOW: break; case T_MARK: - val=mpu->playbuf[chan].sys_val; - if (val==0xfc) { - midi_write(val); - mpu->state.amask &= ~(1<state.req_mask &= ~(1<playbuf[track].sys_val == 0xfc) { + midi_raw_out_rt_byte(mpu->playbuf[track].sys_val); + mpu->state.amask&=~(1<playbuf[chan].vlength; i++) - midi_write(mpu->playbuf[chan].value[i]); + chan = mpu->playbuf[track].value[0] & 0xf; + key = mpu->playbuf[track].value[1] & 0x7f; + chrefnum = mpu->ch_toref[chan]; + send = 1; + retrigger = 0; + switch (msg = mpu->playbuf[track].value[0] & 0xf0) { + 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 */ + 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: + if (mpu->playbuf[track].value[1] == 123) { /* All notes off */ + MPU401_NotesOff(mpu, mpu->playbuf[track].value[0] & 0xf); + return; + } + break; + } + if (retrigger) { + midi_raw_out_byte(0x80 | chan); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + if (send) { + for (i = 0; i < mpu->playbuf[track].length; i++) + midi_raw_out_byte(mpu->playbuf[track].value[i]); + } break; - + default: break; } @@ -627,15 +970,14 @@ MPU401_IntelligentOut(mpu_t *mpu, uint8_t chan) static void -UpdateTrack(mpu_t *mpu, uint8_t chan) +UpdateTrack(mpu_t *mpu, uint8_t track) { - MPU401_IntelligentOut(mpu, chan); + MPU401_IntelligentOut(mpu, track); - 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 << chan); + if (mpu->state.amask&(1<playbuf[track].type = T_OVERFLOW; + mpu->playbuf[track].counter = 0xf0; + mpu->state.req_mask |= (1 << track); } else { if ((mpu->state.amask == 0) && !mpu->state.conductor) mpu->state.req_mask |= (1 << 12); @@ -643,6 +985,7 @@ UpdateTrack(mpu_t *mpu, uint8_t chan) } +#if 0 static void UpdateConductor(mpu_t *mpu) { @@ -659,6 +1002,7 @@ UpdateConductor(mpu_t *mpu) mpu->condbuf.counter = 0xf0; mpu->state.req_mask |= (1 << 9); } +#endif /* Updates counters and requests new data on "End of Input" */ @@ -674,19 +1018,24 @@ MPU401_EOIHandler(void *priv) mpu->state.eoi_scheduled = 0; if (mpu->state.send_now) { mpu->state.send_now = 0; - if (mpu->state.cond_req) UpdateConductor(mpu); - else UpdateTrack(mpu, mpu->state.channel); + 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) + return; + mpu->state.irq_pending = 0; - if (!mpu->state.playing || !mpu->state.req_mask) + if (!(mpu->state.req_mask && mpu->clock.active)) return; i = 0; do { if (mpu->state.req_mask & (1 << i)) { - QueueByte(mpu, 0xf0 + i); + MPU401_QueueByte(mpu, 0xf0 + i); mpu->state.req_mask &= ~(1 << i); break; } @@ -702,7 +1051,7 @@ 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, 60 * TIMER_USEC); /* Possibly a bit longer */ + timer_advance_u64(&mpu->mpu401_eoi_callback, 60LL * TIMER_USEC); /* Possibly a bit longer */ } else if (!mpu->state.eoi_scheduled) MPU401_EOIHandler(mpu); } @@ -721,6 +1070,8 @@ MPU401_ReadData(mpu_t *mpu) uint8_t ret; ret = MSG_MPU_ACK; + thread_wait_mutex(mpu_lock); + if (mpu->queue_used) { if (mpu->queue_pos >= MPU401_QUEUE) mpu->queue_pos -= MPU401_QUEUE; @@ -734,11 +1085,29 @@ MPU401_ReadData(mpu_t *mpu) if (mpu->state.irq_pending) { picintc(1 << mpu->irq); mpu->state.irq_pending = 0; + thread_release_mutex(mpu_lock); } return ret; } + if (mpu->state.rec_copy && !mpu->rec_queue_used) { + mpu->state.rec_copy = 0; + MPU401_EOIHandler(mpu); + thread_release_mutex(mpu_lock); + 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--; + } + if (mpu->queue_used == 0) { picintc(1 << mpu->irq); mpu->state.irq_pending = 0; @@ -746,9 +1115,10 @@ MPU401_ReadData(mpu_t *mpu) if ((ret >= 0xf0) && (ret <= 0xf7)) { /* MIDI data request */ - mpu->state.channel = ret & 7; + 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) { @@ -759,15 +1129,16 @@ MPU401_ReadData(mpu_t *mpu) 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) || (ret == MSG_MPU_OVERFLOW)) { MPU401_EOIHandlerDispatch(mpu); } + thread_release_mutex(mpu_lock); + return(ret); } @@ -822,7 +1193,6 @@ static void MPU401_Event(void *priv) { mpu_t *mpu = (mpu_t *)priv; - int new_time; uint8_t i; mpu401_log("MPU-401 event callback\n"); @@ -833,7 +1203,8 @@ MPU401_Event(void *priv) } if (mpu->state.irq_pending) goto next_event; - + + if (mpu->state.playing) { for (i = 0; i < 8; i++) { /* Decrease counters */ if (mpu->state.amask & (1 << i)) { mpu->playbuf[i].counter--; @@ -843,29 +1214,326 @@ MPU401_Event(void *priv) if (mpu->state.conductor) { mpu->condbuf.counter--; - if (mpu->condbuf.counter <= 0) UpdateConductor(mpu); + if (mpu->condbuf.counter <= 0) { + mpu->condbuf.counter = 0xf0; + mpu->state.req_mask |= (1 << 9); + } } + } - if (mpu->clock.clock_to_host) { + if (mpu->state.clock_to_host) { mpu->clock.cth_counter++; - if (mpu->clock.cth_counter >= mpu->clock.cth_rate) { + 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.irq_pending && mpu->state.req_mask) + 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)) { + 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) { + thread_wait_mutex(mpu_lock); MPU401_EOIHandler(mpu); + thread_release_mutex(mpu_lock); + } next_event: - new_time = ((mpu->clock.tempo * mpu->clock.timebase * mpu->clock.tempo_rel) / 0x40); - if (new_time == 0) { - timer_disable(&mpu->mpu401_event_callback); - return; - } else { - timer_advance_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / new_time) * 1000 * TIMER_USEC); - mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT/new_time) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); - } + MPU401_RunClock(mpu); + if (mpu->state.sync_in) + mpu->clock.ticks_in++; +} + +static void +MPU401_NotesOff(mpu_t *mpu, int i) +{ + int j; + uint8_t key; + + 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 (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 (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 */ +static int +MPU401_InputSysex(uint8_t *buffer, uint32_t len, int abort) +{ + pclog("MPU401 Input Sysex\n"); + + int i; + + if (mpuin->filter.sysex_in) { + if (abort) { + mpuin->state.sysex_in_finished=1; + mpuin->rec_queue_used=0;/*reset also the input queue*/ + return 0; + } + if (mpuin->state.sysex_in_finished) { + if (mpuin->rec_queue_used>=MPU401_INPUT_QUEUE) + return len; + uint8_t val_ff=0xff; + MPU401_RecQueueBuffer(mpuin,&val_ff,1,1); + mpuin->state.sysex_in_finished=0; + mpuin->clock.rec_counter=0; + } + if (mpuin->rec_queue_used>=MPU401_INPUT_QUEUE) + return len; + int available=MPU401_INPUT_QUEUE-mpuin->rec_queue_used; + + if (available>=len) { + MPU401_RecQueueBuffer(mpuin,buffer,len,1); + return 0; + } + else { + MPU401_RecQueueBuffer(mpuin,buffer,available,1); + if (mpuin->state.sysex_in_finished) + return 0; + return (len-available); + } + } + else if (mpuin->filter.sysex_thru && mpuin->midi_thru) { + midi_raw_out_byte(0xf0); + for (i=0;istate.sysex_in_finished) { + pclog("SYSEX in progress\n"); + return; + } + + int i; + static uint8_t old_msg=0; + uint8_t len=msg[3]; + int send=1; + int send_thru=0; + int retrigger_thru=0; + int midistatus=0; + if (mpuin->mode==M_INTELLIGENT) { + if (msg[0]<0x80) { /* Expand running status */ + midistatus=1; + msg[2]=msg[1];msg[1]=msg[0];msg[0]=old_msg; + } + old_msg=msg[0]; + int chan=msg[0]&0xf; + int chrefnum=mpuin->ch_toref[chan]; + uint8_t key=msg[1]&0x7f; + if (msg[0]<0xf0) { //if non-system msg + if (!(mpuin->state.midi_mask&(1<filter.all_thru) + send_thru=1; + else if (mpuin->filter.midi_thru) + send_thru=1; + switch (msg[0]&0xf0) { + case 0x80: /*note off*/ + if (send_thru) { + if (mpuin->chanref[chrefnum].on && (mpuin->chanref[chrefnum].M_GETKEY)) + send_thru=0; + if (!mpuin->filter.midi_thru) + break; + if (!(mpuin->inputref[chan].M_GETKEY)) + send_thru=0; + mpuin->inputref[chan].M_DELKEY; + } + break; + case 0x90: /*note on*/ + if (send_thru) { + if (mpuin->chanref[chrefnum].on && (mpuin->chanref[chrefnum].M_GETKEY)) + retrigger_thru=1; + if (!mpuin->filter.midi_thru) + break; + if (mpuin->inputref[chan].M_GETKEY) + retrigger_thru=1; + mpuin->inputref[chan].M_SETKEY; + } + break; + case 0xb0: + if (msg[1]>=120) { + send_thru=0; + if (msg[1]==123) { /* All notes off */ + for (key=0;key<128;key++) { + if (!(mpuin->chanref[chrefnum].on && (mpuin->chanref[chrefnum].M_GETKEY))) + if (mpuin->inputref[chan].on && mpuin->inputref[chan].M_GETKEY) { + midi_raw_out_byte(0x80|chan); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } + mpuin->inputref[chan].M_DELKEY; + } + } + } + break; + } + } + if (msg[0]>=0xf0 || (mpuin->state.midi_mask&(1<filter.bender_in) + send=0; + break; + case 0xb0: /*control change*/ + if (!mpuin->filter.bender_in && msg[1]<64) + send=0; + if (msg[1]>=120) { + if (mpuin->filter.modemsgs_in) + send=1; + } + break; + case 0xc0: /*program change*/ + if ((mpuin->state.rec!=M_RECON) && !mpuin->filter.data_in_stop) { + mpuin->filter.prchg_buf[chan]=msg[1]; + mpuin->filter.prchg_mask|=1<filter.bender_in) + send=0; + break; + case 0xf0: //system message + if (msg[0]==0xf8) { + send=0; + if (mpuin->clock.active && mpuin->state.sync_in) { + send = 0;/*don't pass to host in this mode?*/ + int tick=mpuin->clock.timebase/24; + if (mpuin->clock.ticks_in!=tick) { + if (!mpuin->clock.ticks_in || (mpuin->clock.ticks_in>tick*2)) + mpuin->clock.freq_mod*=2.0; + else { + if (ABS(mpuin->clock.ticks_in-tick)==1) + mpuin->clock.freq_mod/=mpuin->clock.ticks_in/(float)(tick*2); + else + mpuin->clock.freq_mod/=mpuin->clock.ticks_in/(float)(tick); + } + MPU401_ReCalcClock(mpuin); + } + mpuin->clock.ticks_in=0; + } + } + else if (msg[0]>0xf8) { /*realtime*/ + if (!(mpuin->filter.rt_in && msg[0]<=0xfc && msg[0]>=0xfa)) { + uint8_t recdata[2]={0xff,msg[0]}; + MPU401_RecQueueBuffer(mpuin,recdata,2,1); + send=0; + } + } + else { /*common or system*/ + send=0; + if (msg[0]==0xf2 || msg[0]==0xf3 || msg[0]==0xf6) { + if (mpuin->filter.commonmsgs_in) + send=1; + if (mpuin->filter.commonmsgs_thru) + for (i=0;ifilter.rt_affection) switch(msg[0]) { + case 0xf2:case 0xf3: + mpuin->state.block_ack=1; + MPU401_WriteCommand(mpuin,0xb8);/*clear play counters*/ + break; + case 0xfa: + mpuin->state.block_ack=1; + MPU401_WriteCommand(mpuin,0xa);/*start,play*/ + if (mpuin->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + case 0xfb: + mpuin->state.block_ack=1; + MPU401_WriteCommand(mpuin,0xb);/*continue,play*/ + if (mpuin->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + case 0xfc: + mpuin->state.block_ack=1; + MPU401_WriteCommand(mpuin,0xd);/*stop: play,rec,midi*/ + if (mpuin->filter.rt_out) + midi_raw_out_rt_byte(msg[0]); + break; + } + return; + } + if (send_thru && mpuin->midi_thru) { + if (retrigger_thru) { + midi_raw_out_byte(0x80|(msg[0]&0xf)); + midi_raw_out_byte(msg[1]); + midi_raw_out_byte(msg[2]); + } + for (i=0/*((midistatus && !retrigger_thru)? 1:0)*/;istate.rec==M_RECON) { + uint8_t recmsg[4]={mpuin->clock.rec_counter,msg[0],msg[1],msg[2]}; + MPU401_RecQueueBuffer(mpuin,recmsg,len+1,1); + mpuin->clock.rec_counter=0; + } + else if (mpuin->filter.data_in_stop) { + if (mpuin->filter.timing_in_stop) { + uint8_t recmsg[4]={0,msg[0],msg[1],msg[2]}; + MPU401_RecQueueBuffer(mpuin,recmsg,len+1,1); + } + else { + uint8_t recmsg[4]={msg[0],msg[1],msg[2],0}; + MPU401_RecQueueBuffer(mpuin,recmsg,len,1); + } + } + } + return; + } + /*UART mode input*/ + thread_wait_mutex(mpu_lock); + for (i=0;i * DOSBox Team, @@ -22,10 +22,16 @@ #define MPU401_VERSION 0x15 #define MPU401_REVISION 0x01 -#define MPU401_QUEUE 32 +#define MPU401_QUEUE 64 +#define MPU401_INPUT_QUEUE 1024 #define MPU401_TIMECONSTANT (60000000/1000.0f) #define MPU401_RESETBUSY 27.0f +/*helpers*/ +#define M_GETKEY key[key/32]&(1<<(key%32)) +#define M_SETKEY key[key/32]|=(1<<(key%32)) +#define M_DELKEY key[key/32]&=~(1<<(key%32)) + typedef enum MpuMode { M_UART, @@ -43,6 +49,13 @@ typedef enum MpuDataType T_COMMAND } MpuDataType; +typedef enum RecState +{ + M_RECOFF, + M_RECSTB, + M_RECON +} RecState; + /* Messages sent to MPU-401 from host */ #define MSG_EOX 0xf7 #define MSG_OVERFLOW 0xf8 @@ -57,6 +70,7 @@ typedef enum MpuDataType typedef struct mpu_t { + int midi_thru; int uart_mode, intelligent, irq, queue_pos, queue_used; @@ -64,10 +78,13 @@ typedef struct mpu_t status, queue[MPU401_QUEUE], pos_regs[8]; MpuMode mode; + uint8_t rec_queue[MPU401_INPUT_QUEUE]; + int rec_queue_pos, rec_queue_used; + uint32_t ch_toref[16]; struct track { int counter; - uint8_t value[8], sys_val, + uint8_t value[3], sys_val, vlength,length; MpuDataType type; } playbuf[8], condbuf; @@ -77,23 +94,50 @@ typedef struct mpu_t playing, reset, wsd, wsm, wsd_start, run_irq, irq_pending, + track_req, send_now, eoi_scheduled, - data_onoff; + data_onoff, clock_to_host, + sync_in, sysex_in_finished, + rec_copy; + RecState rec; uint8_t tmask, cmask, amask, - channel, old_chan; + last_rtcmd; uint16_t midi_mask, req_mask; - uint32_t command_byte, cmd_pending; + uint32_t command_byte, cmd_pending, + track, old_track; } 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; + tempo_grad, cth_rate[4], + cth_mode, midimetro, + metromeas; + uint32_t cth_counter, cth_old, + rec_counter; + int32_t measure_counter, meas_old, + freq; + int ticks_in, active; + float freq_mod; } clock; - + struct { + int all_thru, midi_thru, + sysex_thru, commonmsgs_thru, + modemsgs_in, commonmsgs_in, + bender_in, sysex_in, + allnotesoff_out, rt_affection, + rt_out, rt_in, + timing_in_stop, data_in_stop, + rec_measure_end; + uint8_t prchg_buf[16]; + uint16_t prchg_mask; + } filter; + struct { + int on; + uint8_t chan, trmask; + uint32_t key[4]; + } chanref[5], inputref[16]; pc_timer_t mpu401_event_callback, mpu401_eoi_callback, mpu401_reset_callback; } mpu_t; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index b927e54e4..23f5812a9 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -32,6 +32,7 @@ #include "../rom.h" #include "../device.h" #include "sound.h" +#include "midi.h" #include "filters.h" #include "snd_emu8k.h" #include "snd_mpu401.h" @@ -188,6 +189,12 @@ sb_log(const char *fmt, ...) #endif +static void +sb_dsp_set_midi_in(sb_dsp_t *src_dsp_midi_in) +{ + dspin = src_dsp_midi_in; +} + /* sb 1, 1.5, 2, 2 mvc do not have a mixer, so signal is hardwired */ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { @@ -1041,6 +1048,11 @@ void *sb_1_init() io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); } sound_add_handler(sb_get_buffer_sb2, sb); + + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } void *sb_15_init() @@ -1067,6 +1079,11 @@ void *sb_15_init() io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); } sound_add_handler(sb_get_buffer_sb2, sb); + + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } @@ -1090,6 +1107,11 @@ void *sb_mcv_init() mca_add(sb_mcv_read, sb_mcv_write, sb_mcv_feedb, sb); sb->pos_regs[0] = 0x84; sb->pos_regs[1] = 0x50; + + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } void *sb_2_init() @@ -1137,6 +1159,10 @@ void *sb_2_init() else sound_add_handler(sb_get_buffer_sb2, sb); + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } @@ -1170,6 +1196,10 @@ void *sb_pro_v1_init() io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sbpro, sb); + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } @@ -1202,6 +1232,10 @@ void *sb_pro_v2_init() io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sbpro, sb); + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } @@ -1227,6 +1261,10 @@ void *sb_pro_mcv_init() sb->pos_regs[0] = 0x03; sb->pos_regs[1] = 0x51; + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } @@ -1261,6 +1299,11 @@ void *sb_16_init() } else sb->mpu = NULL; + + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } @@ -1305,6 +1348,10 @@ void *sb_awe32_init() sb->mpu = NULL; emu8k_init(&sb->emu8k, emu_addr, onboard_ram); + sb_dsp_set_midi_in(&sb->dsp); + input_msg = sb_dsp_input_msg; + input_sysex = sb_dsp_input_sysex; + return sb; } diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 35aeb7ee7..51188ee03 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -119,7 +119,7 @@ uint8_t adjustMap2[24] = { }; float low_fir_sb16_coef[SB16_NCoef]; - +sb_dsp_t *dspin; #ifdef ENABLE_SB_DSP_LOG int sb_dsp_do_log = ENABLE_SB_DSP_LOG; @@ -147,7 +147,6 @@ sinc(double x) return sin(M_PI * x) / (M_PI * x); } - static void recalc_sb16_filter(int playback_freq) { @@ -207,6 +206,8 @@ sb_irqc(sb_dsp_t *dsp, int irq8) void sb_dsp_reset(sb_dsp_t *dsp) { + midi_clear_buffer(); + timer_disable(&dsp->output_timer); timer_disable(&dsp->input_timer); @@ -218,7 +219,7 @@ sb_dsp_reset(sb_dsp_t *dsp) sb_irqc(dsp, 0); sb_irqc(dsp, 1); dsp->sb_16_pause = 0; - dsp->sb_read_wp = dsp->sb_read_rp = 0; + dsp->sb_read_wp = dsp->sb_read_rp = 0; dsp->sb_data_stat = -1; dsp->sb_speaker = 0; dsp->sb_pausetime = -1LL; @@ -393,7 +394,6 @@ sb_dsp_setdma16(sb_dsp_t *dsp, int dma) dsp->sb_16_dmanum = dma; } - void sb_exec_command(sb_dsp_t *dsp) { @@ -457,19 +457,35 @@ sb_exec_command(sb_dsp_t *dsp) if (dsp->sb_type >= SB15) sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); break; - case 0x30: case 0x31: + case 0x30: /* MIDI Polling mode input */ + pclog("MIDI polling mode input\n"); + dsp->midi_in_poll = 1; + dsp->uart_irq = 0; break; - case 0x34: /* MIDI (UART mode) */ + case 0x31: /* MIDI Interrupt mode input */ + pclog("MIDI interrupt mode input\n"); + dsp->midi_in_poll = 0; + dsp->uart_irq = 1; + break; + case 0x34: /* MIDI In poll */ + if (dsp->sb_type < SB2) + break; + pclog("MIDI poll in\n"); + dsp->midi_in_poll = 1; dsp->uart_midi = 1; dsp->uart_irq = 0; break; - case 0x35: /* MIDI (UART mode) */ + case 0x35: /* MIDI In irq */ + if (dsp->sb_type < SB2) + break; + pclog("MIDI irq in\n"); + dsp->midi_in_poll = 0; dsp->uart_midi = 1; dsp->uart_irq = 1; break; - case 0x36: case 0x37: + case 0x36: case 0x37: /* MIDI timestamps */ break; - case 0x38: /* MIDI (Normal mode) */ + case 0x38: /* Write to SB MIDI Output (Raw) */ dsp->onebyte_midi = 1; break; case 0x40: /* Set time constant */ @@ -724,17 +740,22 @@ sb_write(uint16_t a, uint8_t v, void *priv) switch (a & 0xF) { case 6: /* Reset */ - if (!(v & 1) && (dsp->sbreset & 1)) { - sb_dsp_reset(dsp); - sb_add_data(dsp, 0xAA); + if (!dsp->uart_midi) { + if (!(v & 1) && (dsp->sbreset & 1)) { + sb_dsp_reset(dsp); + sb_add_data(dsp, 0xAA); + } + dsp->sbreset = v; } - dsp->sbreset = v; + dsp->uart_midi = 0; + dsp->uart_irq = 0; + dsp->onebyte_midi = 0; return; case 0xC: /* Command/data write */ - if (dsp->uart_midi || dsp->onebyte_midi) { - midi_write(v); + if (dsp->uart_midi || dsp->onebyte_midi ) { + midi_raw_out_byte(v); dsp->onebyte_midi = 0; - return; + return; } timer_set_delay_u64(&dsp->wb_timer, TIMER_USEC * 1); if (dsp->asp_data_len) { @@ -768,9 +789,9 @@ sb_read(uint16_t a, void *priv) switch (a & 0xf) { case 0xA: /* Read data */ - if (mpu && dsp->uart_midi) + if (mpu && dsp->uart_midi) { ret = MPU401_ReadData(mpu); - else { + } else { dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; if (dsp->sb_read_rp != dsp->sb_read_wp) { dsp->sb_read_rp++; @@ -814,6 +835,47 @@ sb_dsp_set_mpu(mpu_t *src_mpu) mpu = src_mpu; } +void +sb_dsp_input_msg(uint8_t *msg) +{ + pclog("MIDI in sysex = %d, uart irq = %d, midi in = %d\n", dspin->midi_in_sysex, dspin->uart_irq, dspin->midi_in_poll); + + if (dspin->midi_in_sysex) { + return; + } + + uint8_t len = msg[3]; + uint8_t i = 0; + if (dspin->uart_irq) { + for (i=0;isb_irq8) sb_irq(dspin, 1); + } else if (dspin->midi_in_poll) { + for (i=0;imidi_in_sysex = 0; + return 0; + } + dspin->midi_in_sysex = 1; + for (i=0;isb_read_rp == dspin->sb_read_wp) { + pclog("Length sysex SB = %d\n", len-i); + return (len-i); + } + sb_add_data(dspin, buffer[i]); + } + dspin->midi_in_sysex = 0; + return 0; +} void sb_dsp_init(sb_dsp_t *dsp, int type) diff --git a/src/sound/snd_sb_dsp.h b/src/sound/snd_sb_dsp.h index 2772e2254..2c7022912 100644 --- a/src/sound/snd_sb_dsp.h +++ b/src/sound/snd_sb_dsp.h @@ -9,14 +9,18 @@ typedef struct sb_dsp_t int sb_pausetime; uint8_t sb_read_data[256]; - int sb_read_wp, sb_read_rp; + int sb_read_wp, sb_read_rp; int sb_speaker; int muted; int sb_data_stat; - int uart_midi; - int uart_irq; - int onebyte_midi; + + int midi_in_sysex; + int midi_in_poll; + int uart_midi; + int uart_irq; + int onebyte_midi; + int midi_in_timestamp; int sb_irqnum; @@ -72,6 +76,12 @@ typedef struct sb_dsp_t int pos; } sb_dsp_t; +extern sb_dsp_t *dspin; + +void sb_dsp_input_msg(uint8_t *msg); + +int sb_dsp_input_sysex(uint8_t *buffer, uint32_t len, int abort); + void sb_dsp_set_mpu(mpu_t *src_mpu); void sb_dsp_init(sb_dsp_t *dsp, int type); diff --git a/src/sound/sound.c b/src/sound/sound.c index 12875f4f1..d3de46351 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -107,7 +107,6 @@ static const SOUND_CARD sound_cards[] = { "[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 } }; @@ -442,6 +441,7 @@ sound_reset(void) sound_realloc_buffers(); midi_device_init(); + midi_in_device_init(); inital(); timer_add(&sound_poll_timer, sound_poll, NULL, 1); diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 294e813b9..43c2c0f7c 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -380,34 +380,39 @@ BEGIN LTEXT "MIDI Out Device:",IDT_1712,7,26,59,10 PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI,214,25,46,12 + COMBOBOX IDC_COMBO_MIDI_IN,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | + WS_TABSTOP + LTEXT "MIDI In Device:",IDT_1713,7,44,59,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MIDI_IN,214,43,46,12 + CONTROL "Standalone MPU-401",IDC_CHECK_MPU401,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,45,199,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,44,46,12 + BS_AUTOCHECKBOX | WS_TABSTOP,7,65,199,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_MPU401,214,64,46,12 CONTROL "Innovation SSI-2001",IDC_CHECK_SSI,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,63,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,83,94,10 CONTROL "CMS / Game Blaster",IDC_CHECK_CMS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,63,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,147,83,94,10 CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,101,94,10 CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,81,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,147,101,94,10 END DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "Network type:",IDT_1713,7,8,59,10 + LTEXT "Network type:",IDT_1714,7,8,59,10 COMBOBOX IDC_COMBO_NET_TYPE,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "PCap device:",IDT_1714,7,26,59,10 + LTEXT "PCap device:",IDT_1715,7,26,59,10 COMBOBOX IDC_COMBO_PCAP,71,25,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "Network adapter:",IDT_1715,7,44,59,10 + LTEXT "Network adapter:",IDT_1716,7,44,59,10 COMBOBOX IDC_COMBO_NET,71,43,140,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure",IDC_CONFIGURE_NET,214,43,46,12 @@ -417,15 +422,15 @@ DLG_CFG_PORTS DIALOG DISCARDABLE 97, 0, 267, 117 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "LPT1 Device:",IDT_1716,7,8,61,10 + LTEXT "LPT1 Device:",IDT_1717,7,8,61,10 COMBOBOX IDC_COMBO_LPT1,71,7,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LPT2 Device:",IDT_1717,7,27,61,10 + LTEXT "LPT2 Device:",IDT_1718,7,27,61,10 COMBOBOX IDC_COMBO_LPT2,71,26,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP - LTEXT "LPT3 Device:",IDT_1718,7,46,61,10 + LTEXT "LPT3 Device:",IDT_1719,7,46,61,10 COMBOBOX IDC_COMBO_LPT3,71,45,189,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP @@ -446,12 +451,12 @@ DLG_CFG_PERIPHERALS DIALOG DISCARDABLE 97, 0, 267, 200 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN - LTEXT "SCSI Controller:",IDT_1716,7,8,48,10 + LTEXT "SCSI Controller:",IDT_1717,7,8,48,10 COMBOBOX IDC_COMBO_SCSI,64,7,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure",IDC_CONFIGURE_SCSI,222,7,38,12 - LTEXT "HD Controller:",IDT_1717,7,26,48,10 + LTEXT "HD Controller:",IDT_1718,7,26,48,10 COMBOBOX IDC_COMBO_HDC,64,25,155,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP PUSHBUTTON "Configure",IDC_CONFIGURE_HDC,222,25,38,12 diff --git a/src/win/resource.h b/src/win/resource.h index e34f6a1be..49ba9679e 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -54,12 +54,13 @@ #define IDT_1710 1710 /* Joystick: */ #define IDT_1711 1711 /* Sound card: */ #define IDT_1712 1712 /* MIDI Out Device: */ -#define IDT_1713 1713 /* Network type: */ -#define IDT_1714 1714 /* PCap device: */ -#define IDT_1715 1715 /* Network adapter: */ -#define IDT_1716 1716 /* SCSI Controller: */ -#define IDT_1717 1717 /* HD Controller: */ -#define IDT_1718 1718 +#define IDT_1713 1713 /* MIDI In Device: */ +#define IDT_1714 1714 /* Network type: */ +#define IDT_1715 1715 /* PCap device: */ +#define IDT_1716 1716 /* Network adapter: */ +#define IDT_1717 1717 /* SCSI Controller: */ +#define IDT_1718 1718 /* HD Controller: */ +#define IDT_1719 1719 #define IDT_1720 1720 /* Hard disks: */ #define IDT_1721 1721 /* Bus: */ #define IDT_1722 1722 /* Channel: */ @@ -149,6 +150,7 @@ #define IDC_CONFIGURE_MPU401 1077 #define IDC_CHECK_FLOAT 1078 #define IDC_CHECK_GUSMAX 1079 +#define IDC_COMBO_MIDI_IN 1080 #define IDC_COMBO_NET_TYPE 1090 /* network config */ #define IDC_COMBO_PCAP 1091 @@ -241,6 +243,7 @@ #define IDC_CONFIGURE_PCAP 1306 #define IDC_CONFIGURE_NET 1307 #define IDC_CONFIGURE_MIDI 1308 +#define IDC_CONFIGURE_MIDI_IN 1309 #define IDC_JOY1 1310 #define IDC_JOY2 1311 #define IDC_JOY3 1312 diff --git a/src/win/win_devconf.c b/src/win/win_devconf.c index a0a1e5018..e5e379d6c 100644 --- a/src/win/win_devconf.c +++ b/src/win/win_devconf.c @@ -108,6 +108,21 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) id += 2; break; + case CONFIG_MIDI_IN: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + + num = plat_midi_in_get_num_devs(); + for (c = 0; c < num; c++) { + plat_midi_in_get_dev_name(c, s); + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)lptsTemp); + if (val_int == c) + SendMessage(h, CB_SETCURSEL, c, 0); + } + + id += 2; + break; case CONFIG_SPINNER: val_int = config_get_int((char *) config_device.name, (char *) config->name, config->default_int); @@ -205,6 +220,17 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) c = SendMessage(h, CB_GETCURSEL, 0, 0); + if (val_int != c) + changed = 1; + + id += 2; + break; + case CONFIG_MIDI_IN: + val_int = config_get_int((char *) config_device.name, + (char *) config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + if (val_int != c) changed = 1; @@ -302,6 +328,12 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) c = SendMessage(h, CB_GETCURSEL, 0, 0); config_set_int((char *) config_device.name, (char *) config->name, c); + id += 2; + break; + case CONFIG_MIDI_IN: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + config_set_int((char *) config_device.name, (char *) config->name, c); + id += 2; break; case CONFIG_FNAME: @@ -358,6 +390,7 @@ deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) break; case CONFIG_SELECTION: case CONFIG_MIDI: + case CONFIG_MIDI_IN: case CONFIG_SPINNER: id += 2; break; @@ -478,6 +511,7 @@ deviceconfig_inst_open(HWND hwnd, const device_t *device, int inst) case CONFIG_SELECTION: case CONFIG_MIDI: + case CONFIG_MIDI_IN: case CONFIG_HEX16: case CONFIG_HEX20: /*Combo box*/ diff --git a/src/win/win_midi.c b/src/win/win_midi.c index 706db3acb..239fd7a77 100644 --- a/src/win/win_midi.c +++ b/src/win/win_midi.c @@ -13,13 +13,15 @@ typedef struct { - int midi_id; + int midi_id, midi_input_id; HANDLE m_event; + HANDLE m_callback; HMIDIOUT midi_out_device; + HMIDIIN midi_in_device; - MIDIHDR m_hdr; + MIDIHDR m_hdr, m_hdr_in; } plat_midi_t; plat_midi_t *pm = NULL; @@ -39,6 +41,7 @@ plat_midi_init(void) pm->m_event = CreateEvent(NULL, TRUE, TRUE, NULL); + pclog("Plat MIDI Out init\n"); hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); if (hr != MMSYSERR_NOERROR) { @@ -65,7 +68,7 @@ plat_midi_close(void) midiOutClose(pm->midi_out_device); CloseHandle(pm->m_event); } - + free(pm); pm = NULL; } @@ -135,3 +138,119 @@ plat_midi_write(uint8_t val) { return 0; } + +void CALLBACK +plat_midi_in_callback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { + pclog("MIDI: wMsg:%x %x %x\n",wMsg, dwParam1, dwParam2); + uint8_t msg[4] = {((dwParam1&0xff)),(((dwParam1&0xff00)>>8)), + (((dwParam1&0xff0000)>>16)),MIDI_evt_len[((dwParam1&0xff))]}; + uint8_t *sysex; + int len; + int cnt; + MIDIHDR *t_hdr; + switch (wMsg) { + case MM_MIM_DATA: /* 0x3C3 - midi message */ + input_msg(msg); + break; + case MM_MIM_OPEN: /* 0x3C1 */ + break; + case MM_MIM_CLOSE: /* 0x3C2 */ + break; + case MM_MIM_LONGDATA: /* 0x3C4 - sysex */ + pclog("MIDI sysex\n"); + t_hdr = (MIDIHDR *)dwParam1; + sysex = (uint8_t *)t_hdr->lpData; + len = (unsigned int)t_hdr->dwBytesRecorded; + cnt = 5; + while (cnt) { /*abort if timed out*/ + int ret = input_sysex(sysex, len, 0); + if (!ret) { + len = 0; + break; + } + if (len==ret) + cnt--; + else + cnt = 5; + sysex += len-ret; + len = ret; + Sleep(5);/*msec*/ + } + if (len) + input_sysex(sysex, 0, 0); + + midiInUnprepareHeader(hMidiIn, t_hdr, sizeof(*t_hdr)); + t_hdr->dwBytesRecorded = 0; + midiInPrepareHeader(hMidiIn, t_hdr, sizeof(*t_hdr)); + break; + case MM_MIM_ERROR: + case MM_MIM_LONGERROR: + break; + default: + break; + } +} + +void +plat_midi_input_init(void) +{ + MMRESULT hr; + + pm = (plat_midi_t *) malloc(sizeof(plat_midi_t)); + memset(pm, 0, sizeof(plat_midi_t)); + + pclog("Plat MIDI Input init\n"); + + pm->midi_input_id = config_get_int(MIDI_INPUT_NAME, "midi_input", 0); + + hr = midiInOpen(&pm->midi_in_device, pm->midi_input_id, + (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); + if (hr != MMSYSERR_NOERROR) { + pclog("midiInOpen error - %08X\n", hr); + pm->midi_input_id = 0; + hr = midiInOpen(&pm->midi_in_device, pm->midi_input_id, + (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); + if (hr != MMSYSERR_NOERROR) { + pclog("midiInOpen error - %08X\n", hr); + return; + } + } + + pm->m_hdr_in.lpData = (char*)&MIDI_InSysexBuf[0]; + pm->m_hdr_in.dwBufferLength = SYSEX_SIZE; + pm->m_hdr_in.dwBytesRecorded = 0 ; + pm->m_hdr_in.dwUser = 0; + pclog("Prepare MIDI In\n"); + midiInPrepareHeader(pm->midi_in_device,&pm->m_hdr_in,sizeof(pm->m_hdr_in)); + midiInStart(pm->midi_in_device); +} + +void +plat_midi_input_close(void) +{ + if (pm) { + if (pm->midi_in_device != NULL) { + midiInStop(pm->midi_in_device); + midiInClose(pm->midi_in_device); + } + + free(pm); + pm = NULL; + } +} + +int +plat_midi_in_get_num_devs(void) +{ + return midiInGetNumDevs(); +} + + +void +plat_midi_in_get_dev_name(int num, char *s) +{ + MIDIINCAPS caps; + + midiInGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} \ No newline at end of file diff --git a/src/win/win_settings.c b/src/win/win_settings.c index f2a716a8c..1a2605a07 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -84,7 +84,7 @@ static int temp_gfxcard, temp_voodoo; static int temp_mouse, temp_joystick; /* Sound category */ -static int temp_sound_card, temp_midi_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS; +static int temp_sound_card, temp_midi_device, temp_midi_input_device, temp_mpu401, temp_SSI2001, temp_GAMEBLASTER, temp_GUS; static int temp_float; /* Network category */ @@ -123,6 +123,7 @@ extern int is486; static int listtomachine[256], machinetolist[256]; static int settings_device_to_list[2][20], settings_list_to_device[2][20]; static int settings_midi_to_list[20], settings_list_to_midi[20]; +static int settings_midi_in_to_list[20], settings_list_to_midi_in[20]; static int max_spt = 63, max_hpc = 255, max_tracks = 266305; static uint64_t mfm_tracking, esdi_tracking, xta_tracking, ide_tracking, scsi_tracking[2]; @@ -218,6 +219,7 @@ win_settings_init(void) /* Sound category */ temp_sound_card = sound_card_current; temp_midi_device = midi_device_current; + temp_midi_input_device = midi_input_device_current; temp_mpu401 = mpu401_standalone_enable; temp_SSI2001 = SSI2001; temp_GAMEBLASTER = GAMEBLASTER; @@ -329,6 +331,7 @@ win_settings_changed(void) /* Sound category */ i = i || (sound_card_current != temp_sound_card); i = i || (midi_device_current != temp_midi_device); + i = i || (midi_input_device_current != temp_midi_input_device); i = i || (mpu401_standalone_enable != temp_mpu401); i = i || (SSI2001 != temp_SSI2001); i = i || (GAMEBLASTER != temp_GAMEBLASTER); @@ -431,6 +434,7 @@ win_settings_save(void) /* Sound category */ sound_card_current = temp_sound_card; midi_device_current = temp_midi_device; + midi_input_device_current = temp_midi_input_device; mpu401_standalone_enable = temp_mpu401; SSI2001 = temp_SSI2001; GAMEBLASTER = temp_GAMEBLASTER; @@ -1100,12 +1104,13 @@ mpu401_present(void) int mpu401_standalone_allow(void) { - char *md; + char *md, *mdin; md = midi_device_get_internal_name(temp_midi_device); + mdin = midi_in_device_get_internal_name(temp_midi_input_device); if (md != NULL) { - if (!strcmp(md, "none")) + if (!strcmp(md, "none") && !strcmp(mdin, "none")) return 0; } @@ -1195,12 +1200,45 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) else EnableWindow(h, FALSE); + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + c = d = 0; + while (1) { + s = midi_in_device_getname(c); + + if (!s[0]) + break; + + settings_midi_in_to_list[c] = d; + + if (midi_in_device_available(c)) { + if (c == 0) + SendMessage(h, CB_ADDSTRING, 0, win_get_string(IDS_2112)); + else { + mbstowcs(lptsTemp, s, strlen(s) + 1); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM) lptsTemp); + } + settings_list_to_midi_in[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_midi_in_to_list[temp_midi_input_device], 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI_IN); + if (midi_in_device_has_config(temp_midi_input_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); SendMessage(h, BM_SETCHECK, temp_mpu401, 0); EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + h=GetDlgItem(hdlg, IDC_CHECK_CMS); SendMessage(h, BM_SETCHECK, temp_GAMEBLASTER, 0); @@ -1270,6 +1308,31 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_device_getdevice(temp_midi_device)); break; + case IDC_COMBO_MIDI_IN: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MIDI_IN); + if (midi_in_device_has_config(temp_midi_input_device)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); + SendMessage(h, BM_SETCHECK, temp_mpu401, 0); + EnableWindow(h, mpu401_standalone_allow() ? TRUE : FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_MPU401); + EnableWindow(h, (mpu401_standalone_allow() && temp_mpu401) ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_MIDI_IN: + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)midi_in_device_getdevice(temp_midi_input_device)); + break; + case IDC_CHECK_MPU401: h = GetDlgItem(hdlg, IDC_CHECK_MPU401); temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); @@ -1292,6 +1355,9 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h = GetDlgItem(hdlg, IDC_COMBO_MIDI); temp_midi_device = settings_list_to_midi[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_COMBO_MIDI_IN); + temp_midi_input_device = settings_list_to_midi_in[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_CHECK_MPU401); temp_mpu401 = SendMessage(h, BM_GETCHECK, 0, 0); From e8dd8c377450077a76369c2d345c5f1e72e9c989 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Thu, 2 Jan 2020 18:19:22 +0100 Subject: [PATCH 02/10] Fixed midi input code. Currently only MPU401 (standalone) and SB cards have MIDI Input capabilities, es1371 and GUS will be done for a later time. --- src/sound/midi.c | 38 +++---- src/sound/midi.h | 7 +- src/sound/midi_system.c | 12 +-- src/sound/snd_mpu401.c | 222 ++++++++++++++++------------------------ src/sound/snd_sb.c | 30 +++--- src/sound/snd_sb_dsp.c | 56 +++++----- src/sound/snd_sb_dsp.h | 5 +- src/win/win_midi.c | 78 +++++++------- 8 files changed, 199 insertions(+), 249 deletions(-) diff --git a/src/sound/midi.c b/src/sound/midi.c index 7648c8c92..98c5100a0 100644 --- a/src/sound/midi.c +++ b/src/sound/midi.c @@ -45,10 +45,11 @@ static int midi_device_last = 0; int midi_input_device_current = 0; static int midi_input_device_last = 0; -midi_t *midi = NULL; +midi_t *midi = NULL, *midi_in = NULL; -void (*input_msg)(uint8_t *msg); -int (*input_sysex)(uint8_t *buffer, uint32_t len, int abort); +void (*input_msg)(void *p, uint8_t *msg); +int (*input_sysex)(void *p, uint8_t *buffer, uint32_t len, int abort); +void *midi_in_p; uint8_t MIDI_InSysexBuf[SYSEX_SIZE]; @@ -202,14 +203,14 @@ midi_close(void) void midi_in_close(void) { - if (midi && midi->m_in_device) { - free(midi->m_in_device); - midi->m_in_device = NULL; + if (midi_in && midi_in->m_in_device) { + free(midi_in->m_in_device); + midi_in->m_in_device = NULL; } - if (midi) { - free(midi); - midi = NULL; + if (midi_in) { + free(midi_in); + midi_in = NULL; } } @@ -300,24 +301,21 @@ midi_in_device_init() void midi_raw_out_rt_byte(uint8_t val) { - if (!midi || !midi->m_out_device || !midi->m_in_device) + if (!midi_in->midi_realtime) return; - if (!midi->midi_realtime) - return; - - if ((!midi->midi_clockout && (val == 0xf8))) + if ((!midi_in->midi_clockout && (val == 0xf8))) return; - midi->midi_cmd_r = val << 24; + midi_in->midi_cmd_r = val << 24; pclog("Play RT Byte msg\n"); - play_msg((uint8_t *)&midi->midi_cmd_r); + play_msg((uint8_t *)&midi_in->midi_cmd_r); } void midi_raw_out_thru_rt_byte(uint8_t val) { - if (midi->thruchan) + if (midi_in->thruchan) midi_raw_out_rt_byte(val); } @@ -326,11 +324,13 @@ midi_raw_out_byte(uint8_t val) { uint32_t passed_ticks; - if (!midi || !midi->m_out_device) + if (!midi || !midi->m_out_device) { return; + } - if ((midi->m_out_device->write && midi->m_out_device->write(val))) + if ((midi->m_out_device->write && midi->m_out_device->write(val))) { return; + } if (midi->midi_sysex_start) { passed_ticks = plat_get_ticks() - midi->midi_sysex_start; diff --git a/src/sound/midi.h b/src/sound/midi.h index 21441646c..8e516c2a3 100644 --- a/src/sound/midi.h +++ b/src/sound/midi.h @@ -10,8 +10,9 @@ extern uint8_t MIDI_evt_len[256]; extern int midi_device_current; extern int midi_input_device_current; -extern void (*input_msg)(uint8_t *msg); -extern int (*input_sysex)(uint8_t *buffer, uint32_t len, int abort); +extern void (*input_msg)(void *p, uint8_t *msg); +extern int (*input_sysex)(void *p, uint8_t *buffer, uint32_t len, int abort); +extern void *midi_in_p; int midi_device_available(int card); int midi_in_device_available(int card); @@ -50,7 +51,7 @@ typedef struct midi_t midi_device_t *m_out_device, *m_in_device; } midi_t; -extern midi_t *midi; +extern midi_t *midi, *midi_in; void midi_init(midi_device_t* device); void midi_in_init(midi_device_t* device, midi_t **mididev); diff --git a/src/sound/midi_system.c b/src/sound/midi_system.c index f3ace5c69..6ee56b01a 100644 --- a/src/sound/midi_system.c +++ b/src/sound/midi_system.c @@ -17,8 +17,6 @@ void* system_midi_init(const device_t *info) midi_device_t* dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); - pclog("MIDI Output\n"); - dev->play_msg = plat_midi_play_msg; dev->play_sysex = plat_midi_play_sysex; dev->write = plat_midi_write; @@ -35,15 +33,13 @@ void* midi_input_init(const device_t *info) midi_device_t* dev = malloc(sizeof(midi_device_t)); memset(dev, 0, sizeof(midi_device_t)); - pclog("MIDI Input\n"); - plat_midi_input_init(); - midi_in_init(dev, &midi); + midi_in_init(dev, &midi_in); - midi->midi_realtime = device_get_config_int("realtime"); - midi->thruchan = device_get_config_int("thruchan"); - midi->midi_clockout = device_get_config_int("clockout"); + midi_in->midi_realtime = device_get_config_int("realtime"); + midi_in->thruchan = device_get_config_int("thruchan"); + midi_in->midi_clockout = device_get_config_int("clockout"); return dev; } diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index f30517a2c..33fbe16b4 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -56,8 +56,6 @@ static void MPU401_EOIHandler(void *priv); static void MPU401_EOIHandlerDispatch(void *p); static void MPU401_NotesOff(mpu_t *mpu, int i); -static mpu_t *mpuin; -static mutex_t *mpu_lock; #ifdef ENABLE_MPU401_LOG int mpu401_do_log = ENABLE_MPU401_LOG; @@ -79,12 +77,6 @@ mpu401_log(const char *fmt, ...) #endif -void -mpu401_set_midi_in(mpu_t *src_mpu_in) -{ - mpuin = src_mpu_in; -} - static void MPU401_ReCalcClock(mpu_t *mpu) { @@ -169,14 +161,7 @@ static void MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) { uint32_t cnt; - - if (block) { - if (mpu_lock) - thread_wait_mutex(mpu_lock); - else - return; - } - + cnt = 0; while (cnt < len) { if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) { @@ -195,8 +180,6 @@ MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) if (mpu->queue_used == 0) { if (mpu->state.rec_copy || mpu->state.irq_pending) { - if (block && mpu_lock) - thread_release_mutex(mpu_lock); if (mpu->state.irq_pending) { picintc(1 << mpu->irq); mpu->state.irq_pending = 0; @@ -210,9 +193,6 @@ MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) mpu->rec_queue_used--; mpu->rec_queue_pos++; } - - if (block && mpu_lock) - thread_release_mutex(mpu_lock); } static void @@ -341,8 +321,6 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent) return; - thread_wait_mutex(mpu_lock); - /*hack:enable midi through after the first mpu401 command is written*/ mpu->midi_thru = 1; @@ -402,7 +380,6 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) MPU401_QueueByte(mpu, MSG_MPU_END); mpu->filter.prchg_mask = 0; mpu->clock.rec_counter = 0; - thread_release_mutex(mpu_lock); return; case 0x20: /* Start */ if (!(mpu->state.rec == M_RECON)) { @@ -430,7 +407,6 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); mpu->filter.prchg_mask &= ~(1 << i); } - thread_release_mutex(mpu_lock); } 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 */ @@ -545,22 +521,18 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) case 0xab: /* Request and clear recording counter */ MPU401_QueueByte(mpu, MSG_MPU_ACK); MPU401_QueueByte(mpu, 0); - thread_release_mutex(mpu_lock); return; case 0xac: /* Request version */ MPU401_QueueByte(mpu, MSG_MPU_ACK); MPU401_QueueByte(mpu, MPU401_VERSION); - thread_release_mutex(mpu_lock); return; case 0xad: /* Request revision */ MPU401_QueueByte(mpu, MSG_MPU_ACK); MPU401_QueueByte(mpu, MPU401_REVISION); - thread_release_mutex(mpu_lock); return; case 0xaf: /* Request tempo */ MPU401_QueueByte(mpu, MSG_MPU_ACK); MPU401_QueueByte(mpu, mpu->clock.tempo); - thread_release_mutex(mpu_lock); return; case 0xb1: /* Reset relative tempo */ mpu->clock.old_tempo_rel = mpu->clock.tempo_rel; @@ -623,7 +595,6 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) } MPU401_QueueByte(mpu, MSG_MPU_ACK); - thread_release_mutex(mpu_lock); } @@ -790,13 +761,10 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) return; } - thread_wait_mutex(mpu_lock); - if (mpu->state.cond_req) { /* Command */ switch (mpu->state.data_onoff) { case -1: - thread_release_mutex(mpu_lock); return; case 0: /* Timing byte */ mpu->condbuf.length = 0; @@ -833,7 +801,6 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) mpu->state.cond_req = 0; break; } - thread_release_mutex(mpu_lock); return; } @@ -848,7 +815,6 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) mpu->state.data_onoff = -1; MPU401_EOIHandlerDispatch(mpu); mpu->state.track_req = 0; - thread_release_mutex(mpu_lock); return; } mpu->state.send_now = !val ? 1 : 0; @@ -879,7 +845,6 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) mpu->state.data_onoff = -1; MPU401_EOIHandler(mpu); mpu->state.track_req = 0; - thread_release_mutex(mpu_lock); return; default: /* MIDI with running status */ cnt++; @@ -901,7 +866,6 @@ MPU401_WriteData(mpu_t *mpu, uint8_t val) break; } - thread_release_mutex(mpu_lock); return; } @@ -1070,8 +1034,7 @@ MPU401_ReadData(mpu_t *mpu) uint8_t ret; ret = MSG_MPU_ACK; - thread_wait_mutex(mpu_lock); - + if (mpu->queue_used) { if (mpu->queue_pos >= MPU401_QUEUE) mpu->queue_pos -= MPU401_QUEUE; @@ -1085,7 +1048,6 @@ MPU401_ReadData(mpu_t *mpu) if (mpu->state.irq_pending) { picintc(1 << mpu->irq); mpu->state.irq_pending = 0; - thread_release_mutex(mpu_lock); } return ret; @@ -1094,7 +1056,6 @@ MPU401_ReadData(mpu_t *mpu) if (mpu->state.rec_copy && !mpu->rec_queue_used) { mpu->state.rec_copy = 0; MPU401_EOIHandler(mpu); - thread_release_mutex(mpu_lock); return ret; } @@ -1137,8 +1098,6 @@ MPU401_ReadData(mpu_t *mpu) MPU401_EOIHandlerDispatch(mpu); } - thread_release_mutex(mpu_lock); - return(ret); } @@ -1251,9 +1210,7 @@ MPU401_Event(void *priv) } } if (!mpu->state.irq_pending && mpu->state.req_mask) { - thread_wait_mutex(mpu_lock); MPU401_EOIHandler(mpu); - thread_release_mutex(mpu_lock); } next_event: @@ -1291,42 +1248,44 @@ MPU401_NotesOff(mpu_t *mpu, int i) /*Input handler for SysEx */ static int -MPU401_InputSysex(uint8_t *buffer, uint32_t len, int abort) +MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort) { - pclog("MPU401 Input Sysex\n"); + mpu_t *mpu = (mpu_t *)p; + + mpu401_log("MPU401 Input Sysex\n"); int i; - if (mpuin->filter.sysex_in) { + if (mpu->filter.sysex_in) { if (abort) { - mpuin->state.sysex_in_finished=1; - mpuin->rec_queue_used=0;/*reset also the input queue*/ + mpu->state.sysex_in_finished=1; + mpu->rec_queue_used=0;/*reset also the input queue*/ return 0; } - if (mpuin->state.sysex_in_finished) { - if (mpuin->rec_queue_used>=MPU401_INPUT_QUEUE) + if (mpu->state.sysex_in_finished) { + if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) return len; uint8_t val_ff=0xff; - MPU401_RecQueueBuffer(mpuin,&val_ff,1,1); - mpuin->state.sysex_in_finished=0; - mpuin->clock.rec_counter=0; + MPU401_RecQueueBuffer(mpu,&val_ff,1,1); + mpu->state.sysex_in_finished=0; + mpu->clock.rec_counter=0; } - if (mpuin->rec_queue_used>=MPU401_INPUT_QUEUE) + if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) return len; - int available=MPU401_INPUT_QUEUE-mpuin->rec_queue_used; + int available=MPU401_INPUT_QUEUE-mpu->rec_queue_used; if (available>=len) { - MPU401_RecQueueBuffer(mpuin,buffer,len,1); + MPU401_RecQueueBuffer(mpu,buffer,len,1); return 0; } else { - MPU401_RecQueueBuffer(mpuin,buffer,available,1); - if (mpuin->state.sysex_in_finished) + MPU401_RecQueueBuffer(mpu,buffer,available,1); + if (mpu->state.sysex_in_finished) return 0; return (len-available); } } - else if (mpuin->filter.sysex_thru && mpuin->midi_thru) { + else if (mpu->filter.sysex_thru && mpu->midi_thru) { midi_raw_out_byte(0xf0); for (i=0;istate.sysex_in_finished) { - pclog("SYSEX in progress\n"); + if (!mpu->state.sysex_in_finished) { + mpu401_log("SYSEX in progress\n"); return; } + + mpu401_log("MPU401 Input Msg\n"); int i; static uint8_t old_msg=0; @@ -1354,41 +1315,41 @@ MPU401_InputMsg(uint8_t *msg) int send_thru=0; int retrigger_thru=0; int midistatus=0; - if (mpuin->mode==M_INTELLIGENT) { + if (mpu->mode==M_INTELLIGENT) { if (msg[0]<0x80) { /* Expand running status */ midistatus=1; msg[2]=msg[1];msg[1]=msg[0];msg[0]=old_msg; } old_msg=msg[0]; int chan=msg[0]&0xf; - int chrefnum=mpuin->ch_toref[chan]; + int chrefnum=mpu->ch_toref[chan]; uint8_t key=msg[1]&0x7f; if (msg[0]<0xf0) { //if non-system msg - if (!(mpuin->state.midi_mask&(1<filter.all_thru) + if (!(mpu->state.midi_mask&(1<filter.all_thru) send_thru=1; - else if (mpuin->filter.midi_thru) + else if (mpu->filter.midi_thru) send_thru=1; switch (msg[0]&0xf0) { case 0x80: /*note off*/ if (send_thru) { - if (mpuin->chanref[chrefnum].on && (mpuin->chanref[chrefnum].M_GETKEY)) + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) send_thru=0; - if (!mpuin->filter.midi_thru) + if (!mpu->filter.midi_thru) break; - if (!(mpuin->inputref[chan].M_GETKEY)) + if (!(mpu->inputref[chan].M_GETKEY)) send_thru=0; - mpuin->inputref[chan].M_DELKEY; + mpu->inputref[chan].M_DELKEY; } break; case 0x90: /*note on*/ if (send_thru) { - if (mpuin->chanref[chrefnum].on && (mpuin->chanref[chrefnum].M_GETKEY)) + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) retrigger_thru=1; - if (!mpuin->filter.midi_thru) + if (!mpu->filter.midi_thru) break; - if (mpuin->inputref[chan].M_GETKEY) + if (mpu->inputref[chan].M_GETKEY) retrigger_thru=1; - mpuin->inputref[chan].M_SETKEY; + mpu->inputref[chan].M_SETKEY; } break; case 0xb0: @@ -1396,112 +1357,112 @@ MPU401_InputMsg(uint8_t *msg) send_thru=0; if (msg[1]==123) { /* All notes off */ for (key=0;key<128;key++) { - if (!(mpuin->chanref[chrefnum].on && (mpuin->chanref[chrefnum].M_GETKEY))) - if (mpuin->inputref[chan].on && mpuin->inputref[chan].M_GETKEY) { + if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) + if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) { midi_raw_out_byte(0x80|chan); midi_raw_out_byte(key); midi_raw_out_byte(0); } - mpuin->inputref[chan].M_DELKEY; + mpu->inputref[chan].M_DELKEY; } } } break; } } - if (msg[0]>=0xf0 || (mpuin->state.midi_mask&(1<=0xf0 || (mpu->state.midi_mask&(1<filter.bender_in) + if (!mpu->filter.bender_in) send=0; break; case 0xb0: /*control change*/ - if (!mpuin->filter.bender_in && msg[1]<64) + if (!mpu->filter.bender_in && msg[1]<64) send=0; if (msg[1]>=120) { - if (mpuin->filter.modemsgs_in) + if (mpu->filter.modemsgs_in) send=1; } break; case 0xc0: /*program change*/ - if ((mpuin->state.rec!=M_RECON) && !mpuin->filter.data_in_stop) { - mpuin->filter.prchg_buf[chan]=msg[1]; - mpuin->filter.prchg_mask|=1<state.rec!=M_RECON) && !mpu->filter.data_in_stop) { + mpu->filter.prchg_buf[chan]=msg[1]; + mpu->filter.prchg_mask|=1<filter.bender_in) + if (!mpu->filter.bender_in) send=0; break; case 0xf0: //system message if (msg[0]==0xf8) { send=0; - if (mpuin->clock.active && mpuin->state.sync_in) { + if (mpu->clock.active && mpu->state.sync_in) { send = 0;/*don't pass to host in this mode?*/ - int tick=mpuin->clock.timebase/24; - if (mpuin->clock.ticks_in!=tick) { - if (!mpuin->clock.ticks_in || (mpuin->clock.ticks_in>tick*2)) - mpuin->clock.freq_mod*=2.0; + int tick=mpu->clock.timebase/24; + if (mpu->clock.ticks_in!=tick) { + if (!mpu->clock.ticks_in || (mpu->clock.ticks_in>tick*2)) + mpu->clock.freq_mod*=2.0; else { - if (ABS(mpuin->clock.ticks_in-tick)==1) - mpuin->clock.freq_mod/=mpuin->clock.ticks_in/(float)(tick*2); + if (ABS(mpu->clock.ticks_in-tick)==1) + mpu->clock.freq_mod/=mpu->clock.ticks_in/(float)(tick*2); else - mpuin->clock.freq_mod/=mpuin->clock.ticks_in/(float)(tick); + mpu->clock.freq_mod/=mpu->clock.ticks_in/(float)(tick); } - MPU401_ReCalcClock(mpuin); + MPU401_ReCalcClock(mpu); } - mpuin->clock.ticks_in=0; + mpu->clock.ticks_in=0; } } else if (msg[0]>0xf8) { /*realtime*/ - if (!(mpuin->filter.rt_in && msg[0]<=0xfc && msg[0]>=0xfa)) { + if (!(mpu->filter.rt_in && msg[0]<=0xfc && msg[0]>=0xfa)) { uint8_t recdata[2]={0xff,msg[0]}; - MPU401_RecQueueBuffer(mpuin,recdata,2,1); + MPU401_RecQueueBuffer(mpu,recdata,2,1); send=0; } } else { /*common or system*/ send=0; if (msg[0]==0xf2 || msg[0]==0xf3 || msg[0]==0xf6) { - if (mpuin->filter.commonmsgs_in) + if (mpu->filter.commonmsgs_in) send=1; - if (mpuin->filter.commonmsgs_thru) + if (mpu->filter.commonmsgs_thru) for (i=0;ifilter.rt_affection) switch(msg[0]) { + if (mpu->filter.rt_affection) switch(msg[0]) { case 0xf2:case 0xf3: - mpuin->state.block_ack=1; - MPU401_WriteCommand(mpuin,0xb8);/*clear play counters*/ + mpu->state.block_ack=1; + MPU401_WriteCommand(mpu,0xb8);/*clear play counters*/ break; case 0xfa: - mpuin->state.block_ack=1; - MPU401_WriteCommand(mpuin,0xa);/*start,play*/ - if (mpuin->filter.rt_out) + mpu->state.block_ack=1; + MPU401_WriteCommand(mpu,0xa);/*start,play*/ + if (mpu->filter.rt_out) midi_raw_out_rt_byte(msg[0]); break; case 0xfb: - mpuin->state.block_ack=1; - MPU401_WriteCommand(mpuin,0xb);/*continue,play*/ - if (mpuin->filter.rt_out) + mpu->state.block_ack=1; + MPU401_WriteCommand(mpu,0xb);/*continue,play*/ + if (mpu->filter.rt_out) midi_raw_out_rt_byte(msg[0]); break; case 0xfc: - mpuin->state.block_ack=1; - MPU401_WriteCommand(mpuin,0xd);/*stop: play,rec,midi*/ - if (mpuin->filter.rt_out) + mpu->state.block_ack=1; + MPU401_WriteCommand(mpu,0xd);/*stop: play,rec,midi*/ + if (mpu->filter.rt_out) midi_raw_out_rt_byte(msg[0]); break; } return; } - if (send_thru && mpuin->midi_thru) { + if (send_thru && mpu->midi_thru) { if (retrigger_thru) { midi_raw_out_byte(0x80|(msg[0]&0xf)); midi_raw_out_byte(msg[1]); @@ -1511,29 +1472,29 @@ MPU401_InputMsg(uint8_t *msg) midi_raw_out_byte(msg[i]); } if (send) { - if (mpuin->state.rec==M_RECON) { - uint8_t recmsg[4]={mpuin->clock.rec_counter,msg[0],msg[1],msg[2]}; - MPU401_RecQueueBuffer(mpuin,recmsg,len+1,1); - mpuin->clock.rec_counter=0; + if (mpu->state.rec==M_RECON) { + uint8_t recmsg[4]={mpu->clock.rec_counter,msg[0],msg[1],msg[2]}; + MPU401_RecQueueBuffer(mpu,recmsg,len+1,1); + mpu->clock.rec_counter=0; } - else if (mpuin->filter.data_in_stop) { - if (mpuin->filter.timing_in_stop) { + else if (mpu->filter.data_in_stop) { + if (mpu->filter.timing_in_stop) { uint8_t recmsg[4]={0,msg[0],msg[1],msg[2]}; - MPU401_RecQueueBuffer(mpuin,recmsg,len+1,1); + MPU401_RecQueueBuffer(mpu,recmsg,len+1,1); } else { uint8_t recmsg[4]={msg[0],msg[1],msg[2],0}; - MPU401_RecQueueBuffer(mpuin,recmsg,len,1); + MPU401_RecQueueBuffer(mpu,recmsg,len,1); } } } return; } /*UART mode input*/ - thread_wait_mutex(mpu_lock); - for (i=0;iirq); + } } @@ -1644,10 +1605,9 @@ mpu401_standalone_init(const device_t *info) irq = device_get_config_int("irq"); } - mpu401_set_midi_in(mpu); - mpu_lock = thread_create_mutex(L"86Box.MPU401Mutex"); input_msg = MPU401_InputMsg; input_sysex = MPU401_InputSysex; + midi_in_p = mpu; mpu401_init(mpu, base, irq, M_INTELLIGENT); @@ -1660,8 +1620,6 @@ mpu401_standalone_close(void *priv) { mpu_t *mpu = (mpu_t *)priv; - thread_close_mutex(mpu_lock); - free(mpu); } diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index 23f5812a9..f86e85cd9 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -189,12 +189,6 @@ sb_log(const char *fmt, ...) #endif -static void -sb_dsp_set_midi_in(sb_dsp_t *src_dsp_midi_in) -{ - dspin = src_dsp_midi_in; -} - /* sb 1, 1.5, 2, 2 mvc do not have a mixer, so signal is hardwired */ static void sb_get_buffer_sb2(int32_t *buffer, int len, void *p) { @@ -1049,9 +1043,9 @@ void *sb_1_init() } sound_add_handler(sb_get_buffer_sb2, sb); - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; - input_sysex = sb_dsp_input_sysex; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1080,9 +1074,9 @@ void *sb_15_init() } sound_add_handler(sb_get_buffer_sb2, sb); - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; - input_sysex = sb_dsp_input_sysex; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1108,9 +1102,9 @@ void *sb_mcv_init() sb->pos_regs[0] = 0x84; sb->pos_regs[1] = 0x50; - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; - input_sysex = sb_dsp_input_sysex; + input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1159,9 +1153,9 @@ void *sb_2_init() else sound_add_handler(sb_get_buffer_sb2, sb); - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1196,9 +1190,9 @@ void *sb_pro_v1_init() io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sbpro, sb); - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1232,9 +1226,9 @@ void *sb_pro_v2_init() io_sethandler(addr+4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, sb); sound_add_handler(sb_get_buffer_sbpro, sb); - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1261,9 +1255,9 @@ void *sb_pro_mcv_init() sb->pos_regs[0] = 0x03; sb->pos_regs[1] = 0x51; - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1300,9 +1294,9 @@ void *sb_16_init() sb->mpu = NULL; - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } @@ -1348,9 +1342,9 @@ void *sb_awe32_init() sb->mpu = NULL; emu8k_init(&sb->emu8k, emu_addr, onboard_ram); - sb_dsp_set_midi_in(&sb->dsp); input_msg = sb_dsp_input_msg; input_sysex = sb_dsp_input_sysex; + midi_in_p = &sb->dsp; return sb; } diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 51188ee03..dc40de587 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -119,7 +119,7 @@ uint8_t adjustMap2[24] = { }; float low_fir_sb16_coef[SB16_NCoef]; -sb_dsp_t *dspin; + #ifdef ENABLE_SB_DSP_LOG int sb_dsp_do_log = ENABLE_SB_DSP_LOG; @@ -458,19 +458,19 @@ sb_exec_command(sb_dsp_t *dsp) sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); break; case 0x30: /* MIDI Polling mode input */ - pclog("MIDI polling mode input\n"); + sb_dsp_log("MIDI polling mode input\n"); dsp->midi_in_poll = 1; dsp->uart_irq = 0; break; case 0x31: /* MIDI Interrupt mode input */ - pclog("MIDI interrupt mode input\n"); + sb_dsp_log("MIDI interrupt mode input\n"); dsp->midi_in_poll = 0; dsp->uart_irq = 1; break; case 0x34: /* MIDI In poll */ if (dsp->sb_type < SB2) break; - pclog("MIDI poll in\n"); + sb_dsp_log("MIDI poll in\n"); dsp->midi_in_poll = 1; dsp->uart_midi = 1; dsp->uart_irq = 0; @@ -478,7 +478,7 @@ sb_exec_command(sb_dsp_t *dsp) case 0x35: /* MIDI In irq */ if (dsp->sb_type < SB2) break; - pclog("MIDI irq in\n"); + sb_dsp_log("MIDI irq in\n"); dsp->midi_in_poll = 0; dsp->uart_midi = 1; dsp->uart_irq = 1; @@ -836,44 +836,50 @@ sb_dsp_set_mpu(mpu_t *src_mpu) } void -sb_dsp_input_msg(uint8_t *msg) +sb_dsp_input_msg(void *p, uint8_t *msg) { - pclog("MIDI in sysex = %d, uart irq = %d, midi in = %d\n", dspin->midi_in_sysex, dspin->uart_irq, dspin->midi_in_poll); + sb_dsp_t *dsp = (sb_dsp_t *) p; - if (dspin->midi_in_sysex) { + sb_dsp_log("MIDI in sysex = %d, uart irq = %d, msg = %d\n", dsp->midi_in_sysex, dsp->uart_irq, msg[3]); + + if (dsp->midi_in_sysex) { return; } uint8_t len = msg[3]; uint8_t i = 0; - if (dspin->uart_irq) { + if (dsp->uart_irq) { for (i=0;isb_irq8) sb_irq(dspin, 1); - } else if (dspin->midi_in_poll) { + sb_add_data(dsp, msg[i]); + sb_dsp_log("SB IRQ8 = %d\n", dsp->sb_irq8); + if (!dsp->sb_irq8) + picint(1 << dsp->sb_irqnum); + } else if (dsp->midi_in_poll) { for (i=0;imidi_in_sysex = 0; + dsp->midi_in_sysex = 0; return 0; } - dspin->midi_in_sysex = 1; + dsp->midi_in_sysex = 1; for (i=0;isb_read_rp == dspin->sb_read_wp) { - pclog("Length sysex SB = %d\n", len-i); + if (dsp->sb_read_rp == dsp->sb_read_wp) { + sb_dsp_log("Length sysex SB = %d\n", len-i); return (len-i); } - sb_add_data(dspin, buffer[i]); + sb_add_data(dsp, buffer[i]); } - dspin->midi_in_sysex = 0; + dsp->midi_in_sysex = 0; return 0; } @@ -943,7 +949,7 @@ pollsb(void *p) break; dsp->sbdat = (data[0] ^ 0x80) << 8; if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - pclog("pollsb: Mono unsigned, dsp->stereo, %s channel, %04X\n", + sb_dsp_log("pollsb: Mono unsigned, dsp->stereo, %s channel, %04X\n", dsp->sbleftright ? "left" : "right", dsp->sbdat); if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; @@ -960,7 +966,7 @@ pollsb(void *p) break; dsp->sbdat = data[0] << 8; if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - pclog("pollsb: Mono signed, dsp->stereo, %s channel, %04X\n", + sb_dsp_log("pollsb: Mono signed, dsp->stereo, %s channel, %04X\n", dsp->sbleftright ? "left" : "right", data[0], dsp->sbdat); if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; @@ -1020,7 +1026,7 @@ pollsb(void *p) } if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - pclog("pollsb: ADPCM 4, dsp->stereo, %s channel, %04X\n", + sb_dsp_log("pollsb: ADPCM 4, dsp->stereo, %s channel, %04X\n", dsp->sbleftright ? "left" : "right", dsp->sbdat); if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; @@ -1063,7 +1069,7 @@ pollsb(void *p) } if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - pclog("pollsb: ADPCM 26, dsp->stereo, %s channel, %04X\n", + sb_dsp_log("pollsb: ADPCM 26, dsp->stereo, %s channel, %04X\n", dsp->sbleftright ? "left" : "right", dsp->sbdat); if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; @@ -1099,7 +1105,7 @@ pollsb(void *p) } if ((dsp->sb_type >= SBPRO) && (dsp->sb_type < SB16) && dsp->stereo) { - pclog("pollsb: ADPCM 2, dsp->stereo, %s channel, %04X\n", + sb_dsp_log("pollsb: ADPCM 2, dsp->stereo, %s channel, %04X\n", dsp->sbleftright ? "left" : "right", dsp->sbdat); if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; diff --git a/src/sound/snd_sb_dsp.h b/src/sound/snd_sb_dsp.h index 2c7022912..9e60dfaac 100644 --- a/src/sound/snd_sb_dsp.h +++ b/src/sound/snd_sb_dsp.h @@ -76,11 +76,10 @@ typedef struct sb_dsp_t int pos; } sb_dsp_t; -extern sb_dsp_t *dspin; -void sb_dsp_input_msg(uint8_t *msg); +void sb_dsp_input_msg(void *p, uint8_t *msg); -int sb_dsp_input_sysex(uint8_t *buffer, uint32_t len, int abort); +int sb_dsp_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort); void sb_dsp_set_mpu(mpu_t *src_mpu); diff --git a/src/win/win_midi.c b/src/win/win_midi.c index 239fd7a77..256ab6a5e 100644 --- a/src/win/win_midi.c +++ b/src/win/win_midi.c @@ -16,15 +16,14 @@ typedef struct int midi_id, midi_input_id; HANDLE m_event; - HANDLE m_callback; HMIDIOUT midi_out_device; HMIDIIN midi_in_device; - MIDIHDR m_hdr, m_hdr_in; + MIDIHDR m_hdr; } plat_midi_t; -plat_midi_t *pm = NULL; +plat_midi_t *pm = NULL, *pm_in = NULL; void @@ -41,7 +40,6 @@ plat_midi_init(void) pm->m_event = CreateEvent(NULL, TRUE, TRUE, NULL); - pclog("Plat MIDI Out init\n"); hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); if (hr != MMSYSERR_NOERROR) { @@ -140,30 +138,29 @@ plat_midi_write(uint8_t val) } void CALLBACK -plat_midi_in_callback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { - pclog("MIDI: wMsg:%x %x %x\n",wMsg, dwParam1, dwParam2); +plat_midi_in_callback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) +{ uint8_t msg[4] = {((dwParam1&0xff)),(((dwParam1&0xff00)>>8)), (((dwParam1&0xff0000)>>16)),MIDI_evt_len[((dwParam1&0xff))]}; uint8_t *sysex; - int len; + uint32_t len; int cnt; - MIDIHDR *t_hdr; + MIDIHDR *hdr; switch (wMsg) { case MM_MIM_DATA: /* 0x3C3 - midi message */ - input_msg(msg); + input_msg(midi_in_p, msg); break; case MM_MIM_OPEN: /* 0x3C1 */ break; case MM_MIM_CLOSE: /* 0x3C2 */ break; case MM_MIM_LONGDATA: /* 0x3C4 - sysex */ - pclog("MIDI sysex\n"); - t_hdr = (MIDIHDR *)dwParam1; - sysex = (uint8_t *)t_hdr->lpData; - len = (unsigned int)t_hdr->dwBytesRecorded; + hdr = (MIDIHDR *)dwParam1; + sysex = (uint8_t *)hdr->lpData; + len = (uint32_t)hdr->dwBytesRecorded; cnt = 5; while (cnt) { /*abort if timed out*/ - int ret = input_sysex(sysex, len, 0); + int ret = input_sysex(midi_in_p, sysex, len, 0); if (!ret) { len = 0; break; @@ -177,11 +174,11 @@ plat_midi_in_callback(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PT Sleep(5);/*msec*/ } if (len) - input_sysex(sysex, 0, 0); + input_sysex(midi_in_p, sysex, 0, 0); - midiInUnprepareHeader(hMidiIn, t_hdr, sizeof(*t_hdr)); - t_hdr->dwBytesRecorded = 0; - midiInPrepareHeader(hMidiIn, t_hdr, sizeof(*t_hdr)); + midiInUnprepareHeader(hMidiIn, hdr, sizeof(*hdr)); + hdr->dwBytesRecorded = 0; + midiInPrepareHeader(hMidiIn, hdr, sizeof(*hdr)); break; case MM_MIM_ERROR: case MM_MIM_LONGERROR: @@ -196,46 +193,45 @@ plat_midi_input_init(void) { MMRESULT hr; - pm = (plat_midi_t *) malloc(sizeof(plat_midi_t)); - memset(pm, 0, sizeof(plat_midi_t)); + pm_in = (plat_midi_t *) malloc(sizeof(plat_midi_t)); + memset(pm_in, 0, sizeof(plat_midi_t)); - pclog("Plat MIDI Input init\n"); - - pm->midi_input_id = config_get_int(MIDI_INPUT_NAME, "midi_input", 0); + pm_in->midi_input_id = config_get_int(MIDI_INPUT_NAME, "midi_input", 0); - hr = midiInOpen(&pm->midi_in_device, pm->midi_input_id, + hr = MMSYSERR_NOERROR; + + hr = midiInOpen(&pm_in->midi_in_device, pm_in->midi_input_id, (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); if (hr != MMSYSERR_NOERROR) { - pclog("midiInOpen error - %08X\n", hr); - pm->midi_input_id = 0; - hr = midiInOpen(&pm->midi_in_device, pm->midi_input_id, + printf("midiInOpen error - %08X\n", hr); + pm_in->midi_input_id = 0; + hr = midiInOpen(&pm_in->midi_in_device, pm_in->midi_input_id, (uintptr_t) plat_midi_in_callback, 0, CALLBACK_FUNCTION); if (hr != MMSYSERR_NOERROR) { - pclog("midiInOpen error - %08X\n", hr); + printf("midiInOpen error - %08X\n", hr); return; } } - pm->m_hdr_in.lpData = (char*)&MIDI_InSysexBuf[0]; - pm->m_hdr_in.dwBufferLength = SYSEX_SIZE; - pm->m_hdr_in.dwBytesRecorded = 0 ; - pm->m_hdr_in.dwUser = 0; - pclog("Prepare MIDI In\n"); - midiInPrepareHeader(pm->midi_in_device,&pm->m_hdr_in,sizeof(pm->m_hdr_in)); - midiInStart(pm->midi_in_device); + pm_in->m_hdr.lpData = (char*)&MIDI_InSysexBuf[0]; + pm_in->m_hdr.dwBufferLength = SYSEX_SIZE; + pm_in->m_hdr.dwBytesRecorded = 0; + pm_in->m_hdr.dwUser = 0; + midiInPrepareHeader(pm_in->midi_in_device,&pm_in->m_hdr,sizeof(pm_in->m_hdr)); + midiInStart(pm_in->midi_in_device); } void plat_midi_input_close(void) { - if (pm) { - if (pm->midi_in_device != NULL) { - midiInStop(pm->midi_in_device); - midiInClose(pm->midi_in_device); + if (pm_in) { + if (pm_in->midi_in_device != NULL) { + midiInStop(pm_in->midi_in_device); + midiInClose(pm_in->midi_in_device); } - free(pm); - pm = NULL; + free(pm_in); + pm_in = NULL; } } From f7ffe8a2479d06afd9a4d87a40856bea2552a689 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 4 Jan 2020 03:32:20 +0100 Subject: [PATCH 03/10] Fixed coding style and IRQ handling per the spec. Also made commands other than 0xFF ignored in UART mode, also per the spec. --- src/sound/snd_mpu401.c | 852 ++++++++++++++++++++++------------------- 1 file changed, 452 insertions(+), 400 deletions(-) diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 33fbe16b4..5b4d2635b 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -80,58 +80,63 @@ mpu401_log(const char *fmt, ...) static void MPU401_ReCalcClock(mpu_t *mpu) { - int32_t maxtempo = 240, mintempo = 16; - - if (mpu->clock.timebase >= 168) - maxtempo = 179; - if (mpu->clock.timebase == 144) - maxtempo = 208; - if (mpu->clock.timebase >= 120) - maxtempo = 8; - - 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)); + int32_t maxtempo = 240, mintempo = 16; + int32_t freq; - if (mpu->state.sync_in) { - int32_t freq = (int32_t)((float)(mpu->clock.freq) * mpu->clock.freq_mod); + if (mpu->clock.timebase >= 168) + maxtempo = 179; + if (mpu->clock.timebase == 144) + maxtempo = 208; + if (mpu->clock.timebase >= 120) + maxtempo = 8; + + 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)); + + if (mpu->state.sync_in) { + freq = (int32_t)((float)(mpu->clock.freq) * mpu->clock.freq_mod); if ((freq > (mpu->clock.timebase * mintempo)) && (freq < (mpu->clock.timebase * maxtempo))) - mpu->clock.freq = freq; - } + mpu->clock.freq = freq; + } } + static void MPU401_StartClock(mpu_t *mpu) { - 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) + 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); } + static void MPU401_StopClock(mpu_t *mpu) { - if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON)) - return; - mpu->clock.active = 0; - timer_disable(&mpu->mpu401_event_callback); + if (mpu->state.clock_to_host || mpu->state.playing || (mpu->state.rec == M_RECON)) + return; + mpu->clock.active = 0; + timer_disable(&mpu->mpu401_event_callback); } + static void MPU401_RunClock(mpu_t *mpu) { - if (!mpu->clock.active) { - timer_disable(&mpu->mpu401_event_callback); - return; - } - timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); - mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT/mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); + if (!mpu->clock.active) { + timer_disable(&mpu->mpu401_event_callback); + return; + } + timer_set_delay_u64(&mpu->mpu401_event_callback, (MPU401_TIMECONSTANT / mpu->clock.freq) * 1000 * TIMER_USEC); + mpu401_log("Next event after %i us (time constant: %i)\n", (uint64_t) ((MPU401_TIMECONSTANT/mpu->clock.freq) * 1000 * TIMER_USEC), (int) MPU401_TIMECONSTANT); } + static void MPU401_QueueByte(mpu_t *mpu, uint8_t data) { @@ -139,11 +144,12 @@ MPU401_QueueByte(mpu_t *mpu, uint8_t data) mpu->state.block_ack = 0; return; } - - if ((mpu->queue_used == 0) && (mpu->mode == M_INTELLIGENT)) { + + if (mpu->queue_used == 0) { mpu->state.irq_pending = 1; picint(1 << mpu->irq); } + if (mpu->queue_used < MPU401_QUEUE) { int pos = mpu->queue_used+mpu->queue_pos; @@ -157,33 +163,35 @@ MPU401_QueueByte(mpu_t *mpu, uint8_t data) } } + static void MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) { - uint32_t cnt; + uint32_t cnt = 0; + int pos; - cnt = 0; - while (cnt < len) { + while (cnt < len) { if (mpu->rec_queue_used < MPU401_INPUT_QUEUE) { - 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*/ - mpu->state.sysex_in_finished = 1; - break; + 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 */ + mpu->state.sysex_in_finished = 1; + break; + } + cnt++; } - cnt++; - } - } - - if (mpu->queue_used == 0) { + } + + if (mpu->queue_used == 0) { if (mpu->state.rec_copy || mpu->state.irq_pending) { if (mpu->state.irq_pending) { - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; - } + picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + } return; } mpu->state.rec_copy = 1; @@ -192,18 +200,19 @@ MPU401_RecQueueBuffer(mpu_t *mpu, uint8_t *buf, uint32_t len, int block) MPU401_QueueByte(mpu, mpu->rec_queue[mpu->rec_queue_pos]); mpu->rec_queue_used--; mpu->rec_queue_pos++; - } + } } + static void MPU401_ClrQueue(mpu_t *mpu) { mpu->queue_used = 0; mpu->queue_pos = 0; - mpu->rec_queue_used = 0; - mpu->rec_queue_pos = 0; - mpu->state.sysex_in_finished = 1; - mpu->state.irq_pending = 0; + mpu->rec_queue_used = 0; + mpu->rec_queue_pos = 0; + mpu->state.sysex_in_finished = 1; + mpu->state.irq_pending = 0; } @@ -218,8 +227,8 @@ MPU401_Reset(mpu_t *mpu) } mpu->mode = M_INTELLIGENT; - mpu->midi_thru = 0; - mpu->state.rec = M_RECOFF; + mpu->midi_thru = 0; + mpu->state.rec = M_RECOFF; mpu->state.eoi_scheduled = 0; mpu->state.wsd = 0; mpu->state.wsm = 0; @@ -236,38 +245,38 @@ MPU401_Reset(mpu_t *mpu) 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.freq_mod = 1.0; mpu->clock.tempo_grad = 0; - MPU401_StopClock(mpu); - MPU401_ReCalcClock(mpu); - - for (i = 0; i < 4; i++) - 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; + MPU401_StopClock(mpu); + MPU401_ReCalcClock(mpu); - /*reset channel reference and input tables*/ - for (i = 0; i < 4; i++) { + for (i = 0; i < 4; i++) + 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; + + /* 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; - } - - for (i = 0; i < 16; i++) { + } + + for (i = 0; i < 16; 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; @@ -276,19 +285,19 @@ MPU401_Reset(mpu_t *mpu) mpu->condbuf.counter = 0; mpu->condbuf.type = T_OVERFLOW; - for (i=0;i<8;i++) { + for (i = 0; i < 8; i++) { mpu->playbuf[i].type = T_OVERFLOW; mpu->playbuf[i].counter = 0; } - - /*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); - } + + /* 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); + } } @@ -313,16 +322,21 @@ MPU401_ResetDone(void *priv) static void MPU401_WriteCommand(mpu_t *mpu, uint8_t val) { - uint8_t i, j, was_uart; + uint8_t i, j, was_uart, recmsg[3]; if (mpu->state.reset) mpu->state.cmd_pending = val + 1; - if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent) - return; + /* The only command recognized in UART mode is 0xFF: Reset and return to Intelligent mode. */ + if ((val != 0xff) && (mpu->mode == M_UART)) + return; - /*hack:enable midi through after the first mpu401 command is written*/ - mpu->midi_thru = 1; + /* In Intelligent mode, UART-only variants of the MPU-401 only support commands 0x3F and 0xFF. */ + if ((val != 0x3f) && (val != 0xff) && !mpu->intelligent) + return; + + /* Hack: Enable midi through after the first mpu401 command is written. */ + mpu->midi_thru = 1; if (val <= 0x2f) { /* Sequencer state */ int send_prchg = 0; @@ -383,16 +397,17 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) return; case 0x20: /* Start */ if (!(mpu->state.rec == M_RECON)) { - mpu->clock.rec_counter = 0; - mpu->state.rec = M_RECSTB; + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECSTB; } if ((mpu->state.last_rtcmd == 0xfa) || (mpu->state.last_rtcmd == 0xfb)) { - mpu->clock.rec_counter = 0; - mpu->state.rec = M_RECON; - if (mpu->filter.prchg_mask) - send_prchg = 1; - MPU401_StartClock(mpu); + mpu->clock.rec_counter = 0; + mpu->state.rec = M_RECON; + if (mpu->filter.prchg_mask) + send_prchg = 1; + MPU401_StartClock(mpu); } + break; } } MPU401_QueueByte(mpu, MSG_MPU_ACK); @@ -401,21 +416,26 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) if (((val == 0x20) || (val == 0x26)) && (mpu->state.rec == M_RECON)) MPU401_RecQueueBuffer(mpu, &rec_cnt, 1, 0); - if (send_prchg) for (i = 0; i < 16; i++) - if (mpu->filter.prchg_mask & (1 << i)) { - uint8_t recmsg[3] = {mpu->clock.rec_counter, 0xc0 | i, mpu->filter.prchg_buf[i]}; - MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); - mpu->filter.prchg_mask &= ~(1 << i); + if (send_prchg) { + for (i = 0; i < 16; i++) { + if (mpu->filter.prchg_mask & (1 << i)) { + recmsg[0] = mpu->clock.rec_counter; + recmsg[1] = 0xc0 | i; + recmsg[2] = mpu->filter.prchg_buf[i]; + MPU401_RecQueueBuffer(mpu, recmsg, 3, 0); + mpu->filter.prchg_mask &= ~(1 << i); + } + } } - } else if ((val >= 0xa0) && (val <= 0xa7)) { /* Request play counter */ + } 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 */ + else if ((val >= 0xd0) && (val <= 0xd7)) { /* Send data */ mpu->state.old_track = mpu->state.track; mpu->state.track= val & 7; mpu->state.wsd = 1; mpu->state.wsm = 0; mpu->state.wsd_start = 1; - } else if ((val < 0x80) && (val >= 0x40)) { /* Set reference table channel */ + } else if ((val < 0x80) && (val >= 0x40)) { /* Set reference table channel */ mpu->chanref[(val >> 4) - 4].on = 1; mpu->chanref[(val >> 4) - 4].chan = val & 0x0f; mpu->chanref[(val >> 4) - 4].trmask = 0; @@ -438,9 +458,9 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->filter.commonmsgs_thru = 0; mpu->filter.midi_thru = 0; for (i = 0; i < 16; i++) { - mpu->inputref[i].on = 0; - for (j = 0; i < 4; j++) - mpu->inputref[i].key[j] = 0; + mpu->inputref[i].on = 0; + for (j = 0; i < 4; j++) + mpu->inputref[i].key[j] = 0; } break; case 0x34: @@ -459,7 +479,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->filter.rt_in = 1; break; case 0x3f: /* UART mode */ - mpu401_log("MPU-401:Set UART mode %X\n",val); + mpu401_log("MPU-401: Set UART mode %X\n",val); MPU401_QueueByte(mpu, MSG_MPU_ACK); mpu->mode = M_UART; return; @@ -481,11 +501,11 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) case 0x88: case 0x89: /* MIDI through */ mpu->filter.midi_thru = !!(val & 1); for (i = 0; i < 16; i++) { - mpu->inputref[i].on = mpu->filter.midi_thru; - if (!(val & 1)) { - for (j = 0; j < 4; j++) - mpu->inputref[i].key[j] = 0; - } + mpu->inputref[i].on = mpu->filter.midi_thru; + if (!(val & 1)) { + for (j = 0; j < 4; j++) + mpu->inputref[i].key[j] = 0; + } } break; case 0x8a: case 0x8b: /* Data in stop */ @@ -581,7 +601,7 @@ MPU401_WriteCommand(mpu_t *mpu, uint8_t val) mpu->state.command_byte = val; break; case 0xff: /* Reset MPU-401 */ - mpu401_log("MPU-401:Reset %X\n",val); + mpu401_log("MPU-401: Reset %X\n", val); timer_set_delay_u64(&mpu->mpu401_reset_callback, MPU401_RESETBUSY * 33LL * TIMER_USEC); mpu->state.reset = 1; was_uart = (mpu->mode == M_UART); @@ -1028,6 +1048,21 @@ imf_write(uint16_t addr, uint8_t val, void *priv) } +void +MPU401_ReadRaiseIRQ(mpu_t *mpu) +{ + /* Clear IRQ. */ + picintc(1 << mpu->irq); + mpu->state.irq_pending = 0; + + if (mpu->queue_used) { + /* Bytes remaining in queue, raise IRQ again. */ + mpu->state.irq_pending = 1; + picint(1 << mpu->irq); + } +} + + uint8_t MPU401_ReadData(mpu_t *mpu) { @@ -1045,35 +1080,28 @@ MPU401_ReadData(mpu_t *mpu) /* Shouldn't this check mpu->mode? */ if (mpu->mode == M_UART) { - if (mpu->state.irq_pending) { - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; - } - + MPU401_ReadRaiseIRQ(mpu); return ret; } - if (mpu->state.rec_copy && !mpu->rec_queue_used) { + 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) { + /* 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--; - } - - if (mpu->queue_used == 0) { - picintc(1 << mpu->irq); - mpu->state.irq_pending = 0; } + MPU401_ReadRaiseIRQ(mpu); + if ((ret >= 0xf0) && (ret <= 0xf7)) { /* MIDI data request */ mpu->state.track = ret & 7; @@ -1094,11 +1122,10 @@ MPU401_ReadData(mpu_t *mpu) } } - if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK) || (ret == MSG_MPU_OVERFLOW)) { + if ((ret == MSG_MPU_END) || (ret == MSG_MPU_CLOCK) || (ret == MSG_MPU_ACK) || (ret == MSG_MPU_OVERFLOW)) MPU401_EOIHandlerDispatch(mpu); - } - return(ret); + return ret; } @@ -1135,8 +1162,10 @@ 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; + if (mpu->state.cmd_pending) + ret = STATUS_OUTPUT_NOT_READY; + if (!mpu->queue_used) + ret = STATUS_INPUT_NOT_READY; ret |= 0x3f; mpu401_log("Read Status (0x331) %x\n", ret); @@ -1153,6 +1182,7 @@ MPU401_Event(void *priv) { mpu_t *mpu = (mpu_t *)priv; uint8_t i; + int max_meascnt; mpu401_log("MPU-401 event callback\n"); @@ -1163,22 +1193,24 @@ MPU401_Event(void *priv) if (mpu->state.irq_pending) goto next_event; - if (mpu->state.playing) { - for (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.playing) { + for (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.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++; @@ -1189,108 +1221,108 @@ MPU401_Event(void *priv) } } - 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.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)) { - 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.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 (!mpu->state.irq_pending && mpu->state.req_mask) { + } + 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++; + MPU401_RunClock(mpu); + if (mpu->state.sync_in) + mpu->clock.ticks_in++; } + static void MPU401_NotesOff(mpu_t *mpu, int i) { - int j; - uint8_t key; - - 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 (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 (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; + int j; + uint8_t key; + + 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 (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 (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 */ static int MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort) { - mpu_t *mpu = (mpu_t *)p; - - mpu401_log("MPU401 Input Sysex\n"); - - int i; - - if (mpu->filter.sysex_in) { - if (abort) { - mpu->state.sysex_in_finished=1; - mpu->rec_queue_used=0;/*reset also the input queue*/ - return 0; - } - if (mpu->state.sysex_in_finished) { - if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) - return len; - uint8_t val_ff=0xff; - MPU401_RecQueueBuffer(mpu,&val_ff,1,1); - mpu->state.sysex_in_finished=0; - mpu->clock.rec_counter=0; - } + mpu_t *mpu = (mpu_t *)p; + int i; + uint8_t val_ff = 0xff; + + mpu401_log("MPU401 Input Sysex\n"); + + if (mpu->filter.sysex_in) { + if (abort) { + mpu->state.sysex_in_finished=1; + mpu->rec_queue_used=0;/*reset also the input queue*/ + return 0; + } + if (mpu->state.sysex_in_finished) { if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) return len; - int available=MPU401_INPUT_QUEUE-mpu->rec_queue_used; + MPU401_RecQueueBuffer(mpu, &val_ff, 1, 1); + mpu->state.sysex_in_finished=0; + mpu->clock.rec_counter=0; + } + if (mpu->rec_queue_used>=MPU401_INPUT_QUEUE) + return len; + int available = MPU401_INPUT_QUEUE - mpu->rec_queue_used; - if (available>=len) { - MPU401_RecQueueBuffer(mpu,buffer,len,1); + if (available >= len) { + MPU401_RecQueueBuffer(mpu, buffer, len, 1); + return 0; + } else { + MPU401_RecQueueBuffer(mpu,buffer, available, 1); + if (mpu->state.sysex_in_finished) return 0; - } - else { - MPU401_RecQueueBuffer(mpu,buffer,available,1); - if (mpu->state.sysex_in_finished) - return 0; - return (len-available); - } + return (len - available); } - else if (mpu->filter.sysex_thru && mpu->midi_thru) { - midi_raw_out_byte(0xf0); - for (i=0;ifilter.sysex_thru && mpu->midi_thru) { + midi_raw_out_byte(0xf0); + for (i = 0; i < len; i++) + midi_raw_out_byte(*(buffer+i)); + } + return 0; } @@ -1298,203 +1330,222 @@ MPU401_InputSysex(void *p, uint8_t *buffer, uint32_t len, int abort) static void MPU401_InputMsg(void *p, uint8_t *msg) { - mpu_t *mpu = (mpu_t *)p; + mpu_t *mpu = (mpu_t *)p; + int i, tick; + static uint8_t old_msg = 0; + uint8_t len = msg[3], key; + uint8_t recdata[2], recmsg[4]; + int send = 1, send_thru = 0; + int retrigger_thru = 0, midistatus = 0, chan, chrefnum; - /*abort if sysex transfer is in progress*/ - if (!mpu->state.sysex_in_finished) { - mpu401_log("SYSEX in progress\n"); - return; + /* Abort if sysex transfer is in progress. */ + if (!mpu->state.sysex_in_finished) { + mpu401_log("SYSEX in progress\n"); + return; + } + + mpu401_log("MPU401 Input Msg\n"); + + if (mpu->mode == M_INTELLIGENT) { + if (msg[0] < 0x80) { + /* Expand running status */ + midistatus = 1; + msg[2] = msg[1]; + msg[1] = msg[0]; + msg[0] = old_msg; } - - mpu401_log("MPU401 Input Msg\n"); - - int i; - static uint8_t old_msg=0; - uint8_t len=msg[3]; - int send=1; - int send_thru=0; - int retrigger_thru=0; - int midistatus=0; - if (mpu->mode==M_INTELLIGENT) { - if (msg[0]<0x80) { /* Expand running status */ - midistatus=1; - msg[2]=msg[1];msg[1]=msg[0];msg[0]=old_msg; - } - old_msg=msg[0]; - int chan=msg[0]&0xf; - int chrefnum=mpu->ch_toref[chan]; - uint8_t key=msg[1]&0x7f; - if (msg[0]<0xf0) { //if non-system msg - if (!(mpu->state.midi_mask&(1<filter.all_thru) - send_thru=1; - else if (mpu->filter.midi_thru) - send_thru=1; - switch (msg[0]&0xf0) { - case 0x80: /*note off*/ - if (send_thru) { - if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) - send_thru=0; - if (!mpu->filter.midi_thru) - break; - if (!(mpu->inputref[chan].M_GETKEY)) - send_thru=0; - mpu->inputref[chan].M_DELKEY; - } - break; - case 0x90: /*note on*/ - if (send_thru) { - if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) - retrigger_thru=1; - if (!mpu->filter.midi_thru) - break; - if (mpu->inputref[chan].M_GETKEY) - retrigger_thru=1; - mpu->inputref[chan].M_SETKEY; - } - break; - case 0xb0: - if (msg[1]>=120) { - send_thru=0; - if (msg[1]==123) { /* All notes off */ - for (key=0;key<128;key++) { - if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) - if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) { - midi_raw_out_byte(0x80|chan); - midi_raw_out_byte(key); - midi_raw_out_byte(0); - } + old_msg = msg[0]; + chan = msg[0] & 0xf; + chrefnum = mpu->ch_toref[chan]; + key = msg[1] & 0x7f; + if (msg[0] < 0xf0) { + /* If non-system msg. */ + if (!(mpu->state.midi_mask & (1 << chan)) && mpu->filter.all_thru) + send_thru = 1; + else if (mpu->filter.midi_thru) + send_thru = 1; + switch (msg[0] & 0xf0) { + case 0x80: /* Note off. */ + if (send_thru) { + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) + send_thru = 0; + if (!mpu->filter.midi_thru) + break; + if (!(mpu->inputref[chan].M_GETKEY)) + send_thru = 0; + mpu->inputref[chan].M_DELKEY; + } + break; + case 0x90: /* Note on. */ + if (send_thru) { + if (mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY)) + retrigger_thru = 1; + if (!mpu->filter.midi_thru) + break; + if (mpu->inputref[chan].M_GETKEY) + retrigger_thru = 1; + mpu->inputref[chan].M_SETKEY; + } + break; + case 0xb0: + if (msg[1] >= 120) { + send_thru = 0; + if (msg[1] == 123) { + /* All notes off. */ + for (key = 0; key < 128; key++) { + if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) + if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) { + midi_raw_out_byte(0x80 | chan); + midi_raw_out_byte(key); + midi_raw_out_byte(0); + } mpu->inputref[chan].M_DELKEY; } } } break; - } + } } - if (msg[0]>=0xf0 || (mpu->state.midi_mask&(1<filter.bender_in) - send=0; - break; - case 0xb0: /*control change*/ - if (!mpu->filter.bender_in && msg[1]<64) - send=0; - if (msg[1]>=120) { - if (mpu->filter.modemsgs_in) - send=1; - } - break; - case 0xc0: /*program change*/ - if ((mpu->state.rec!=M_RECON) && !mpu->filter.data_in_stop) { - mpu->filter.prchg_buf[chan]=msg[1]; - mpu->filter.prchg_mask|=1<filter.bender_in) - send=0; - break; - case 0xf0: //system message - if (msg[0]==0xf8) { - send=0; - if (mpu->clock.active && mpu->state.sync_in) { - send = 0;/*don't pass to host in this mode?*/ - int tick=mpu->clock.timebase/24; - if (mpu->clock.ticks_in!=tick) { - if (!mpu->clock.ticks_in || (mpu->clock.ticks_in>tick*2)) - mpu->clock.freq_mod*=2.0; - else { - if (ABS(mpu->clock.ticks_in-tick)==1) - mpu->clock.freq_mod/=mpu->clock.ticks_in/(float)(tick*2); - else - mpu->clock.freq_mod/=mpu->clock.ticks_in/(float)(tick); - } - MPU401_ReCalcClock(mpu); + } + if ((msg[0] >= 0xf0) || (mpu->state.midi_mask & (1 << chan))) { + switch (msg[0] & 0xf0) { + case 0xa0: /* Aftertouch. */ + if (!mpu->filter.bender_in) + send = 0; + break; + case 0xb0: /* Control change. */ + if (!mpu->filter.bender_in && (msg[1] < 64)) + send = 0; + if (msg[1] >= 120) { + if (mpu->filter.modemsgs_in) + send = 1; + } + break; + case 0xc0: /* Program change. */ + if ((mpu->state.rec != M_RECON) && !mpu->filter.data_in_stop) { + mpu->filter.prchg_buf[chan] = msg[1]; + mpu->filter.prchg_mask |= 1 << chan; + } + break; + case 0xd0: /* Ch pressure. */ + case 0xe0: /* Pitch wheel. */ + if (!mpu->filter.bender_in) + send = 0; + break; + case 0xf0: /* System message. */ + if (msg[0] == 0xf8) { + send = 0; + if (mpu->clock.active && mpu->state.sync_in) { + send = 0; /* Don't pass to host in this mode? */ + tick = mpu->clock.timebase / 24; + if (mpu->clock.ticks_in != tick) { + if (!mpu->clock.ticks_in || (mpu->clock.ticks_in > (tick * 2))) + mpu->clock.freq_mod *= 2.0; + else { + if (ABS(mpu->clock.ticks_in-tick) == 1) + mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick * 2); + else + mpu->clock.freq_mod /= mpu->clock.ticks_in / (float) (tick); } - mpu->clock.ticks_in=0; + MPU401_ReCalcClock(mpu); } + mpu->clock.ticks_in = 0; } - else if (msg[0]>0xf8) { /*realtime*/ - if (!(mpu->filter.rt_in && msg[0]<=0xfc && msg[0]>=0xfa)) { - uint8_t recdata[2]={0xff,msg[0]}; - MPU401_RecQueueBuffer(mpu,recdata,2,1); - send=0; - } + } else if (msg[0] > 0xf8) { /* Realtime. */ + if (!(mpu->filter.rt_in && (msg[0] <= 0xfc) && (msg[0] >= 0xfa))) { + recdata[0] = 0xff; + recdata[1] = msg[0]; + MPU401_RecQueueBuffer(mpu, recdata, 2, 1); + send = 0; } - else { /*common or system*/ - send=0; - if (msg[0]==0xf2 || msg[0]==0xf3 || msg[0]==0xf6) { - if (mpu->filter.commonmsgs_in) - send=1; - if (mpu->filter.commonmsgs_thru) - for (i=0;ifilter.commonmsgs_in) + send = 1; + if (mpu->filter.commonmsgs_thru) + for (i = 0; i < len; i++) + midi_raw_out_byte(msg[i]); } - if (send) { - uint8_t recmsg[4]={0xff,msg[0],msg[1],msg[2]}; - MPU401_RecQueueBuffer(mpu,recmsg,len+1,1); - } - if (mpu->filter.rt_affection) switch(msg[0]) { - case 0xf2:case 0xf3: - mpu->state.block_ack=1; - MPU401_WriteCommand(mpu,0xb8);/*clear play counters*/ + } + if (send) { + recmsg[0] = 0xff; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + } + if (mpu->filter.rt_affection) { + switch(msg[0]) { + case 0xf2: case 0xf3: + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xb8); /* Clear play counters. */ break; case 0xfa: - mpu->state.block_ack=1; - MPU401_WriteCommand(mpu,0xa);/*start,play*/ + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xa); /* Start, play. */ if (mpu->filter.rt_out) midi_raw_out_rt_byte(msg[0]); break; case 0xfb: - mpu->state.block_ack=1; - MPU401_WriteCommand(mpu,0xb);/*continue,play*/ + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xb); /* Continue, play. */ if (mpu->filter.rt_out) midi_raw_out_rt_byte(msg[0]); break; case 0xfc: - mpu->state.block_ack=1; - MPU401_WriteCommand(mpu,0xd);/*stop: play,rec,midi*/ + mpu->state.block_ack = 1; + MPU401_WriteCommand(mpu, 0xd) ;/* Stop: Play, rec, midi */ if (mpu->filter.rt_out) midi_raw_out_rt_byte(msg[0]); break; } return; - } - if (send_thru && mpu->midi_thru) { - if (retrigger_thru) { - midi_raw_out_byte(0x80|(msg[0]&0xf)); - midi_raw_out_byte(msg[1]); - midi_raw_out_byte(msg[2]); - } - for (i=0/*((midistatus && !retrigger_thru)? 1:0)*/;istate.rec==M_RECON) { - uint8_t recmsg[4]={mpu->clock.rec_counter,msg[0],msg[1],msg[2]}; - MPU401_RecQueueBuffer(mpu,recmsg,len+1,1); - mpu->clock.rec_counter=0; - } - else if (mpu->filter.data_in_stop) { - if (mpu->filter.timing_in_stop) { - uint8_t recmsg[4]={0,msg[0],msg[1],msg[2]}; - MPU401_RecQueueBuffer(mpu,recmsg,len+1,1); - } - else { - uint8_t recmsg[4]={msg[0],msg[1],msg[2],0}; - MPU401_RecQueueBuffer(mpu,recmsg,len,1); - } + } + if (send_thru && mpu->midi_thru) { + if (retrigger_thru) { + midi_raw_out_byte(0x80 | (msg[0] & 0xf)); + midi_raw_out_byte(msg[1]); + midi_raw_out_byte(msg[2]); + } + for (i = 0; i < len; i++) + midi_raw_out_byte(msg[i]); + } + if (send) { + if (mpu->state.rec == M_RECON) { + recmsg[0] = mpu->clock.rec_counter; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + mpu->clock.rec_counter = 0; + } + else if (mpu->filter.data_in_stop) { + if (mpu->filter.timing_in_stop) { + recmsg[0] = 0; + recmsg[1] = msg[0]; + recmsg[2] = msg[1]; + recmsg[3] = msg[2]; + MPU401_RecQueueBuffer(mpu, recmsg, len + 1, 1); + } else { + recmsg[0] = msg[0]; + recmsg[1] = msg[1]; + recmsg[2] = msg[2]; + recmsg[3] = 0; + MPU401_RecQueueBuffer(mpu, recmsg, len, 1); } } - return; - } - /*UART mode input*/ - for (i=0;iirq); } + return; + } + + /* UART mode input. */ + for (i = 0; i < len; i++) { + MPU401_QueueByte(mpu, msg[i]); + picint(1 << mpu->irq); + } } @@ -1530,7 +1581,8 @@ mpu401_init(mpu_t *mpu, uint16_t addr, int irq, int mode) void mpu401_device_add(void) { - if (!mpu401_standalone_enable) return; + if (!mpu401_standalone_enable) + return; if (machines[machine].flags & MACHINE_MCA) device_add(&mpu401_mca_device); From bb4e4e10c3875185062d47ad4a3ff48d18e7aa1b Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 8 Jan 2020 17:11:13 +0100 Subject: [PATCH 04/10] Added Gravis Ultrasound MIDI Input. --- src/sound/snd_gus.c | 287 +++++++++++++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 99 deletions(-) diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 46bd3408d..05840a7f6 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -13,6 +13,7 @@ #include "../timer.h" #include "../device.h" #include "sound.h" +#include "midi.h" #include "snd_gus.h" @@ -68,9 +69,9 @@ typedef struct gus_t uint8_t ad_status, ad_data; uint8_t ad_timer_ctrl; - uint8_t midi_ctrl, midi_status; - uint8_t midi_data; - int midi_loopback; + uint8_t uart_queue[64]; + int uart_pos, uart_used; + int uart_in, uart_out, sysex; uint8_t gp1, gp2; uint16_t gp1_addr, gp2_addr; @@ -79,7 +80,6 @@ typedef struct gus_t } gus_t; static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; -static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; int gusfreqs[]= @@ -144,68 +144,45 @@ enum GUS_TIMER_CTRL_AUTO = 0x01 }; -void gus_midi_update_int_status(gus_t *gus) -{ - gus->midi_status &= ~MIDI_INT_MASTER; - if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) - { - gus->midi_status |= MIDI_INT_MASTER; - gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; - } - else - gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; - - if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) - { - gus->midi_status |= MIDI_INT_MASTER; - gus->irqstatus |= GUS_INT_MIDI_RECEIVE; - } - else - gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; - if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) - { - picint(1 << gus->irq_midi); - } -} - void writegus(uint16_t addr, uint8_t val, void *p) { gus_t *gus = (gus_t *)p; int c, d; int old; - if (gus->latch_enable && addr != 0x24b) - gus->latch_enable = 0; switch (addr) { case 0x340: /*MIDI control*/ - old = gus->midi_ctrl; - gus->midi_ctrl = val; - - if ((val & 3) == 3) - gus->midi_status = 0; - else if ((old & 3) == 3) - { - gus->midi_status |= MIDI_INT_TRANSMIT; - } - gus_midi_update_int_status(gus); + gus->uart_out = 1; + if (val == 3 || !val) { + gus->uart_in = 0; + gus->irqstatus &= ~0x03; + gus->uart_used = 0; + return; + } + + if (val & 0x20) { + gus->irqstatus |= 0x01; + } else { + gus->irqstatus &= ~0x01; + } + + if (val & 0x80) + gus->uart_in = 1; + else + gus->uart_in = 0; break; - case 0x341: /*MIDI data*/ - if (gus->midi_loopback) - { - gus->midi_status |= MIDI_INT_RECEIVE; - gus->midi_data = val; + if (gus->uart_out) { + midi_raw_out_byte(val); + picint(1 << gus->irq_midi); } - else - gus->midi_status |= MIDI_INT_TRANSMIT; break; - case 0x342: /*Voice select*/ - gus->voice=val&31; + gus->voice = val & 31; break; case 0x343: /*Global select*/ - gus->global=val; + gus->global = val; break; case 0x344: /*Global low*/ switch (gus->global) @@ -231,11 +208,11 @@ void writegus(uint16_t addr, uint8_t val, void *p) gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; break; - case 0x6: /*Ramp frequency*/ + case 6: /*Ramp frequency*/ gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); break; - case 0x9: /*Current volume*/ + case 9: /*Current volume*/ gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); break; @@ -263,10 +240,6 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); switch (gus->global) { case 0: /*Voice control*/ - if (!(val&1) && gus->ctrl[gus->voice]&1) - { - } - gus->ctrl[gus->voice] = val & 0x7f; old = gus->waveirqs[gus->voice]; @@ -294,16 +267,16 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); break; - case 0x6: /*Ramp frequency*/ + case 6: /*Ramp frequency*/ gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); break; - case 0x7: /*Ramp start*/ + case 7: /*Ramp start*/ gus->rstart[gus->voice] = val << 14; break; - case 0x8: /*Ramp end*/ + case 8: /*Ramp end*/ gus->rend[gus->voice] = val << 14; break; - case 0x9: /*Current volume*/ + case 9: /*Current volume*/ gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); break; @@ -494,33 +467,75 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); break; case 0x240: - gus->midi_loopback = val & 0x20; - gus->latch_enable = (val & 0x40) ? 2 : 1; + gus->latch_enable = val; break; case 0x24b: switch (gus->reg_ctrl & 0x07) { case 0: - if (gus->latch_enable == 1) - gus->dma = gus_dmas[val & 7]; - if (gus->latch_enable == 2) - { - gus->irq = gus_irqs[val & 7]; - - if (val & 0x40) - { - if (gus->irq == -1) - gus->irq = gus->irq_midi = gus_irqs[(val >> 3) & 7]; - else - gus->irq_midi = gus->irq; - } - else - gus->irq_midi = gus_irqs_midi[(val >> 3) & 7]; - - gus->sb_nmi = val & 0x80; - } - gus->latch_enable = 0; + if (gus->latch_enable & 0x40) { + // GUS SDK: IRQ Control Register + // Channel 1 GF1 IRQ selector (bits 2-0) + // 0=reserved, do not use + // 1=IRQ2 + // 2=IRQ5 + // 3=IRQ3 + // 4=IRQ7 + // 5=IRQ11 + // 6=IRQ12 + // 7=IRQ15 + // Channel 2 MIDI IRQ selector (bits 5-3) + // 0=no interrupt + // 1=IRQ2 + // 2=IRQ5 + // 3=IRQ3 + // 4=IRQ7 + // 5=IRQ11 + // 6=IRQ12 + // 7=IRQ15 + // Combine both IRQs using channel 1 (bit 6) + // Reserved (bit 7) + // + // "If both channels are sharing an IRQ, channel 2's IRQ must be set to 0 and turn on bit 6. A + // bus conflict will occur if both latches are programmed with the same IRQ #." + if (gus_irqs[val & 7] != -1) + gus->irq = gus_irqs[val & 7]; + + if (val & 0x40) // "Combine both IRQs" + gus->irq_midi = gus->irq; + else + gus->irq_midi = gus_irqs[(val >> 3) & 7]; + + gus->sb_nmi = val & 0x80; + } else { + // GUS SDK: DMA Control Register + // Channel 1 (bits 2-0) + // 0=NO DMA + // 1=DMA1 + // 2=DMA3 + // 3=DMA5 + // 4=DMA6 + // 5=DMA7 + // 6=? + // 7=? + // Channel 2 (bits 5-3) + // 0=NO DMA + // 1=DMA1 + // 2=DMA3 + // 3=DMA5 + // 4=DMA6 + // 5=DMA7 + // 6=? + // 7=? + // Combine both DMA channels using channel 1 (bit 6) + // Reserved (bit 7) + // + // "If both channels are sharing an DMA, channel 2's DMA must be set to 0 and turn on bit 6. A + // bus conflict will occur if both latches are programmed with the same DMA #." + if (gus_dmas[val & 7] != -1) + gus->dma = gus_dmas[val & 7]; + } break; case 1: gus->gp1 = val; @@ -543,13 +558,12 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); break; case 0x246: - gus->ad_status |= 0x08; - if (gus->sb_ctrl & 0x20) - { + if (gus->sb_ctrl & 0x20) { + gus->ad_status |= 0x08; if (gus->sb_nmi) - nmi = 1; + nmi = 1; else if (gus->irq != -1) - picint(1 << gus->irq); + picint(1 << gus->irq); } break; case 0x24a: @@ -583,26 +597,49 @@ uint8_t readgus(uint16_t addr, void *p) switch (addr) { case 0x340: /*MIDI status*/ - val = gus->midi_status; + val = ((gus->irqstatus & 0x03 ? 0x80 : 0) | + (gus->uart_in && gus->uart_used >= 64 ? 0x20:0) | + ((gus->uart_used && gus->uart_in) ? 1 : 0) | (gus->uart_out ? 2 : 0)); break; case 0x341: /*MIDI data*/ - val = gus->midi_data; - gus->midi_status &= ~MIDI_INT_RECEIVE; - gus_midi_update_int_status(gus); + val = 0; + if (gus->uart_in) { + if (gus->uart_used) { + if (gus->uart_pos >= 64) + gus->uart_pos -= 64; + val = gus->uart_queue[gus->uart_pos]; + gus->uart_pos++; + gus->uart_used--; + } + if (!gus->uart_used) + gus->irqstatus &= ~0x02; + } break; - case 0x240: return 0; - case 0x246: /*IRQ status*/ + case 0x240: + val = 0xff; + break; + + case 0x246: /*IRQ status*/ val = gus->irqstatus & ~0x10; if (gus->ad_status & 0x19) val |= 0x10; - return val; + break; - case 0x24F: return 0; - case 0x342: return gus->voice; - case 0x343: return gus->global; - case 0x344: /*Global low*/ + case 0x24F: + val = 0; + break; + + case 0x342: + val = gus->voice; + break; + + case 0x343: + val = gus->global; + break; + + case 0x344: /*Global low*/ switch (gus->global) { case 0x82: /*Start addr high*/ @@ -770,7 +807,6 @@ void gus_poll_timer_1(void *p) if (gus->irq != -1) picint(1 << gus->irq); } - gus_midi_update_int_status(gus); } void gus_poll_timer_2(void *p) @@ -998,6 +1034,55 @@ static void gus_get_buffer(int32_t *buffer, int len, void *p) gus->pos = 0; } +static void gus_queue(gus_t *gus, uint8_t val) +{ + int pos; + + if (gus->uart_used < 64) { + pos = gus->uart_used + gus->uart_pos; + if (pos >= 64) + pos -= 64; + gus->uart_queue[pos] = val; + gus->uart_used++; + } +} + +static void gus_input_msg(void *p, uint8_t *msg) +{ + gus_t *gus = (gus_t *)p; + uint8_t i; + + if (gus->sysex) + return; + + if (gus->uart_in) { + gus->irqstatus |= 0x02; + for (i=0;iirq_midi); + } +} + +static int gus_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) +{ + gus_t *gus = (gus_t *)p; + uint32_t i; + + if (abort) { + gus->uart_used = 0; + gus->sysex = 0; + return 0; + } + gus->sysex = 1; + for (i=0;iuart_used >= 64) { + return (len-i); + } + gus_queue(gus, buffer[i]); + } + gus->sysex = 0; + return 0; +} void *gus_init(const device_t *info) { @@ -1026,7 +1111,7 @@ void *gus_init(const device_t *info) gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); gus->t1l = gus->t2l = 0xff; - + io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); @@ -1037,6 +1122,10 @@ void *gus_init(const device_t *info) sound_add_handler(gus_get_buffer, gus); + input_msg = gus_input_msg; + input_sysex = gus_input_sysex; + midi_in_p = gus; + return gus; } From 3bdec705e574ff28033c3f673f7bf28b4e777658 Mon Sep 17 00:00:00 2001 From: Altheos Date: Wed, 8 Jan 2020 17:49:06 +0100 Subject: [PATCH 05/10] GUS soundcard improvements : IO address flexibility 256kb, 512kb or 1Mb total memory variant --- src/sound/snd_gus.c | 247 ++++++++++++++++++++++++++++------------- src/win/86Box.rc | 6 +- src/win/resource.h | 4 +- src/win/win_settings.c | 19 +++- 4 files changed, 195 insertions(+), 81 deletions(-) diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 46bd3408d..235bd9ca9 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -15,6 +15,36 @@ #include "sound.h" #include "snd_gus.h" +enum +{ + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 +}; + +enum +{ + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 +}; + +enum +{ + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 +}; + +enum +{ + GUS_TIMER_CTRL_AUTO = 0x01 +}; + +enum +{ + GUS_CLASSIC = 0, + GUS_MAX = 1, +}; typedef struct gus_t { @@ -51,12 +81,14 @@ typedef struct gus_t uint64_t samp_latch; uint8_t *ram; + uint32_t gus_end_ram; int irqnext; pc_timer_t timer_1, timer_2; int irq, dma, irq_midi; + uint16_t base; int latch_enable; uint8_t sb_2xa, sb_2xc, sb_2xe; @@ -119,31 +151,6 @@ void pollgusirqs(gus_t *gus) if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); } -enum -{ - MIDI_INT_RECEIVE = 0x01, - MIDI_INT_TRANSMIT = 0x02, - MIDI_INT_MASTER = 0x80 -}; - -enum -{ - MIDI_CTRL_TRANSMIT_MASK = 0x60, - MIDI_CTRL_TRANSMIT = 0x20, - MIDI_CTRL_RECEIVE = 0x80 -}; - -enum -{ - GUS_INT_MIDI_TRANSMIT = 0x01, - GUS_INT_MIDI_RECEIVE = 0x02 -}; - -enum -{ - GUS_TIMER_CTRL_AUTO = 0x01 -}; - void gus_midi_update_int_status(gus_t *gus) { gus->midi_status &= ~MIDI_INT_MASTER; @@ -174,11 +181,19 @@ void writegus(uint16_t addr, uint8_t val, void *p) gus_t *gus = (gus_t *)p; int c, d; int old; - if (gus->latch_enable && addr != 0x24b) + uint16_t port; + + if ((addr == 0x388) || (addr == 0x389)) + port = addr; + else + port = addr & 0xf0f; + + if (gus->latch_enable && port != 0x20b) gus->latch_enable = 0; - switch (addr) + + switch (port) { - case 0x340: /*MIDI control*/ + case 0x300: /*MIDI control*/ old = gus->midi_ctrl; gus->midi_ctrl = val; @@ -191,7 +206,7 @@ void writegus(uint16_t addr, uint8_t val, void *p) gus_midi_update_int_status(gus); break; - case 0x341: /*MIDI data*/ + case 0x301: /*MIDI data*/ if (gus->midi_loopback) { gus->midi_status |= MIDI_INT_RECEIVE; @@ -201,13 +216,13 @@ void writegus(uint16_t addr, uint8_t val, void *p) gus->midi_status |= MIDI_INT_TRANSMIT; break; - case 0x342: /*Voice select*/ + case 0x302: /*Voice select*/ gus->voice=val&31; break; - case 0x343: /*Global select*/ + case 0x303: /*Global select*/ gus->global=val; break; - case 0x344: /*Global low*/ + case 0x304: /*Global low*/ switch (gus->global) { case 0: /*Voice control*/ @@ -259,7 +274,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); break; } break; - case 0x345: /*Global high*/ + case 0x305: /*Global high*/ switch (gus->global) { case 0: /*Voice control*/ @@ -449,11 +464,12 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); break; } break; - case 0x347: /*DRAM access*/ - gus->ram[gus->addr]=val; + case 0x307: /*DRAM access*/ gus->addr&=0xFFFFF; + if (gus->addr < gus->gus_end_ram) + gus->ram[gus->addr]=val; break; - case 0x248: case 0x388: + case 0x208: case 0x388: gus->adcommand = val; break; @@ -493,12 +509,12 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); } break; - case 0x240: + case 0x200: gus->midi_loopback = val & 0x20; gus->latch_enable = (val & 0x40) ? 2 : 1; break; - case 0x24b: + case 0x20b: switch (gus->reg_ctrl & 0x07) { case 0: @@ -542,7 +558,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); } break; - case 0x246: + case 0x206: gus->ad_status |= 0x08; if (gus->sb_ctrl & 0x20) { @@ -552,10 +568,10 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); picint(1 << gus->irq); } break; - case 0x24a: + case 0x20a: gus->sb_2xa = val; break; - case 0x24c: + case 0x20c: gus->ad_status |= 0x10; if (gus->sb_ctrl & 0x20) { @@ -564,45 +580,53 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); else if (gus->irq != -1) picint(1 << gus->irq); } - case 0x24d: + case 0x20d: gus->sb_2xc = val; break; - case 0x24e: + case 0x20e: gus->sb_2xe = val; break; - case 0x24f: + case 0x20f: gus->reg_ctrl = val; break; } } + uint8_t readgus(uint16_t addr, void *p) { gus_t *gus = (gus_t *)p; uint8_t val = 0xff; - switch (addr) + uint16_t port; + + if ((addr == 0x388) || (addr == 0x389)) + port = addr; + else + port = addr & 0xf0f; + + switch (port) { - case 0x340: /*MIDI status*/ + case 0x300: /*MIDI status*/ val = gus->midi_status; break; - case 0x341: /*MIDI data*/ + case 0x301: /*MIDI data*/ val = gus->midi_data; gus->midi_status &= ~MIDI_INT_RECEIVE; gus_midi_update_int_status(gus); break; - case 0x240: return 0; - case 0x246: /*IRQ status*/ + case 0x200: return 0; + case 0x206: /*IRQ status*/ val = gus->irqstatus & ~0x10; if (gus->ad_status & 0x19) val |= 0x10; return val; - case 0x24F: return 0; - case 0x342: return gus->voice; - case 0x343: return gus->global; - case 0x344: /*Global low*/ + case 0x20F: return 0; + case 0x302: return gus->voice; + case 0x303: return gus->global; + case 0x304: /*Global low*/ switch (gus->global) { case 0x82: /*Start addr high*/ @@ -632,7 +656,7 @@ uint8_t readgus(uint16_t addr, void *p) break; } break; - case 0x345: /*Global high*/ + case 0x305: /*Global high*/ switch (gus->global) { case 0x80: /*Voice control*/ @@ -681,16 +705,20 @@ uint8_t readgus(uint16_t addr, void *p) break; } break; - case 0x346: return 0xff; - case 0x347: /*DRAM access*/ + case 0x306: case 0x706: /*Revision level*/ + val = 0xff; + break; + case 0x307: /*DRAM access*/ val=gus->ram[gus->addr]; gus->addr&=0xFFFFF; - return val; - case 0x349: return 0; - case 0x746: /*Revision level*/ - return 0xff; /*Pre 3.7 - no mixer*/ + if (gus->addr < gus->gus_end_ram) + val = gus->ram[gus->addr]; + else + val = 0; + break; + case 0x309: return 0; - case 0x24b: + case 0x20b: switch (gus->reg_ctrl & 0x07) { case 1: @@ -708,15 +736,15 @@ uint8_t readgus(uint16_t addr, void *p) } break; - case 0x24c: + case 0x20c: val = gus->sb_2xc; if (gus->reg_ctrl & 0x20) gus->sb_2xc &= 0x80; break; - case 0x24e: + case 0x20e: return gus->sb_2xe; - case 0x248: case 0x388: + case 0x208: case 0x388: if (gus->tctrl & GUS_TIMER_CTRL_AUTO) val = gus->sb_2xa; else @@ -727,14 +755,14 @@ uint8_t readgus(uint16_t addr, void *p) } break; - case 0x249: + case 0x209: gus->ad_status &= ~0x01; nmi = 0; case 0x389: val = gus->ad_data; break; - case 0x24A: + case 0x20A: val = gus->adcommand; break; @@ -1003,11 +1031,13 @@ void *gus_init(const device_t *info) { int c; double out = 1.0; + uint8_t gus_ram = device_get_config_int("gus_ram"); gus_t *gus = malloc(sizeof(gus_t)); memset(gus, 0, sizeof(gus_t)); - gus->ram = malloc(1 << 20); - memset(gus->ram, 0, 1 << 20); + gus->gus_end_ram = 1 << (18 + gus_ram); + gus->ram = (uint8_t *)malloc(gus->gus_end_ram); + memset(gus->ram, 0x00, (gus->gus_end_ram)); for (c=0;c<32;c++) { @@ -1026,10 +1056,12 @@ void *gus_init(const device_t *info) gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / 44100.0)); gus->t1l = gus->t2l = 0xff; + + gus->base = device_get_config_hex16("base"); - io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); - io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0100+gus->base, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0506+gus->base, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); timer_add(&gus->samp_timer, gus_poll_wave, gus, 1); timer_add(&gus->timer_1, gus_poll_timer_1, gus, 1); @@ -1058,11 +1090,76 @@ void gus_speed_changed(void *p) gus->samp_latch = (uint64_t)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); } +static const device_config_t gus_config[] = { + { + "type", "GUS type", CONFIG_SELECTION, "", 0, + { + { + "Classic", GUS_CLASSIC + }, +#if 0 + { + "MAX", GUS_MAX + }, +#endif + { + NULL + } + }, + }, + { + "base", "Address", CONFIG_HEX16, "", 0x220, + { + { + "210H", 0x210 + }, + { + "220H", 0x220 + }, + { + "230H", 0x230 + }, + { + "240H", 0x240 + }, + { + "250H", 0x250 + }, + { + "260H", 0x260 + }, + }, + }, + { + "gus_ram", "Onboard RAM", CONFIG_SELECTION, "", 0, + { + { + "256 KB", 0 + }, + { + "512 KB", 1 + }, + { + "1 MB", 2 + }, + { + NULL + } + } + }, + { + "", "", -1 + } +}; + const device_t gus_device = { "Gravis UltraSound", - 0, 0, - gus_init, gus_close, NULL, NULL, - gus_speed_changed, NULL, - NULL + DEVICE_ISA, + 0, + gus_init, gus_close, NULL, + NULL, + gus_speed_changed, + NULL, + gus_config }; diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 43c2c0f7c..69d53a69a 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -395,9 +395,11 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,147,83,94,10 CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,101,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,81,46,12 + CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,147,101,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 END DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 diff --git a/src/win/resource.h b/src/win/resource.h index 49ba9679e..8e11ed62a 100644 --- a/src/win/resource.h +++ b/src/win/resource.h @@ -149,8 +149,8 @@ #define IDC_CHECK_MPU401 1076 #define IDC_CONFIGURE_MPU401 1077 #define IDC_CHECK_FLOAT 1078 -#define IDC_CHECK_GUSMAX 1079 -#define IDC_COMBO_MIDI_IN 1080 +#define IDC_CONFIGURE_GUS 1079 +#define IDC_COMBO_MIDI_IN 1080 #define IDC_COMBO_NET_TYPE 1090 /* network config */ #define IDC_COMBO_PCAP 1091 diff --git a/src/win/win_settings.c b/src/win/win_settings.c index 1a2605a07..f47f4f4b1 100644 --- a/src/win/win_settings.c +++ b/src/win/win_settings.c @@ -56,6 +56,7 @@ #include "../sound/sound.h" #include "../sound/midi.h" #include "../sound/snd_mpu401.h" +#include "../sound/snd_gus.h" #include "../video/video.h" #include "../video/vid_voodoo.h" #include "../plat.h" @@ -1117,7 +1118,6 @@ mpu401_standalone_allow(void) return 1; } - #if defined(__amd64__) || defined(__aarch64__) static LRESULT CALLBACK #else @@ -1245,7 +1245,10 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) h=GetDlgItem(hdlg, IDC_CHECK_GUS); SendMessage(h, BM_SETCHECK, temp_GUS, 0); - + + h = GetDlgItem(hdlg, IDC_CONFIGURE_GUS); + EnableWindow(h, (temp_GUS) ? TRUE : FALSE); + h=GetDlgItem(hdlg, IDC_CHECK_SSI); SendMessage(h, BM_SETCHECK, temp_SSI2001, 0); @@ -1345,6 +1348,18 @@ win_settings_sound_proc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) temp_deviceconfig |= deviceconfig_open(hdlg, (machines[temp_machine].flags & MACHINE_MCA) ? (void *)&mpu401_mca_device : (void *)&mpu401_device); break; + + case IDC_CHECK_GUS: + h = GetDlgItem(hdlg, IDC_CHECK_GUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CONFIGURE_GUS); + EnableWindow(h, temp_GUS ? TRUE : FALSE); + break; + + case IDC_CONFIGURE_GUS: + temp_deviceconfig |= deviceconfig_open(hdlg, (void *)&gus_device); + break; } return FALSE; From c524a62c4069e16e20b361845cb7351414118d15 Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 8 Jan 2020 19:01:24 +0100 Subject: [PATCH 06/10] Fixed an intance of undefined behavior in sb_mpu401.c. --- src/sound/snd_mpu401.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 5b4d2635b..03916ae3e 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -1216,7 +1216,8 @@ MPU401_Event(void *priv) 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->clock.cth_mode++; + mpu->clock.cth_mode %= 4; mpu->state.req_mask |= (1 << 13); } } From 04931767e78a42393b2ebcb6a7ebeffbf0d1bcec Mon Sep 17 00:00:00 2001 From: TC1995 Date: Wed, 8 Jan 2020 19:05:21 +0100 Subject: [PATCH 07/10] Fixed compile error. --- src/sound/snd_mpu401.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_mpu401.c b/src/sound/snd_mpu401.c index 03916ae3e..1ffc067f1 100644 --- a/src/sound/snd_mpu401.c +++ b/src/sound/snd_mpu401.c @@ -1394,7 +1394,7 @@ MPU401_InputMsg(void *p, uint8_t *msg) if (msg[1] == 123) { /* All notes off. */ for (key = 0; key < 128; key++) { - if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) + if (!(mpu->chanref[chrefnum].on && (mpu->chanref[chrefnum].M_GETKEY))) { if (mpu->inputref[chan].on && mpu->inputref[chan].M_GETKEY) { midi_raw_out_byte(0x80 | chan); midi_raw_out_byte(key); From 405030abd4a7f6da96012c5df169928219f721aa Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 10 Jan 2020 01:13:38 +0100 Subject: [PATCH 08/10] Made MIDI Input reset properly with midi data set to 0xaa (required by the GUS Installation MIDI IRQ tests) and initialize with data set to 0x00 when a master reset is not used (required by midi input from Sound Club). --- src/sound/snd_gus.c | 168 +++++++++++++++++++++++++------------------- 1 file changed, 95 insertions(+), 73 deletions(-) diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 05840a7f6..3fbbfa5e0 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -69,8 +69,8 @@ typedef struct gus_t uint8_t ad_status, ad_data; uint8_t ad_timer_ctrl; - uint8_t uart_queue[64]; - int uart_pos, uart_used; + uint8_t midi_ctrl, midi_status, midi_queue[64], midi_data; + int midi_r, midi_w; int uart_in, uart_out, sysex; uint8_t gp1, gp2; @@ -79,7 +79,8 @@ typedef struct gus_t uint8_t usrr; } gus_t; -static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_gf1_irqs[8] = {0, 2, 5, 3, 7, 11, 12, 15}; +static int gus_midi_irqs[8] = {0, 2, 5, 3, 7, 11, 12, 15}; static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; int gusfreqs[]= @@ -102,21 +103,24 @@ void pollgusirqs(gus_t *gus) gus->irqstatus2=0x60|c; if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; gus->irqstatus|=0x20; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); return; } if (gus->rampirqs[c]) { gus->irqstatus2=0xA0|c; gus->irqstatus|=0x40; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); return; } } gus->irqstatus2=0xE0; - if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); + if (!gus->irqstatus) { + if (gus->irq != 0) + picintc(1 << gus->irq); + } } enum @@ -144,6 +148,30 @@ enum GUS_TIMER_CTRL_AUTO = 0x01 }; +void gus_midi_update_int_status(gus_t *gus) +{ + gus->midi_status &= ~MIDI_INT_MASTER; + if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; + + if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_RECEIVE; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + + if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != 0)) + { + picint(1 << gus->irq_midi); + } +} void writegus(uint16_t addr, uint8_t val, void *p) { @@ -153,30 +181,30 @@ void writegus(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x340: /*MIDI control*/ + gus->midi_ctrl = val; gus->uart_out = 1; - if (val == 3 || !val) { + + if (((gus->midi_ctrl & 3) == 3) || !gus->midi_ctrl) { /*Master reset*/ gus->uart_in = 0; - gus->irqstatus &= ~0x03; - gus->uart_used = 0; - return; - } - - if (val & 0x20) { - gus->irqstatus |= 0x01; - } else { - gus->irqstatus &= ~0x01; - } - - if (val & 0x80) + gus->midi_status = 0; + gus->midi_r = 0; + gus->midi_w = 0; + } else if (gus->midi_ctrl & MIDI_CTRL_TRANSMIT) { + gus->midi_status |= MIDI_INT_TRANSMIT; + } else if (gus->midi_ctrl & MIDI_CTRL_RECEIVE) { gus->uart_in = 1; - else - gus->uart_in = 0; + } + gus_midi_update_int_status(gus); break; case 0x341: /*MIDI data*/ + gus->midi_data = val; if (gus->uart_out) { midi_raw_out_byte(val); - picint(1 << gus->irq_midi); } + if (gus->latch_enable & 0x20) { + gus->midi_status |= MIDI_INT_RECEIVE; + } else + gus->midi_status |= MIDI_INT_TRANSMIT; break; case 0x342: /*Voice select*/ gus->voice = val & 31; @@ -439,7 +467,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); { if (gus->sb_nmi) nmi = 1; - else if (gus->irq != -1) + else picint(1 << gus->irq); } } @@ -499,14 +527,14 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); // // "If both channels are sharing an IRQ, channel 2's IRQ must be set to 0 and turn on bit 6. A // bus conflict will occur if both latches are programmed with the same IRQ #." - if (gus_irqs[val & 7] != -1) - gus->irq = gus_irqs[val & 7]; - + if ((val & 7) != 0) + gus->irq = gus_gf1_irqs[val & 7]; + if (val & 0x40) // "Combine both IRQs" gus->irq_midi = gus->irq; else - gus->irq_midi = gus_irqs[(val >> 3) & 7]; - + gus->irq_midi = gus_midi_irqs[(val >> 3) & 7]; + gus->sb_nmi = val & 0x80; } else { // GUS SDK: DMA Control Register @@ -562,7 +590,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); gus->ad_status |= 0x08; if (gus->sb_nmi) nmi = 1; - else if (gus->irq != -1) + else if (gus->irq != 0) picint(1 << gus->irq); } break; @@ -575,7 +603,7 @@ gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); { if (gus->sb_nmi) nmi = 1; - else if (gus->irq != -1) + else if (gus->irq != 0) picint(1 << gus->irq); } case 0x24d: @@ -597,23 +625,23 @@ uint8_t readgus(uint16_t addr, void *p) switch (addr) { case 0x340: /*MIDI status*/ - val = ((gus->irqstatus & 0x03 ? 0x80 : 0) | - (gus->uart_in && gus->uart_used >= 64 ? 0x20:0) | - ((gus->uart_used && gus->uart_in) ? 1 : 0) | (gus->uart_out ? 2 : 0)); + val = gus->midi_status; break; case 0x341: /*MIDI data*/ val = 0; if (gus->uart_in) { - if (gus->uart_used) { - if (gus->uart_pos >= 64) - gus->uart_pos -= 64; - val = gus->uart_queue[gus->uart_pos]; - gus->uart_pos++; - gus->uart_used--; + if ((gus->midi_data == 0xaa) && (gus->midi_ctrl & MIDI_CTRL_RECEIVE)) /*Handle master reset*/ + val = gus->midi_data; + else { + val = gus->midi_queue[gus->midi_r]; + if (gus->midi_r != gus->midi_w) { + gus->midi_r++; + gus->midi_r &= 63; + } } - if (!gus->uart_used) - gus->irqstatus &= ~0x02; + gus->midi_status &= ~MIDI_INT_RECEIVE; + gus_midi_update_int_status(gus); } break; @@ -793,9 +821,9 @@ void gus_poll_timer_1(void *p) gus->ad_status |= 0x40; if (gus->tctrl&4) { - if (gus->irq != -1) - picint(1 << gus->irq); - gus->ad_status |= 0x04; + if (gus->irq != 0) + picint(1 << gus->irq); + gus->ad_status |= 0x04; gus->irqstatus |= 0x04; } } @@ -804,9 +832,11 @@ void gus_poll_timer_1(void *p) { gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); } + + gus_midi_update_int_status(gus); } void gus_poll_timer_2(void *p) @@ -823,8 +853,8 @@ void gus_poll_timer_2(void *p) gus->ad_status |= 0x20; if (gus->tctrl&8) { - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); gus->ad_status |= 0x02; gus->irqstatus |= 0x08; } @@ -834,8 +864,8 @@ void gus_poll_timer_2(void *p) { gus->irqnext=0; gus->irqstatus|=0x80; - if (gus->irq != -1) - picint(1 << gus->irq); + if (gus->irq != 0) + picint(1 << gus->irq); } } @@ -1034,19 +1064,6 @@ static void gus_get_buffer(int32_t *buffer, int len, void *p) gus->pos = 0; } -static void gus_queue(gus_t *gus, uint8_t val) -{ - int pos; - - if (gus->uart_used < 64) { - pos = gus->uart_used + gus->uart_pos; - if (pos >= 64) - pos -= 64; - gus->uart_queue[pos] = val; - gus->uart_used++; - } -} - static void gus_input_msg(void *p, uint8_t *msg) { gus_t *gus = (gus_t *)p; @@ -1056,10 +1073,14 @@ static void gus_input_msg(void *p, uint8_t *msg) return; if (gus->uart_in) { - gus->irqstatus |= 0x02; - for (i=0;iirq_midi); + gus->midi_status |= MIDI_INT_RECEIVE; + + for (i=0;imidi_queue[gus->midi_w++] = msg[i]; + gus->midi_w &= 63; + } + + gus_midi_update_int_status(gus); } } @@ -1069,16 +1090,15 @@ static int gus_input_sysex(void *p, uint8_t *buffer, uint32_t len, int abort) uint32_t i; if (abort) { - gus->uart_used = 0; gus->sysex = 0; return 0; } gus->sysex = 1; for (i=0;iuart_used >= 64) { + if (gus->midi_r == gus->midi_w) return (len-i); - } - gus_queue(gus, buffer[i]); + gus->midi_queue[gus->midi_w++] = buffer[i]; + gus->midi_w &= 63; } gus->sysex = 0; return 0; @@ -1112,6 +1132,8 @@ void *gus_init(const device_t *info) gus->t1l = gus->t2l = 0xff; + gus->uart_out = 1; + io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); From d0a8b1211ab53d9460e5aa3ee62296f83a5e9a5b Mon Sep 17 00:00:00 2001 From: Altheos Date: Fri, 10 Jan 2020 12:22:49 +0100 Subject: [PATCH 09/10] Fix wrong 86Box.rc --- src/win/86Box.rc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/win/86Box.rc b/src/win/86Box.rc index 69d53a69a..851b7d287 100644 --- a/src/win/86Box.rc +++ b/src/win/86Box.rc @@ -366,7 +366,7 @@ BEGIN PUSHBUTTON "Joystick 4...",IDC_JOY4,209,44,50,14 END -DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 116 +DLG_CFG_SOUND DIALOG DISCARDABLE 97, 0, 267, 199 STYLE DS_CONTROL | WS_CHILD FONT 9, "Segoe UI" BEGIN @@ -395,11 +395,11 @@ BEGIN BS_AUTOCHECKBOX | WS_TABSTOP,147,83,94,10 CONTROL "Gravis Ultrasound",IDC_CHECK_GUS,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,81,94,10 - PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,81,46,12 + BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 + PUSHBUTTON "Configure",IDC_CONFIGURE_GUS,214,99,46,12 CONTROL "Use FLOAT32 sound",IDC_CHECK_FLOAT,"Button", - BS_AUTOCHECKBOX | WS_TABSTOP,7,99,94,10 + BS_AUTOCHECKBOX | WS_TABSTOP,7,115,94,10 END DLG_CFG_NETWORK DIALOG DISCARDABLE 97, 0, 267, 63 From e0be29af062f53feb61c4a5f0c960e9978bf87a1 Mon Sep 17 00:00:00 2001 From: TC1995 Date: Fri, 10 Jan 2020 12:33:20 +0100 Subject: [PATCH 10/10] Fixed GUS MIDI Out. --- src/sound/snd_gus.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/sound/snd_gus.c b/src/sound/snd_gus.c index 3fbbfa5e0..9399c3dc5 100644 --- a/src/sound/snd_gus.c +++ b/src/sound/snd_gus.c @@ -181,15 +181,16 @@ void writegus(uint16_t addr, uint8_t val, void *p) switch (addr) { case 0x340: /*MIDI control*/ + old = gus->midi_ctrl; gus->midi_ctrl = val; gus->uart_out = 1; - if (((gus->midi_ctrl & 3) == 3) || !gus->midi_ctrl) { /*Master reset*/ + if ((val & 3) == 3) { /*Master reset*/ gus->uart_in = 0; gus->midi_status = 0; gus->midi_r = 0; gus->midi_w = 0; - } else if (gus->midi_ctrl & MIDI_CTRL_TRANSMIT) { + } else if ((old & 3) == 3) { gus->midi_status |= MIDI_INT_TRANSMIT; } else if (gus->midi_ctrl & MIDI_CTRL_RECEIVE) { gus->uart_in = 1;