From f347c69dd033d1fc4960253f3e92d764168fd9e0 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Thu, 2 Dec 2021 23:53:25 +0600 Subject: [PATCH 1/3] Frameskip when needed Fixes lockups. --- src/qt/qt_gleswidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_gleswidget.cpp b/src/qt/qt_gleswidget.cpp index 829b484b9..40daa2e0c 100644 --- a/src/qt/qt_gleswidget.cpp +++ b/src/qt/qt_gleswidget.cpp @@ -156,5 +156,6 @@ void GLESWidget::qt_real_blit(int x, int y, int w, int h) video_screenshot((uint32_t *)imagebits, 0, 0, 2048 + 64); } video_blit_complete(); + firstupdate = false; this->reqUpdate(); } From f7aec4cfcf32a7a34f8e02e6244c63205c8b9001 Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 3 Dec 2021 01:22:54 +0600 Subject: [PATCH 2/3] Implement MIDI I/O support using RtMidi --- src/qt/CMakeLists.txt | 18 +++++- src/qt/rtmidi_midi.cpp | 143 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 src/qt/rtmidi_midi.cpp diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 9a2be5a7f..45c9d1d77 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -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) diff --git a/src/qt/rtmidi_midi.cpp b/src/qt/rtmidi_midi.cpp new file mode 100644 index 000000000..b8ab2ca30 --- /dev/null +++ b/src/qt/rtmidi_midi.cpp @@ -0,0 +1,143 @@ + +#include +#include +#include +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 *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()); +} + +} From e021b3460a83e464785c10829af732db185b4a0d Mon Sep 17 00:00:00 2001 From: Cacodemon345 Date: Fri, 3 Dec 2021 02:12:35 +0600 Subject: [PATCH 3/3] Make external MIDI options actually appear in Settings --- src/qt/qt_deviceconfig.cpp | 50 +++++++++++++++++++++++++++++++------- src/qt/qt_midi.cpp | 12 +++++++++ src/qt/rtmidi_midi.cpp | 26 ++++++++++++++++++-- 3 files changed, 77 insertions(+), 11 deletions(-) diff --git a/src/qt/qt_deviceconfig.cpp b/src/qt/qt_deviceconfig.cpp index a0d62c1c9..a99e1ab26 100644 --- a/src/qt/qt_deviceconfig.cpp +++ b/src/qt/qt_deviceconfig.cpp @@ -11,6 +11,7 @@ extern "C" { #include <86box/86box.h> #include <86box/config.h> #include <86box/device.h> +#include <86box/plat_midi.h> } #include "qt_filefield.hpp" @@ -58,19 +59,50 @@ void DeviceConfig::ConfigureDevice(const _device_* device) { int currentIndex = -1; int selected = config_get_int(device_context.name, const_cast(config->name), config->default_int); - for (auto* sel = config->selection; (sel->description != nullptr) && (strlen(sel->description) > 0); ++sel) { - int rows = model->rowCount(); - model->insertRow(rows); - auto idx = model->index(rows, 0); + if (config->type == CONFIG_MIDI) { + for (int i = 0; i < plat_midi_get_num_devs(); i++) { + char midiName[512] = { 0 }; + plat_midi_get_dev_name(i, midiName); - model->setData(idx, sel->description, Qt::DisplayRole); - model->setData(idx, sel->value, Qt::UserRole); + int rows = model->rowCount(); + model->insertRow(rows); + auto idx = model->index(rows, 0); - if (selected == sel->value) { - currentIndex = idx.row(); + model->setData(idx, midiName, Qt::DisplayRole); + model->setData(idx, i, Qt::UserRole); + if (selected == i) { + currentIndex = idx.row(); + } + } + } else if (config->type == CONFIG_MIDI_IN) { + for (int i = 0; i < plat_midi_in_get_num_devs(); i++) { + char midiName[512] = { 0 }; + plat_midi_in_get_dev_name(i, midiName); + + int rows = model->rowCount(); + model->insertRow(rows); + auto idx = model->index(rows, 0); + + model->setData(idx, midiName, Qt::DisplayRole); + model->setData(idx, i, Qt::UserRole); + if (selected == i) { + currentIndex = idx.row(); + } + } + } else { + for (auto* sel = config->selection; (sel->description != nullptr) && (strlen(sel->description) > 0); ++sel) { + int rows = model->rowCount(); + model->insertRow(rows); + auto idx = model->index(rows, 0); + + model->setData(idx, sel->description, Qt::DisplayRole); + model->setData(idx, sel->value, Qt::UserRole); + + if (selected == sel->value) { + currentIndex = idx.row(); + } } } - dc.ui->formLayout->addRow(config->description, cbox); cbox->setCurrentIndex(currentIndex); break; diff --git a/src/qt/qt_midi.cpp b/src/qt/qt_midi.cpp index 0027e5b5a..a9b741c9e 100644 --- a/src/qt/qt_midi.cpp +++ b/src/qt/qt_midi.cpp @@ -29,4 +29,16 @@ int plat_midi_get_num_devs() int plat_midi_in_get_num_devs(void) { return 0; } +void plat_midi_get_dev_name(int num, char *s) +{ + s[0] = ' '; + s[1] = 0; +} + +void plat_midi_in_get_dev_name(int num, char *s) +{ + s[0] = ' '; + s[1] = 0; +} + } diff --git a/src/qt/rtmidi_midi.cpp b/src/qt/rtmidi_midi.cpp index b8ab2ca30..fd4ccbbaf 100644 --- a/src/qt/rtmidi_midi.cpp +++ b/src/qt/rtmidi_midi.cpp @@ -24,7 +24,7 @@ void plat_midi_init() { try { - midiout = new RtMidiOut; + if (!midiout) midiout = new RtMidiOut; } catch (RtMidiError& error) { @@ -63,6 +63,17 @@ void plat_midi_close() int plat_midi_get_num_devs() { + 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; } @@ -91,7 +102,7 @@ void plat_midi_input_init(void) { try { - midiin = new RtMidiIn; + if (!midiin) midiin = new RtMidiIn; } catch (RtMidiError& error) { @@ -132,6 +143,17 @@ void plat_midi_input_close(void) 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; }