src/JackHandler.h
branchv_0
changeset 10 6aa881c10efd
parent 9 14cf28d7681c
child 11 1c0b9981eb6d
equal deleted inserted replaced
9:14cf28d7681c 10:6aa881c10efd
     1 /**
     1 /**
     2  * Relational pipes
     2  * Relational pipes
     3  * Copyright © 2018 František Kučera (Frantovo.cz, GlobalCode.info)
     3  * Copyright © 2020 František Kučera (Frantovo.cz, GlobalCode.info)
     4  *
     4  *
     5  * This program is free software: you can redistribute it and/or modify
     5  * This program is free software: you can redistribute it and/or modify
     6  * it under the terms of the GNU General Public License as published by
     6  * it under the terms of the GNU General Public License as published by
     7  * the Free Software Foundation, version 3 of the License.
     7  * the Free Software Foundation, version 3 of the License.
     8  *
     8  *
    58 
    58 
    59 	std::atomic<bool> continueProcessing{true};
    59 	std::atomic<bool> continueProcessing{true};
    60 
    60 
    61 	const int RING_BUFFER_SIZE = 100;
    61 	const int RING_BUFFER_SIZE = 100;
    62 
    62 
       
    63 	/**
       
    64 	 * Is passed through the ring buffer
       
    65 	 * from the relpipe-reading thread to the jack-writing thread (callback).
       
    66 	 */
    63 	struct MidiMessage {
    67 	struct MidiMessage {
    64 		uint8_t buffer[4096];
    68 		uint8_t buffer[4096];
    65 		uint32_t size;
    69 		uint32_t size;
    66 		uint32_t time;
    70 		uint32_t time;
    67 	};
    71 	};
    68 
    72 
    69 	/**
    73 	/**
    70 	 * The message being prepared before enqueing in the ringBuffer.
    74 	 * Temporary storage of values read from relational input.
    71 	 * Not the message dequeued from the ringBuffer (different thread).
       
    72 	 */
    75 	 */
    73 	MidiMessage currentMidiMessage;
    76 	class RelationContext {
    74 	size_t currentAttributeCount = 0;
    77 	public:
    75 	size_t currentAttributeIndex = 0;
    78 		size_t indexOfEvent = -1;
    76 
    79 		size_t indexOfChannel = -1;
       
    80 		size_t indexOfNoteOn = -1;
       
    81 		size_t indexOfNotePitch = -1;
       
    82 		size_t indexOfNoteVelocity = -1;
       
    83 		size_t indexOfControllerId = -1;
       
    84 		size_t indexOfControllerValue = -1;
       
    85 		size_t indexOfRaw = -1;
       
    86 
       
    87 		size_t attributeCount = 0;
       
    88 
       
    89 		class RecordContext {
       
    90 		public:
       
    91 
       
    92 			enum class Event {
       
    93 				NOTE,
       
    94 				CONTROL,
       
    95 				SYSEX,
       
    96 				UNKNOWN
       
    97 			};
       
    98 
       
    99 			static Event parseEventType(const relpipe::common::type::StringX name) {
       
   100 				if (name == L"note") return Event::NOTE;
       
   101 				else if (name == L"control") return Event::CONTROL;
       
   102 				else if (name == L"sysex") return Event::SYSEX;
       
   103 				else return Event::UNKNOWN;
       
   104 			}
       
   105 
       
   106 			Event event;
       
   107 			relpipe::common::type::Integer channel;
       
   108 			relpipe::common::type::Boolean noteOn;
       
   109 			relpipe::common::type::Integer notePitch;
       
   110 			relpipe::common::type::Integer noteVelocity;
       
   111 			relpipe::common::type::Integer controllerId;
       
   112 			relpipe::common::type::Integer controllerValue;
       
   113 			relpipe::common::type::StringX raw;
       
   114 
       
   115 			size_t attributeIndex = 0;
       
   116 
       
   117 		} recordContext;
       
   118 
       
   119 	} relationContext;
    77 
   120 
    78 public:
   121 public:
    79 
   122 
    80 	JackHandler(Configuration& configuration) : configuration(configuration) {
   123 	JackHandler(Configuration& configuration) : configuration(configuration) {
    81 		// Initialize JACK connection:
   124 		// Initialize JACK connection:
   103 	}
   146 	}
   104 
   147 
   105 	void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override {
   148 	void startRelation(const relpipe::common::type::StringX name, std::vector<relpipe::reader::handlers::AttributeMetadata> attributes) override {
   106 		// TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter)
   149 		// TODO: validate metadata and prepare attribute mappings (names and types are important, order does not matter)
   107 
   150 
   108 		currentAttributeCount = attributes.size();
   151 		relationContext = RelationContext();
       
   152 		relationContext.attributeCount = attributes.size();
       
   153 
       
   154 		for (int i = 0; i < relationContext.attributeCount; i++) {
       
   155 			const relpipe::common::type::StringX attributeName = attributes[i].getAttributeName();
       
   156 			if (attributeName == L"event") relationContext.indexOfEvent = i;
       
   157 			else if (attributeName == L"channel") relationContext.indexOfChannel = i;
       
   158 			else if (attributeName == L"controller_id") relationContext.indexOfControllerId = i;
       
   159 			else if (attributeName == L"controller_value") relationContext.indexOfControllerValue = i;
       
   160 			else if (attributeName == L"note_on") relationContext.indexOfNoteOn = i;
       
   161 			else if (attributeName == L"note_pitch") relationContext.indexOfNotePitch = i;
       
   162 			else if (attributeName == L"note_velocity") relationContext.indexOfNoteVelocity = i;
       
   163 			else if (attributeName == L"raw") relationContext.indexOfRaw = i;
       
   164 		}
       
   165 		
       
   166 		// TODO: check also data types and skipt relation if important attributes are missing
       
   167 		// TODO: configurable relation name
   109 	}
   168 	}
   110 
   169 
   111 	void attribute(const relpipe::common::type::StringX& value) override {
   170 	void attribute(const relpipe::common::type::StringX& value) override {
       
   171 		// TODO: switch to RelationalReaderStringHandler
   112 		// TODO: append to current message + if this is last attribute, put whole message to the ring buffer
   172 		// TODO: append to current message + if this is last attribute, put whole message to the ring buffer
   113 		// TODO: if (continueProcessing) {} ?
   173 		// TODO: if (continueProcessing) {} ?
   114 
   174 
   115 		// memcpy(currentMidiMessage.buffer, ….buffer, ….size);
   175 		// memcpy(currentMidiMessage.buffer, ….buffer, ….size);
   116 		// currentMidiMessage.size = …;
   176 		// currentMidiMessage.size = …;
   117 		// currentMidiMessage.time = …;
   177 		// currentMidiMessage.time = …;
   118 
   178 
   119 		// TODO: correct timing?
   179 		// TODO: correct timing?
   120 		// TODO: real data
   180 		// TODO: real data
   121 		currentMidiMessage.time = 0;
   181 
   122 		currentMidiMessage.size = 3;
   182 		{
   123 		currentMidiMessage.buffer[0] = 0x90;
   183 			RelationContext& rel = relationContext;
   124 		currentMidiMessage.buffer[1] = 0x24;
   184 			RelationContext::RecordContext& rec = rel.recordContext;
   125 		currentMidiMessage.buffer[2] = 0x40;
   185 
   126 
   186 			if (rel.indexOfEvent == rec.attributeIndex) rec.event = rec.parseEventType(value);
   127 		currentAttributeIndex++;
   187 			else if (rel.indexOfChannel == rec.attributeIndex) rec.channel = std::stoi(value);
   128 
   188 			else if (rel.indexOfControllerId == rec.attributeIndex) rec.controllerId = std::stoi(value);
   129 		if (currentAttributeIndex == currentAttributeCount) {
   189 			else if (rel.indexOfControllerValue == rec.attributeIndex) rec.controllerValue = std::stoi(value);
       
   190 			else if (rel.indexOfNoteOn == rec.attributeIndex) rec.noteOn = value == L"true";
       
   191 			else if (rel.indexOfNotePitch == rec.attributeIndex) rec.notePitch = std::stoi(value);
       
   192 			else if (rel.indexOfNoteVelocity == rec.attributeIndex) rec.noteVelocity = std::stoi(value);
       
   193 			else if (rel.indexOfRaw == rec.attributeIndex) rec.raw = value;
       
   194 		}
       
   195 
       
   196 		relationContext.recordContext.attributeIndex++;
       
   197 
       
   198 		if (relationContext.recordContext.attributeIndex == relationContext.attributeCount) {
   130 			if (jack_ringbuffer_write_space(ringBuffer) >= sizeof (MidiMessage)) {
   199 			if (jack_ringbuffer_write_space(ringBuffer) >= sizeof (MidiMessage)) {
   131 				jack_ringbuffer_write(ringBuffer, (const char *) &currentMidiMessage, sizeof (MidiMessage));
   200 				MidiMessage m;
   132 				std::cout << "jack_ringbuffer_write" << std::endl;
   201 
       
   202 				// TODO: convert relationContext.recordContext to m
       
   203 				m.time = 0;
       
   204 				m.size = 3;
       
   205 				m.buffer[0] = 0x90;
       
   206 				m.buffer[1] = 0x24;
       
   207 				m.buffer[2] = 0x40;
       
   208 
       
   209 				jack_ringbuffer_write(ringBuffer, (const char *) &m, sizeof (m));
   133 			} else {
   210 			} else {
   134 				fwprintf(stderr, L"Error: ring buffer is full → skipping event.\n");
   211 				fwprintf(stderr, L"Error: ring buffer is full → skipping event.\n");
   135 			}
   212 			}
   136 
   213 
   137 			currentMidiMessage = MidiMessage();
   214 			relationContext.recordContext = RelationContext::RecordContext();
   138 			currentAttributeIndex = 0;
       
   139 		}
   215 		}
   140 
   216 
   141 	}
   217 	}
   142 
   218 
   143 	void endOfPipe() {
   219 	void endOfPipe() {
   148 		usleep(1000000);
   224 		usleep(1000000);
   149 		// TODO: better waiting (ringBuffer might be empty, but events have not been sent to JACK yet)
   225 		// TODO: better waiting (ringBuffer might be empty, but events have not been sent to JACK yet)
   150 		// TODO: optionally mute all; probably enabled by default
   226 		// TODO: optionally mute all; probably enabled by default
   151 	}
   227 	}
   152 
   228 
       
   229 	/**
       
   230 	 * TODO: use separate class/instance for JACK callbacks to minimize scope and prevent mistakes.
       
   231 	 */
   153 	int dequeueMessages(jack_nframes_t frames) {
   232 	int dequeueMessages(jack_nframes_t frames) {
   154 		const size_t queuedMessages = jack_ringbuffer_read_space(ringBuffer) / sizeof (MidiMessage);
   233 		const size_t queuedMessages = jack_ringbuffer_read_space(ringBuffer) / sizeof (MidiMessage);
   155 		void* jackPortBuffer = jack_port_get_buffer(jackPort, frames); // jack_port_get_buffer() must be called outside the loop, otherwise it will multiply the MIDI events
   234 		void* jackPortBuffer = jack_port_get_buffer(jackPort, frames); // jack_port_get_buffer() must be called outside the loop, otherwise it will multiply the MIDI events
   156 		jack_midi_clear_buffer(jackPortBuffer); // TODO: clean buffer?
   235 		jack_midi_clear_buffer(jackPortBuffer); // TODO: clean buffer?
   157 		for (size_t i = 0; i < queuedMessages && i < frames; i++) {
   236 		for (size_t i = 0; i < queuedMessages && i < frames; i++) {
   158 			// TODO: correct timing?
   237 			// TODO: correct timing?
   159 			MidiMessage m;
   238 			MidiMessage m;
   160 			jack_ringbuffer_read(ringBuffer, (char*) &m, sizeof (MidiMessage));
   239 			jack_ringbuffer_read(ringBuffer, (char*) &m, sizeof (MidiMessage));
   161 			jack_midi_data_t* midiData = jack_midi_event_reserve(jackPortBuffer, m.time, m.size);
   240 			jack_midi_data_t* midiData = jack_midi_event_reserve(jackPortBuffer, m.time, m.size);
   162 			memcpy(midiData, m.buffer, m.size);
   241 			memcpy(midiData, m.buffer, m.size);
   163 			std::cout << "jack_midi_event_reserve" << std::endl;
       
   164 		}
   242 		}
   165 		return 0;
   243 		return 0;
   166 	}
   244 	}
   167 
   245 
   168 	void finish(int sig) {
   246 	void finish(int sig) {