encode MIDI messages + process JACK error output v_0
authorFrantišek Kučera <franta-hg@frantovo.cz>
Sat, 03 Oct 2020 18:20:30 +0200
branchv_0
changeset 14 9ad606c80d3b
parent 13 a85c191709e6
child 15 b3239e4ad328
encode MIDI messages + process JACK error output
src/JackHandler.h
--- a/src/JackHandler.h	Sat Oct 03 13:40:07 2020 +0200
+++ b/src/JackHandler.h	Sat Oct 03 18:20:30 2020 +0200
@@ -59,7 +59,7 @@
 	 * from the relpipe-reading thread to the jack-writing thread (callback).
 	 */
 	struct MidiMessage {
-		uint8_t buffer[4096];
+		uint8_t buffer[4096] = {0};
 		uint32_t size;
 		uint32_t time;
 	};
@@ -130,7 +130,7 @@
 				else return Event::UNKNOWN;
 			}
 
-			Event event;
+			Event event = Event::UNKNOWN;
 			relpipe::common::type::Integer channel;
 			relpipe::common::type::Boolean noteOn;
 			relpipe::common::type::Integer notePitch;
@@ -145,6 +145,11 @@
 
 	} relationContext;
 
+	static void jackErrorCallback(const char * message) {
+		std::wstring_convert < std::codecvt_utf8<wchar_t>> convertor; // TODO: local system encoding
+		std::wcerr << L"JACK: " << convertor.from_bytes(message) << std::endl;
+	}
+
 public:
 
 	JackHandler(Configuration& configuration) : configuration(configuration) {
@@ -157,7 +162,8 @@
 
 		jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext);
 		// TODO: report also other events (connections etc.)
-		// TODO: jack_set_error_function() + avoid mixing char and wchar output
+		jack_set_error_function(jackErrorCallback);
+		jack_set_info_function(jackErrorCallback);
 
 		realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
 		if (realTimeContext.jackPort == nullptr) throw JackException(L"Could not register port.");
@@ -194,9 +200,9 @@
 		// TODO: check also data types and skipt relation if important attributes are missing
 		// TODO: configurable relation name
 
-		if (relationContext.indexOfEvent == -1 || relationContext.indexOfRaw == -1) {
+		if (relationContext.indexOfRaw == -1) {
 			relationContext.skip = true;
-			fwprintf(stderr, L"Relation „%ls“ will be ignored because mandatory attributes are missing.\n", name.c_str());
+			fwprintf(stderr, L"Relation „%ls“ will be ignored because mandatory attribute „raw“ is missing.\n", name.c_str());
 		}
 
 	}
@@ -206,39 +212,57 @@
 		// TODO: switch to RelationalReaderStringHandler
 		// TODO: if (continueProcessing) {} ?
 
-		// memcpy(currentMidiMessage.buffer, ….buffer, ….size);
-		// currentMidiMessage.size = …;
-		// currentMidiMessage.time = …;
-
-		{
-			RelationContext& rel = relationContext;
-			RelationContext::RecordContext& rec = rel.recordContext;
+		RelationContext& rel = relationContext;
+		RelationContext::RecordContext& rec = rel.recordContext;
 
-			if (rel.indexOfEvent == rec.attributeIndex) rec.event = rec.parseEventType(value);
-			else if (rel.indexOfChannel == rec.attributeIndex) rec.channel = std::stoi(value);
-			else if (rel.indexOfControllerId == rec.attributeIndex) rec.controllerId = std::stoi(value);
-			else if (rel.indexOfControllerValue == rec.attributeIndex) rec.controllerValue = std::stoi(value);
-			else if (rel.indexOfNoteOn == rec.attributeIndex) rec.noteOn = value == L"true";
-			else if (rel.indexOfNotePitch == rec.attributeIndex) rec.notePitch = std::stoi(value);
-			else if (rel.indexOfNoteVelocity == rec.attributeIndex) rec.noteVelocity = std::stoi(value);
-			else if (rel.indexOfRaw == rec.attributeIndex) rec.raw = value;
-		}
+		if (rel.indexOfEvent == rec.attributeIndex) rec.event = rec.parseEventType(value);
+		else if (rel.indexOfChannel == rec.attributeIndex) rec.channel = std::stoi(value);
+		else if (rel.indexOfControllerId == rec.attributeIndex) rec.controllerId = std::stoi(value);
+		else if (rel.indexOfControllerValue == rec.attributeIndex) rec.controllerValue = std::stoi(value);
+		else if (rel.indexOfNoteOn == rec.attributeIndex) rec.noteOn = value == L"true";
+		else if (rel.indexOfNotePitch == rec.attributeIndex) rec.notePitch = std::stoi(value);
+		else if (rel.indexOfNoteVelocity == rec.attributeIndex) rec.noteVelocity = std::stoi(value);
+		else if (rel.indexOfRaw == rec.attributeIndex) rec.raw = value;
 
-		relationContext.recordContext.attributeIndex++;
+		rec.attributeIndex++;
 
-		if (relationContext.recordContext.attributeIndex == relationContext.attributeCount) {
+		if (rec.attributeIndex == rel.attributeCount) {
 
 			while (jack_ringbuffer_write_space(realTimeContext.ringBuffer) < sizeof (MidiMessage)) usleep(1000); // should not happen, the real-time thread should be faster
 
 			MidiMessage m;
 
-			// TODO: convert relationContext.recordContext to m
 			// TODO: correct timing?
 			m.time = 0;
-			m.size = 3;
-			m.buffer[0] = 0x90;
-			m.buffer[1] = 0x24;
-			m.buffer[2] = 0x40;
+
+			if (rec.event == RelationContext::RecordContext::Event::NOTE) {
+				m.size = 3;
+				m.buffer[0] = (rec.noteOn ? 0x90 : 0x80) | rec.channel;
+				m.buffer[1] = rec.notePitch;
+				m.buffer[2] = rec.noteVelocity;
+			} else if (rec.event == RelationContext::RecordContext::Event::CONTROL) {
+				m.size = 3;
+				m.buffer[0] = 0xB0 | rec.channel;
+				m.buffer[1] = rec.controllerId;
+				m.buffer[2] = rec.controllerValue;
+			} else { // SysEx and other raw messages
+				m.size = 0;
+				size_t nibble = 0;
+				for (int i = 0; i < rec.raw.size() && m.size < sizeof (m.buffer); i++) {
+					wchar_t ch = rec.raw[i];
+
+					if (ch == L' ') continue;
+					else if (ch >= L'0' && ch <= L'9') m.buffer[m.size] += (ch - '0') /**/ << (nibble % 2 ? 0 : 4);
+					else if (ch >= L'a' && ch <= L'f') m.buffer[m.size] += (ch - 'a' + 10) << (nibble % 2 ? 0 : 4);
+					else if (ch >= L'A' && ch <= L'F') m.buffer[m.size] += (ch - 'A' + 10) << (nibble % 2 ? 0 : 4);
+					else throw JackException(L"Invalid character in the hexadeximal sequence: „" + std::wstring(1, ch) + L"“.");
+
+					nibble++;
+					if (nibble % 2 == 0) m.size++;
+				}
+			}
+
+			// TODO: if (m.size == 0) fwprintf(stderr, L"Missing data\n");
 
 			jack_ringbuffer_write(realTimeContext.ringBuffer, (const char *) &m, sizeof (m));