I wrote a small module which accepts MIDI input from a MIDI device using the RtMidi library:
http://www.music.mcgill.ca/~gary/rtmidi/
I have no issues using the library, it works great. I've exported my module for use with Python using Cython. The module imports fine and works correctly with Python. The problem is that since this waits for user MIDI input indefinitely, it is necessary to spawn this in its own thread.
I've tested spawning this in its own thread in C++ using std::thread, and it works just fine. The problem is specifically trying to spawn this on its own thread from within Python when using the exported library.
Here's the code:
import midi #my exported C++ module
import threading
import time
def test():
for i in range(0, 10):
print(i)
time.sleep(.25)
my_thread = threading.Thread(target=test)
my_thread.daemon = False
my_thread.start()
midi_input = midi.MidiListen()
midi_input.start() #listen for MIDI input indefinitely
What winds up happening is that the thread I've spawned will print '0', and then the MIDI input reader will start, and the first thread will not continue printing until the midi_input.start() function returns, instead of both functions running concurrently.
Additionally, I've tried running this code the other way around where the midi_input.start() is executed on a separate thread instead of the test() function.
What am I doing wrong here?
EDIT:
I was able to fix my problem thanks to Geoff's answer.
Notice the "nogil" and "with gil" at the end of the function declarations.
Here's my .pyx file:
from libcpp.vector cimport vector
cdef extern from "hello_midi.h":
cdef cppclass MidiInput:
void mycallback(double deltatime, vector[unsigned char]* message, void* userData) with gil
int midi_listen() nogil
cdef void midi_init(MidiInput* ob):
with nogil:
ob.midi_listen()
cdef class MidiListen:
cdef MidiInput* thisptr
def __cinit__(self):
self.thisptr = new MidiInput()
def start_midi(self):
midi_init(self.thisptr)
And here's the final Python script:
import midi
import threading
import time
def test():
for i in range(0, 10):
print(i)
time.sleep(.25)
def start():
x = midi.MidiListen()
x.start_midi()
thread = threading.Thread(target=start)
thread.start()
test()