From 251b3727b69c59ad9329f8ebc3aa87787e78ffe3 Mon Sep 17 00:00:00 2001 From: philip Date: Sat, 23 May 2020 09:05:43 +0200 Subject: [PATCH] added macos multithread runloop call (incl. example and readme note) --- CMakeLists.txt | 4 ++- README.md | 4 +++ RtMidi.cpp | 4 +++ RtMidi.h | 6 ++++ tests/backgroundscanner.cpp | 59 +++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 tests/backgroundscanner.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ee1f86..5d4d27d4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -205,11 +205,13 @@ if (RTMIDI_BUILD_TESTING) add_executable(qmidiin tests/qmidiin.cpp) add_executable(sysextest tests/sysextest.cpp) add_executable(apinames tests/apinames.cpp) + add_executable(backgroundscanner tests/backgroundscanner.cpp) list(GET LIB_TARGETS 0 LIBRTMIDI) - set_target_properties(cmidiin midiclock midiout midiprobe qmidiin sysextest apinames + set_target_properties(cmidiin midiclock midiout midiprobe qmidiin sysextest apinames backgroundscanner PROPERTIES RUNTIME_OUTPUT_DIRECTORY tests INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR} LINK_LIBRARIES ${LIBRTMIDI}) + target_compile_options(backgroundscanner PUBLIC "-std=c++11") add_test(NAME apinames COMMAND apinames) endif() diff --git a/README.md b/README.md index 9f9304c5..0618ad17 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,10 @@ MIDI input and output functionality are separated into two classes, `RtMidiIn` a In some cases, for example to use RtMidi with GS Synth, it may be necessary for your program to call `CoInitializeEx` and `CoUninitialize` on entry to and exit from the thread that uses RtMidi. +## OSX / macOS + +- In *multithreaded* setups port enumeration might not properly update which is due to the macOS system processing loops not being called. To resolve make sure to call `RtMidi_multithreadRunLoop()` (declared only when `__APPLE__` is defined which should be automatically) in relevant threads (other threads (the first thread) in which RtMidi objects have been instantiated). Also see example `tests/backgroundscanner.cpp`. + ## Further reading For complete documentation on RtMidi, see the `doc` directory of the distribution or surf to http://www.music.mcgill.ca/~gary/rtmidi/. diff --git a/RtMidi.cpp b/RtMidi.cpp index 302f81a0..9fc9a1cf 100644 --- a/RtMidi.cpp +++ b/RtMidi.cpp @@ -732,6 +732,10 @@ struct CoreMidiData { MIDISysexSendRequest sysexreq; }; +void RtMidi_multithreadRunLoop(){ + CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false ); +} + //*********************************************************************// // API: OS-X // Class Definitions: MidiInCore diff --git a/RtMidi.h b/RtMidi.h index 9fc520ed..1e5f5122 100644 --- a/RtMidi.h +++ b/RtMidi.h @@ -626,4 +626,10 @@ inline void RtMidiOut :: sendMessage( const std::vector *message inline void RtMidiOut :: sendMessage( const unsigned char *message, size_t size ) { static_cast(rtapi_)->sendMessage( message, size ); } inline void RtMidiOut :: setErrorCallback( RtMidiErrorCallback errorCallback, void *userData ) { rtapi_->setErrorCallback(errorCallback, userData); } +#if defined(__APPLE__) + +void RtMidi_multithreadRunLoop(); + +#endif /* __MACOSX_CORE__ */ + #endif diff --git a/tests/backgroundscanner.cpp b/tests/backgroundscanner.cpp new file mode 100644 index 00000000..bb485a43 --- /dev/null +++ b/tests/backgroundscanner.cpp @@ -0,0 +1,59 @@ +#include +#include +#include +#include + +#include "RtMidi.h" + + +int main(int argc, char * argv[]){ + + const unsigned int interval = 1000; + unsigned int round = 0; + + RtMidiIn * baseThreadPort = new RtMidiIn(); + + baseThreadPort->openVirtualPort("baseThreadPort"); + + std::thread thr = std::thread([interval, &round]() { + + for(round = 1;; round++){ + + RtMidiIn * midi = NULL; + + try { + midi = new RtMidiIn(); + + unsigned int nPorts = midi->getPortCount(); + + std::cout << "Scan-Round " << std::to_string(round) << ", found " << nPorts << " ports" << std::endl; + + for ( unsigned int i=0; igetPortName(i); + + std::cout << "\t #" << i << " " << name << std::endl; + } + + } catch ( RtMidiError &error ) { + error.printMessage(); + } + + delete midi; + + std::this_thread::sleep_for(std::chrono::milliseconds(interval)); + } + }); + + // loop until CTRL-C + std::cout << ">>>>>>>>> PRESS CTRL-C to QUIT <<<<<<<<<<" << std::endl; + while(1){ + + #ifdef __APPLE__ + RtMidi_multithreadRunLoop(); + #endif + + } + + return EXIT_SUCCESS; +}