# HG changeset patch # User František Kučera # Date 1601492079 -7200 # Node ID 65dfbf0494a3488f4eb6b7b6f5aa1d98e287dfbd # Parent baa8055c5b10a7e651f39704c8faeb98e16a2198 pass MIDI messages through the ring buffer (queue) from one thread to another diff -r baa8055c5b10 -r 65dfbf0494a3 src/CMakeLists.txt --- a/src/CMakeLists.txt Wed Sep 30 00:34:41 2020 +0200 +++ b/src/CMakeLists.txt Wed Sep 30 20:54:39 2020 +0200 @@ -34,7 +34,7 @@ ) # Link libraries: -target_link_libraries(${EXECUTABLE_FILE} ${RELPIPE_LIBS_LIBRARIES}) +target_link_libraries(${EXECUTABLE_FILE} ${RELPIPE_LIBS_LIBRARIES} pthread) set_property(TARGET ${EXECUTABLE_FILE} PROPERTY INSTALL_RPATH_USE_LINK_PATH TRUE) install(TARGETS ${EXECUTABLE_FILE} DESTINATION bin) diff -r baa8055c5b10 -r 65dfbf0494a3 src/JackHandler.h --- a/src/JackHandler.h Wed Sep 30 00:34:41 2020 +0200 +++ b/src/JackHandler.h Wed Sep 30 20:54:39 2020 +0200 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,8 @@ jack_client_t* jackClient = nullptr; jack_port_t* jackPort = nullptr; jack_ringbuffer_t* ringBuffer = nullptr; + pthread_mutex_t messageThreadLock = PTHREAD_MUTEX_INITIALIZER; + pthread_cond_t dataReady = PTHREAD_COND_INITIALIZER; std::atomic continueProcessing{true}; @@ -64,6 +67,15 @@ uint32_t time; }; + /** + * The message being prepared before enqueing in the ringBuffer. + * Not the message dequeued from the ringBuffer (different thread). + */ + MidiMessage currentMidiMessage; + size_t currentAttributeCount = 0; + size_t currentAttributeIndex = 0; + + public: JackHandler(Configuration& configuration) : configuration(configuration) { @@ -89,23 +101,60 @@ void startRelation(const relpipe::common::type::StringX name, std::vector attributes) override { // TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter) + currentAttributeCount = attributes.size(); } void attribute(const relpipe::common::type::StringX& value) override { // TODO: append to current message + if this is last attribute, put whole message to the ring buffer // TODO: if (continueProcessing) {} ? + + if (currentAttributeIndex < currentAttributeCount) { + // memcpy(currentMidiMessage.buffer, ….buffer, ….size); + // currentMidiMessage.size = …; + // currentMidiMessage.time = …; + currentAttributeIndex++; + } else { + if (jack_ringbuffer_write_space(ringBuffer) >= sizeof (MidiMessage)) { + jack_ringbuffer_write(ringBuffer, (const char *) ¤tMidiMessage, sizeof (MidiMessage)); + } else { + fwprintf(stderr, L"Error: ring buffer is full → skipping event.\n"); + } + + if (pthread_mutex_trylock(&messageThreadLock) == 0) { + pthread_cond_signal(&dataReady); + pthread_mutex_unlock(&messageThreadLock); + } + + currentMidiMessage = MidiMessage(); + currentAttributeIndex = 0; + } + } void endOfPipe() { // TODO: send optional (configurable) MIDI events - // TODO: wait until the ring buffer is empty + + // Wait until the ring buffer is empty + while (continueProcessing && jack_ringbuffer_read_space(ringBuffer)) usleep(1000); } int dequeueMessages(jack_nframes_t frames) { + std::cout << "dequeueMessages(" << frames << ")" << std::endl; // TODO: remove debug message - // TODO: send events from the ring buffer to JACK + correct timing - std::cout << "dequeueMessages(" << frames << ")" << std::endl; + // Process messages from the ring buffer queue: + pthread_mutex_lock(&messageThreadLock); + while (continueProcessing) { // TODO: is continueProcessing needed? + const size_t queuedMessages = jack_ringbuffer_read_space(ringBuffer) / sizeof (MidiMessage); + for (size_t i = 0; i < queuedMessages; ++i) { + MidiMessage m; + jack_ringbuffer_read(ringBuffer, (char*) &m, sizeof (MidiMessage)); + // TODO: send events from the ring buffer to JACK + correct timing + std::cout << "will process MidiMessage: " << &m << "" << std::endl; // TODO: remove debug message + } + pthread_cond_wait(&dataReady, &messageThreadLock); + } + pthread_mutex_unlock(&messageThreadLock); return 0;