Implement MIDI I/O support using RtMidi

This commit is contained in:
Cacodemon345
2021-12-03 01:22:54 +06:00
parent 9c0a90534e
commit f7aec4cfcf
2 changed files with 160 additions and 1 deletions

View File

@@ -4,9 +4,10 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTORCC ON)
find_package(PkgConfig)
find_package(Threads REQUIRED)
add_library(plat STATIC qt.c qt_main.cpp qt_platform.cpp qt_midi.cpp cpp11_thread.cpp)
add_library(plat STATIC qt.c qt_main.cpp qt_platform.cpp cpp11_thread.cpp)
add_library(ui STATIC
qt_ui.cpp
qt_cdrom.c
@@ -101,6 +102,21 @@ if (UNIX AND NOT APPLE)
find_package(X11 REQUIRED)
target_link_libraries(ui PRIVATE X11::X11)
find_package(ECM NO_MODULE)
if (PkgConfig_FOUND)
pkg_check_modules(RTMIDI rtmidi)
if (RTMIDI_FOUND)
target_include_directories(plat PRIVATE ${RTMIDI_INCLUDE_DIRS})
target_link_directories(plat PRIVATE ${RTMIDI_LIBRARY_DIRS})
target_link_libraries(plat PRIVATE ${RTMIDI_LIBRARIES})
target_link_options(plat PRIVATE ${RTMIDI_LDFLAGS})
target_compile_options(plat PRIVATE ${RTMIDI_CFLAGS})
target_sources(plat PRIVATE rtmidi_midi.cpp)
else()
target_sources(plat PRIVATE qt_midi.cpp)
endif()
else()
target_sources(plat PRIVATE qt_midi.cpp)
endif()
if (ECM_FOUND)
list(APPEND CMAKE_MODULE_PATH ${ECM_MODULE_PATH})
find_package(Wayland COMPONENTS Client)

143
src/qt/rtmidi_midi.cpp Normal file
View File

@@ -0,0 +1,143 @@
#include <RtMidi.h>
#include <cstdint>
#include <cstring>
extern "C"
{
#include <86box/86box.h>
#include <86box/midi.h>
#include <86box/plat_midi.h>
#include <86box/config.h>
}
extern "C" {
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()
{
try
{
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()
{
if (!midiout) return;
midiout->closePort();
delete midiout;
midiout = nullptr;
}
int plat_midi_get_num_devs()
{
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<unsigned char> *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
{
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)
{
return midiin ? midiin->getPortCount() : 0;
}
void plat_midi_in_get_dev_name(int num, char *s)
{
strcpy(s, midiin->getPortName(num).c_str());
}
}