Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

macOS multithreading fix/note #219

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/.
Expand Down
4 changes: 4 additions & 0 deletions RtMidi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,10 @@ struct CoreMidiData {
MIDISysexSendRequest sysexreq;
};

void RtMidi_multithreadRunLoop(){
CFRunLoopRunInMode( kCFRunLoopDefaultMode, 0, false );
}

//*********************************************************************//
// API: OS-X
// Class Definitions: MidiInCore
Expand Down
6 changes: 6 additions & 0 deletions RtMidi.h
Original file line number Diff line number Diff line change
Expand Up @@ -626,4 +626,10 @@ inline void RtMidiOut :: sendMessage( const std::vector<unsigned char> *message
inline void RtMidiOut :: sendMessage( const unsigned char *message, size_t size ) { static_cast<MidiOutApi *>(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
59 changes: 59 additions & 0 deletions tests/backgroundscanner.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#include <iostream>
#include <chrono>
#include <thread>
#include <ctime>

#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; i<nPorts; i++ ) {

std::string name = midi->getPortName(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;
}