--- 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)
--- 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 <codecvt>
#include <sys/mman.h>
#include <signal.h>
+#include <unistd.h>
#include <jack/jack.h>
#include <jack/midiport.h>
@@ -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<bool> 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<relpipe::reader::handlers::AttributeMetadata> 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;