From 3eaa6153b5992b3850c203912603938a83abe975 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 3 Dec 2021 20:12:44 +0100 Subject: [PATCH] Switched MIDI to RtMidi. --- src/CMakeLists.txt | 7 +- src/rtmidi_midi.cpp | 204 ++++++++++++++++++++++++++++++++++ src/win/CMakeLists.txt | 2 +- src/win/Makefile.mingw | 6 +- src/win/win_midi.c | 241 ----------------------------------------- 5 files changed, 214 insertions(+), 246 deletions(-) create mode 100644 src/rtmidi_midi.cpp delete mode 100644 src/win/win_midi.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7e9e24e89..58a9c2959 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -36,7 +36,12 @@ endif() # MACOSX_BUNDLE prepares a macOS application bundle including with the app icon add_executable(86Box WIN32 MACOSX_BUNDLE 86box.c config.c log.c random.c timer.c io.c acpi.c apm.c dma.c ddma.c nmi.c pic.c pit.c port_6x.c port_92.c ppi.c pci.c mca.c usb.c - device.c nvr.c nvr_at.c nvr_ps2.c ${APP_ICON_MACOSX}) + device.c nvr.c nvr_at.c nvr_ps2.c rtmidi_midi.cpp ${APP_ICON_MACOSX}) + +find_package(RTMIDI REQUIRED) +target_include_directories(86Box ${RTMIDI_INCLUDE_DIRS}) +target_link_directories(86Box INTERFACE ${RTMIDI_LIBRARY_DIRS}) +target_link_libraries(86Box ${RTMIDI_LIBRARY_DIRS}) if(APPLE) target_link_libraries(86Box "-framework AppKit") diff --git a/src/rtmidi_midi.cpp b/src/rtmidi_midi.cpp new file mode 100644 index 000000000..43f8a2400 --- /dev/null +++ b/src/rtmidi_midi.cpp @@ -0,0 +1,204 @@ +/* + * 86Box A hypervisor and IBM PC system emulator that specializes in + * running old operating systems and software designed for IBM + * PC systems and compatibles from 1981 through fairly recent + * system designs based on the PCI bus. + * + * This file is part of the 86Box distribution. + * + * MIDI backend implemented using the RtMidi library. + * + * Author: jgilje, + * Miran Grca, + * Copyright 2021 jgilje. + * Copyright 2021 Miran Grca. + */ +#if defined __has_include +# if __has_include () +# include +# endif +# if __has_include () +# include +# endif +#endif + +#include +#include + +extern "C" +{ +#include <86box/86box.h> +#include <86box/midi.h> +#include <86box/plat_midi.h> +#include <86box/config.h> + + +static RtMidiOut * midiout = nullptr; +static RtMidiIn * midiin = nullptr; +static int midi_out_id = 0, midi_in_id = 0; +static const int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 1}; + + +int +plat_midi_write(uint8_t val) +{ + return 0; +} + + +void plat_midi_init(void) +{ + try { + if (!midiout) midiout = new RtMidiOut; + } catch (RtMidiError& error) { + pclog("Failed to initialize MIDI output: %s\n", error.getMessage().c_str()); + return; + } + + midi_out_id = config_get_int((char*)SYSTEM_MIDI_NAME, (char*)"midi", 0); + + try { + midiout->openPort(midi_out_id); + } catch (RtMidiError& error) { + pclog("Fallback to default MIDI output port: %s\n", error.getMessage().c_str()); + + try { + midiout->openPort(0); + } catch (RtMidiError& error) { + pclog("Failed to initialize MIDI output: %s\n", error.getMessage().c_str()); + delete midiout; + midiout = nullptr; + return; + } + } +} + + +void +plat_midi_close(void) +{ + if (!midiout) + return; + + midiout->closePort(); + + delete midiout; + midiout = nullptr; +} + + +int +plat_midi_get_num_devs(void) +{ + if (!midiout) { + try { + midiout = new RtMidiOut; + } catch (RtMidiError& error) { + pclog("Failed to initialize MIDI output: %s\n", error.getMessage().c_str()); + } + } + + return midiout ? midiout->getPortCount() : 0; +} + + +void +plat_midi_play_msg(uint8_t *msg) +{ + if (midiout) + midiout->sendMessage(msg, midi_lengths[(msg[0] >> 4) & 7]); +} + + +void +plat_midi_get_dev_name(int num, char *s) +{ + strcpy(s, midiout->getPortName(num).c_str()); +} + + +void +plat_midi_play_sysex(uint8_t *sysex, unsigned int len) +{ + if (midiout) + midiout->sendMessage(sysex, len); +} + + +static void +plat_midi_callback(double timeStamp, std::vector *message, void *userData) +{ + if (message->size() <= 3) + midi_in_msg(message->data()); + else + midi_in_sysex(message->data(), message->size()); +} + + +void +plat_midi_input_init(void) +{ + try { + if (!midiin) + midiin = new RtMidiIn; + } catch (RtMidiError& error) { + pclog("Failed to initialize MIDI input: %s\n", error.getMessage().c_str()); + return; + } + + midi_in_id = config_get_int((char*)SYSTEM_MIDI_NAME, (char*)"midi_input", 0); + + try { + midiin->openPort(midi_in_id); + } catch (RtMidiError& error) { + pclog("Fallback to default MIDI input port: %s\n", error.getMessage().c_str()); + + try { + midiin->openPort(0); + } catch (RtMidiError& error) { + pclog("Failed to initialize MIDI input: %s\n", error.getMessage().c_str()); + delete midiin; + midiin = nullptr; + return; + } + } + + midiin->setCallback(plat_midi_callback); +} + + +void +plat_midi_input_close(void) +{ + midiin->cancelCallback(); + midiin->closePort(); + + delete midiin; + midiin = nullptr; + + return; +} + + +int +plat_midi_in_get_num_devs(void) +{ + if (!midiin) { + try { + midiin = new RtMidiIn; + } catch (RtMidiError& error) { + pclog("Failed to initialize MIDI input: %s\n", error.getMessage().c_str()); + } + } + + return midiin ? midiin->getPortCount() : 0; +} + + +void +plat_midi_in_get_dev_name(int num, char *s) +{ + strcpy(s, midiin->getPortName(num).c_str()); +} + +} diff --git a/src/win/CMakeLists.txt b/src/win/CMakeLists.txt index 1a535c61a..301544798 100644 --- a/src/win/CMakeLists.txt +++ b/src/win/CMakeLists.txt @@ -16,7 +16,7 @@ enable_language(RC) add_library(plat OBJECT win.c win_dynld.c win_cdrom.c win_thread.c - win_keyboard.c win_crashdump.c win_midi.c win_mouse.c) + win_keyboard.c win_crashdump.c win_mouse.c) add_library(ui OBJECT win_ui.c win_icon.c win_stbar.c win_sdl.c win_dialog.c win_about.c win_settings.c win_devconf.c win_snd_gain.c win_specify_dim.c win_new_floppy.c diff --git a/src/win/Makefile.mingw b/src/win/Makefile.mingw index 0fcdd9ab4..e3199b319 100644 --- a/src/win/Makefile.mingw +++ b/src/win/Makefile.mingw @@ -466,7 +466,7 @@ CXXFLAGS := $(CFLAGS) ######################################################################### MAINOBJ := 86box.o config.o log.o random.o timer.o io.o acpi.o apm.o dma.o ddma.o \ nmi.o pic.o pit.o port_6x.o port_92.o ppi.o pci.o mca.o \ - usb.o device.o nvr.o nvr_at.o nvr_ps2.o \ + usb.o device.o nvr.o nvr_at.o nvr_ps2.o rtmidi_midi.o \ $(VNCOBJ) MEMOBJ := catalyst_flash.o i2c_eeprom.o intel_flash.o mem.o rom.o smram.o spd.o sst_flash.o @@ -674,7 +674,7 @@ VOODOOOBJ := vid_voodoo.o vid_voodoo_banshee.o \ PLATOBJ := win.o \ win_dynld.o win_thread.o \ win_cdrom.o win_keyboard.o \ - win_crashdump.o win_midi.o \ + win_crashdump.o \ win_mouse.o UIOBJ := win_ui.o win_icon.o win_stbar.o win_discord.o \ @@ -704,7 +704,7 @@ LIBS := -mwindows -lcomctl32 \ ifeq ($(VNC), y) LIBS += $(VNCLIB) -lws2_32 endif -LIBS += -lpng -lz -lwsock32 -lshell32 -liphlpapi -lpsapi -lSDL2 -limm32 -lhid -lsetupapi -loleaut32 -luxtheme -lversion -lwinmm -static -lstdc++ +LIBS += -lpng -lz -lwsock32 -lshell32 -liphlpapi -lpsapi -lSDL2 -limm32 -lhid -lsetupapi -loleaut32 -luxtheme -lversion -lrtmidi -lwinmm -static -lstdc++ ifneq ($(X64), y) ifneq ($(ARM64), y) LIBS += -Wl,--large-address-aware diff --git a/src/win/win_midi.c b/src/win/win_midi.c deleted file mode 100644 index 86ff9d285..000000000 --- a/src/win/win_midi.c +++ /dev/null @@ -1,241 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include <86box/86box.h> -#include <86box/config.h> -#include <86box/midi.h> -#include <86box/plat.h> -#include <86box/plat_midi.h> - - -typedef struct -{ - int midi_id, midi_input_id; - - HANDLE m_event; - - HMIDIOUT midi_out_device; - HMIDIIN midi_in_device; - - MIDIHDR m_hdr; -} plat_midi_t; - -plat_midi_t *pm = NULL, *pm_in = NULL; - - -void -plat_midi_init(void) -{ - MMRESULT hr; - - pm = (plat_midi_t *) malloc(sizeof(plat_midi_t)); - memset(pm, 0, sizeof(plat_midi_t)); - - pm->midi_id = config_get_int(SYSTEM_MIDI_NAME, "midi", 0); - - hr = MMSYSERR_NOERROR; - - pm->m_event = CreateEvent(NULL, TRUE, TRUE, NULL); - - hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, - (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n", hr); - pm->midi_id = 0; - hr = midiOutOpen(&pm->midi_out_device, pm->midi_id, - (uintptr_t) pm->m_event, 0, CALLBACK_EVENT); - if (hr != MMSYSERR_NOERROR) { - printf("midiOutOpen error - %08X\n", hr); - return; - } - } - - midiOutReset(pm->midi_out_device); -} - - -void -plat_midi_close(void) -{ - if (pm) { - if (pm->midi_out_device != NULL) { - midiOutReset(pm->midi_out_device); - midiOutClose(pm->midi_out_device); - CloseHandle(pm->m_event); - } - - free(pm); - pm = NULL; - } -} - - -int -plat_midi_get_num_devs(void) -{ - return midiOutGetNumDevs(); -} - - -void -plat_midi_get_dev_name(int num, char *s) -{ - MIDIOUTCAPS caps; - - midiOutGetDevCaps(num, &caps, sizeof(caps)); - strcpy(s, caps.szPname); -} - - -void -plat_midi_play_msg(uint8_t *msg) -{ - if (!pm) - return; - - midiOutShortMsg(pm->midi_out_device, *(uint32_t *) msg); -} - - -void -plat_midi_play_sysex(uint8_t *sysex, unsigned int len) -{ - MMRESULT result; - - if (!pm) - return; - - if (WaitForSingleObject(pm->m_event, 2000) == WAIT_TIMEOUT) - return; - - midiOutUnprepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); - - pm->m_hdr.lpData = (char *) sysex; - pm->m_hdr.dwBufferLength = len; - pm->m_hdr.dwBytesRecorded = len; - pm->m_hdr.dwUser = 0; - - result = midiOutPrepareHeader(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); - - if (result != MMSYSERR_NOERROR) - return; - ResetEvent(pm->m_event); - result = midiOutLongMsg(pm->midi_out_device, &pm->m_hdr, sizeof(pm->m_hdr)); - if (result != MMSYSERR_NOERROR) { - SetEvent(pm->m_event); - return; - } -} - - -int -plat_midi_write(uint8_t val) -{ - return 0; -} - - -void CALLBACK -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; - uint32_t len; - MIDIHDR *hdr; - - switch (wMsg) { - case MM_MIM_DATA: /* 0x3C3 - midi message */ - midi_in_msg(msg); - break; - case MM_MIM_OPEN: /* 0x3C1 */ - break; - case MM_MIM_CLOSE: /* 0x3C2 */ - break; - case MM_MIM_LONGDATA: /* 0x3C4 - sysex */ - /* It is midi_in_sysex() that now does the loop. */ - hdr = (MIDIHDR *) dwParam1; - sysex = (uint8_t *) hdr->lpData; - len = (uint32_t) hdr->dwBytesRecorded; - midi_in_sysex(sysex, len); - - midiInUnprepareHeader(hMidiIn, hdr, sizeof(*hdr)); - hdr->dwBytesRecorded = 0; - midiInPrepareHeader(hMidiIn, hdr, sizeof(*hdr)); - break; - case MM_MIM_ERROR: - case MM_MIM_LONGERROR: - break; - default: - break; - } -} - - -void -plat_midi_input_init(void) -{ - MMRESULT hr; - - pm_in = (plat_midi_t *) malloc(sizeof(plat_midi_t)); - memset(pm_in, 0, sizeof(plat_midi_t)); - - pm_in->midi_input_id = config_get_int(MIDI_INPUT_NAME, "midi_input", 0); - - 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) { - 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) { - printf("midiInOpen error - %08X\n", hr); - return; - } - } - - 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_in) { - if (pm_in->midi_in_device != NULL) { - midiInStop(pm_in->midi_in_device); - midiInClose(pm_in->midi_in_device); - } - - free(pm_in); - pm_in = 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); -}