From b9062a1d0c5aa0b9c3b187add010d314a3260936 Mon Sep 17 00:00:00 2001 From: TomW Date: Tue, 4 Jun 2013 20:52:17 +0100 Subject: [PATCH] Added preliminary MPU-401 emulation (UART mode only) for SB16. Currently outputs to default Windows MIDI device. This allows Windows 3.x SB16 drivers to work. --- src/Makefile.mingw | 22 +++++++-------- src/plat-midi.h | 3 ++ src/sound_mpu401_uart.c | 57 +++++++++++++++++++++++++++++++++++++ src/sound_mpu401_uart.h | 9 ++++++ src/sound_sb.c | 11 +++++--- src/win-midi.c | 62 +++++++++++++++++++++++++++++++++++++++++ src/win.c | 3 ++ 7 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 src/plat-midi.h create mode 100644 src/sound_mpu401_uart.c create mode 100644 src/sound_mpu401_uart.h create mode 100644 src/win-midi.c diff --git a/src/Makefile.mingw b/src/Makefile.mingw index 29b6448..8015b65 100644 --- a/src/Makefile.mingw +++ b/src/Makefile.mingw @@ -9,17 +9,17 @@ OBJ = 386.o 808x.o acer386sx.o ali1429.o amstrad.o cdrom-ioctl.o \ keyboard_olim24.o keyboard_xt.o lpt.o mcr.o mem.o model.o \ mouse.o mouse_ps2.o mouse_serial.o neat.o nvr.o olivetti_m24.o \ opti.o pc.o pci.o pic.o piix.o pit.o ppi.o serial.o sound.o sound_adlib.o \ - sound_adlibgold.o sound_cms.o sound_gus.o sound_opl.o sound_pas16.o sound_sb.o \ - sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_wss.o soundopenal.o timer.o \ - um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \ - vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o \ - vid_et4000.o vid_et4000w32.o vid_et4000w32i.o vid_hercules.o vid_icd2061.o \ - vid_ics2595.o vid_mda.o vid_olivetti_m24.o vid_oti067.o vid_paradise.o \ - vid_pc1512.o vid_pc1640.o vid_pc200.o vid_s3.o vid_s3_virge.o vid_sdac_ramdac.o \ - vid_stg_ramdac.o vid_svga.o vid_svga_render.o vid_tandy.o vid_tkd8001_ramdac.o \ - vid_tvga.o vid_unk_ramdac.o vid_vga.o vid_voodoo.o video.o wd76c10.o \ - win.o win-ddraw.o win-keyboard.o win-mouse.o win-timer.o win-video.o \ - x86seg.o x87.o xtide.o pc.res + sound_adlibgold.o sound_cms.o sound_gus.o sound_mpu401_uart.o sound_opl.o \ + sound_pas16.o sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o \ + sound_wss.o soundopenal.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o \ + vid_ati_mach64.o vid_ati18800.o vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o \ + vid_cl5429.o vid_ega.o vid_et4000.o vid_et4000w32.o vid_et4000w32i.o \ + vid_hercules.o vid_icd2061.o vid_ics2595.o vid_mda.o vid_olivetti_m24.o \ + vid_oti067.o vid_paradise.o vid_pc1512.o vid_pc1640.o vid_pc200.o vid_s3.o \ + vid_s3_virge.o vid_sdac_ramdac.o vid_stg_ramdac.o vid_svga.o vid_svga_render.o \ + vid_tandy.o vid_tkd8001_ramdac.o vid_tvga.o vid_unk_ramdac.o vid_vga.o \ + vid_voodoo.o video.o wd76c10.o win.o win-ddraw.o win-keyboard.o win-midi.o \ + win-mouse.o win-timer.o win-video.o x86seg.o x87.o xtide.o pc.res FMOBJ = fmopl.o ymf262.o diff --git a/src/plat-midi.h b/src/plat-midi.h new file mode 100644 index 0000000..46671ff --- /dev/null +++ b/src/plat-midi.h @@ -0,0 +1,3 @@ +void midi_init(); +void midi_close(); +void midi_out(uint8_t val); diff --git a/src/sound_mpu401_uart.c b/src/sound_mpu401_uart.c new file mode 100644 index 0000000..dc62612 --- /dev/null +++ b/src/sound_mpu401_uart.c @@ -0,0 +1,57 @@ +#include "ibm.h" +#include "io.h" +#include "sound_mpu401_uart.h" + +enum +{ + STATUS_OUTPUT_NOT_READY = 0x40, + STATUS_INPUT_NOT_READY = 0x80 +}; + +static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (addr & 1) /*Command*/ + { + switch (val) + { + case 0xff: /*Reset*/ + mpu->rx_data = 0xfe; /*Acknowledge*/ + mpu->status = 0; + mpu->uart_mode = 0; + break; + + case 0x3f: /*Enter UART mode*/ + mpu->rx_data = 0xfe; /*Acknowledge*/ + mpu->status = 0; + mpu->uart_mode = 1; + break; + } + return; + } + + /*Data*/ + if (mpu->uart_mode) + midi_out(val); +} + +static uint8_t mpu401_uart_read(uint16_t addr, void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (addr & 1) /*Status*/ + return mpu->status; + + /*Data*/ + mpu->status |= STATUS_INPUT_NOT_READY; + return mpu->rx_data; +} + +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr) +{ + mpu->status = STATUS_INPUT_NOT_READY; + mpu->uart_mode = 0; + + io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); +} diff --git a/src/sound_mpu401_uart.h b/src/sound_mpu401_uart.h new file mode 100644 index 0000000..91f4119 --- /dev/null +++ b/src/sound_mpu401_uart.h @@ -0,0 +1,9 @@ +typedef struct mpu401_uart_t +{ + uint8_t status; + uint8_t rx_data; + + int uart_mode; +} mpu401_uart_t; + +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr); diff --git a/src/sound_sb.c b/src/sound_sb.c index 1d19da8..ec5625f 100644 --- a/src/sound_sb.c +++ b/src/sound_sb.c @@ -1,9 +1,10 @@ #include #include "ibm.h" #include "device.h" +#include "sound_mpu401_uart.h" +#include "sound_opl.h" #include "sound_sb.h" #include "sound_sb_dsp.h" -#include "sound_opl.h" #include "filters.h" @@ -22,9 +23,10 @@ typedef struct sb_mixer_t typedef struct sb_t { - opl_t opl; - sb_dsp_t dsp; - sb_mixer_t mixer; + opl_t opl; + sb_dsp_t dsp; + sb_mixer_t mixer; + mpu401_uart_t mpu; int16_t opl_buffer[SOUNDBUFLEN * 2]; int16_t dsp_buffer[SOUNDBUFLEN * 2]; @@ -336,6 +338,7 @@ void *sb_16_init() io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); sound_add_handler(sb_opl3_poll, sb_get_buffer, sb); + mpu401_uart_init(&sb->mpu, 0x330); sb->mixer.regs[0x30] = 31 << 3; sb->mixer.regs[0x31] = 31 << 3; diff --git a/src/win-midi.c b/src/win-midi.c new file mode 100644 index 0000000..e12613a --- /dev/null +++ b/src/win-midi.c @@ -0,0 +1,62 @@ +#include +#include +#include "ibm.h" +#include "plat-midi.h" + +static int midi_id; +static HMIDIOUT midi_out_device = NULL; + +void midi_close(); + +void midi_init() +{ + int c; + int n; + MIDIOUTCAPS ocaps; + MMRESULT hr; + + midi_id=0; + + hr = midiOutOpen(&midi_out_device, midi_id, 0, + 0, CALLBACK_NULL); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + return; + } + + midiOutReset(midi_out_device); +} + +void midi_close() +{ + if (midi_out_device != NULL) + { + midiOutReset(midi_out_device); + midiOutClose(midi_out_device); + midi_out_device = NULL; + } +} + +static int midi_pos, midi_len; +static uint32_t midi_command; +static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 0}; + +void midi_out(uint8_t val) +{ + if (val & 0x80) + { + midi_pos = 0; + midi_len = midi_lengths[(val >> 4) & 7]; + midi_command = 0; + } + + if (midi_len) + { + midi_command |= (val << (midi_pos * 8)); + + midi_pos++; + + if (midi_pos == midi_len) + midiOutShortMsg(midi_out_device, midi_command); + } +} diff --git a/src/win.c b/src/win.c index 52c5237..9f67ade 100644 --- a/src/win.c +++ b/src/win.c @@ -18,6 +18,7 @@ #include "nvr.h" #include "sound.h" +#include "plat-midi.h" #include "plat-keyboard.h" #include "win-ddraw.h" @@ -300,6 +301,8 @@ int WINAPI WinMain (HINSTANCE hThisInstance, ghwnd=hwnd; ddraw_init(hwnd); + midi_init(); + atexit(midi_close); // d3d_init(hwnd); // opengl_init(hwnd);