src/JackHandler.h
branchv_0
changeset 4 65dfbf0494a3
parent 3 baa8055c5b10
child 5 6be3464ccb2b
equal deleted inserted replaced
3:baa8055c5b10 4:65dfbf0494a3
    24 #include <sstream>
    24 #include <sstream>
    25 #include <locale>
    25 #include <locale>
    26 #include <codecvt>
    26 #include <codecvt>
    27 #include <sys/mman.h>
    27 #include <sys/mman.h>
    28 #include <signal.h>
    28 #include <signal.h>
       
    29 #include <unistd.h>
    29 
    30 
    30 #include <jack/jack.h>
    31 #include <jack/jack.h>
    31 #include <jack/midiport.h>
    32 #include <jack/midiport.h>
    32 #include <jack/ringbuffer.h>
    33 #include <jack/ringbuffer.h>
    33 
    34 
    51 	std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // TODO: local system encoding
    52 	std::wstring_convert<std::codecvt_utf8<wchar_t>> convertor; // TODO: local system encoding
    52 
    53 
    53 	jack_client_t* jackClient = nullptr;
    54 	jack_client_t* jackClient = nullptr;
    54 	jack_port_t* jackPort = nullptr;
    55 	jack_port_t* jackPort = nullptr;
    55 	jack_ringbuffer_t* ringBuffer = nullptr;
    56 	jack_ringbuffer_t* ringBuffer = nullptr;
       
    57 	pthread_mutex_t messageThreadLock = PTHREAD_MUTEX_INITIALIZER;
       
    58 	pthread_cond_t dataReady = PTHREAD_COND_INITIALIZER;
    56 
    59 
    57 	std::atomic<bool> continueProcessing{true};
    60 	std::atomic<bool> continueProcessing{true};
    58 
    61 
    59 	const int RING_BUFFER_SIZE = 100;
    62 	const int RING_BUFFER_SIZE = 100;
    60 
    63 
    61 	struct MidiMessage {
    64 	struct MidiMessage {
    62 		uint8_t buffer[4096];
    65 		uint8_t buffer[4096];
    63 		uint32_t size;
    66 		uint32_t size;
    64 		uint32_t time;
    67 		uint32_t time;
    65 	};
    68 	};
       
    69 
       
    70 	/**
       
    71 	 * The message being prepared before enqueing in the ringBuffer.
       
    72 	 * Not the message dequeued from the ringBuffer (different thread).
       
    73 	 */
       
    74 	MidiMessage currentMidiMessage;
       
    75 	size_t currentAttributeCount = 0;
       
    76 	size_t currentAttributeIndex = 0;
       
    77 
    66 
    78 
    67 public:
    79 public:
    68 
    80 
    69 	JackHandler(Configuration& configuration) : configuration(configuration) {
    81 	JackHandler(Configuration& configuration) : configuration(configuration) {
    70 		// Initialize JACK connection:
    82 		// Initialize JACK connection:
    87 	}
    99 	}
    88 
   100 
    89 	void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override {
   101 	void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override {
    90 		// TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter)
   102 		// TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter)
    91 
   103 
       
   104 		currentAttributeCount = attributes.size();
    92 	}
   105 	}
    93 
   106 
    94 	void attribute(const relpipe::common::type::StringX& value) override {
   107 	void attribute(const relpipe::common::type::StringX& value) override {
    95 		// TODO: append to current message + if this is last attribute, put whole message to the ring buffer
   108 		// TODO: append to current message + if this is last attribute, put whole message to the ring buffer
    96 		// TODO: if (continueProcessing) {} ?
   109 		// TODO: if (continueProcessing) {} ?
       
   110 
       
   111 		if (currentAttributeIndex < currentAttributeCount) {
       
   112 			// memcpy(currentMidiMessage.buffer, ….buffer, ….size);
       
   113 			// currentMidiMessage.size = …;
       
   114 			// currentMidiMessage.time = …;
       
   115 			currentAttributeIndex++;
       
   116 		} else {
       
   117 			if (jack_ringbuffer_write_space(ringBuffer) >= sizeof (MidiMessage)) {
       
   118 				jack_ringbuffer_write(ringBuffer, (const char *) &currentMidiMessage, sizeof (MidiMessage));
       
   119 			} else {
       
   120 				fwprintf(stderr, L"Error: ring buffer is full → skipping event.\n");
       
   121 			}
       
   122 
       
   123 			if (pthread_mutex_trylock(&messageThreadLock) == 0) {
       
   124 				pthread_cond_signal(&dataReady);
       
   125 				pthread_mutex_unlock(&messageThreadLock);
       
   126 			}
       
   127 
       
   128 			currentMidiMessage = MidiMessage();
       
   129 			currentAttributeIndex = 0;
       
   130 		}
       
   131 
    97 	}
   132 	}
    98 
   133 
    99 	void endOfPipe() {
   134 	void endOfPipe() {
   100 		// TODO: send optional (configurable) MIDI events
   135 		// TODO: send optional (configurable) MIDI events
   101 		// TODO: wait until the ring buffer is empty
   136 
       
   137 		// Wait until the ring buffer is empty
       
   138 		while (continueProcessing && jack_ringbuffer_read_space(ringBuffer)) usleep(1000);
   102 	}
   139 	}
   103 
   140 
   104 	int dequeueMessages(jack_nframes_t frames) {
   141 	int dequeueMessages(jack_nframes_t frames) {
   105 
   142 
       
   143 		std::cout << "dequeueMessages(" << frames << ")" << std::endl; // TODO: remove debug message
   106 
   144 
   107 		// TODO: send events from the ring buffer to JACK + correct timing
   145 		// Process messages from the ring buffer queue:
   108 		std::cout << "dequeueMessages(" << frames << ")" << std::endl;
   146 		pthread_mutex_lock(&messageThreadLock);
       
   147 		while (continueProcessing) { // TODO: is continueProcessing needed?
       
   148 			const size_t queuedMessages = jack_ringbuffer_read_space(ringBuffer) / sizeof (MidiMessage);
       
   149 			for (size_t i = 0; i < queuedMessages; ++i) {
       
   150 				MidiMessage m;
       
   151 				jack_ringbuffer_read(ringBuffer, (char*) &m, sizeof (MidiMessage));
       
   152 				// TODO: send events from the ring buffer to JACK + correct timing
       
   153 				std::cout << "will process MidiMessage: " << &m << "" << std::endl; // TODO: remove debug message
       
   154 			}
       
   155 			pthread_cond_wait(&dataReady, &messageThreadLock);
       
   156 		}
       
   157 		pthread_mutex_unlock(&messageThreadLock);
   109 
   158 
   110 
   159 
   111 		return 0;
   160 		return 0;
   112 	}
   161 	}
   113 
   162