src/JackHandler.h
branchv_0
changeset 14 9ad606c80d3b
parent 13 a85c191709e6
child 15 b3239e4ad328
equal deleted inserted replaced
13:a85c191709e6 14:9ad606c80d3b
    57 	/**
    57 	/**
    58 	 * Is passed through the ring buffer
    58 	 * Is passed through the ring buffer
    59 	 * from the relpipe-reading thread to the jack-writing thread (callback).
    59 	 * from the relpipe-reading thread to the jack-writing thread (callback).
    60 	 */
    60 	 */
    61 	struct MidiMessage {
    61 	struct MidiMessage {
    62 		uint8_t buffer[4096];
    62 		uint8_t buffer[4096] = {0};
    63 		uint32_t size;
    63 		uint32_t size;
    64 		uint32_t time;
    64 		uint32_t time;
    65 	};
    65 	};
    66 
    66 
    67 	/**
    67 	/**
   128 				else if (name == L"control") return Event::CONTROL;
   128 				else if (name == L"control") return Event::CONTROL;
   129 				else if (name == L"sysex") return Event::SYSEX;
   129 				else if (name == L"sysex") return Event::SYSEX;
   130 				else return Event::UNKNOWN;
   130 				else return Event::UNKNOWN;
   131 			}
   131 			}
   132 
   132 
   133 			Event event;
   133 			Event event = Event::UNKNOWN;
   134 			relpipe::common::type::Integer channel;
   134 			relpipe::common::type::Integer channel;
   135 			relpipe::common::type::Boolean noteOn;
   135 			relpipe::common::type::Boolean noteOn;
   136 			relpipe::common::type::Integer notePitch;
   136 			relpipe::common::type::Integer notePitch;
   137 			relpipe::common::type::Integer noteVelocity;
   137 			relpipe::common::type::Integer noteVelocity;
   138 			relpipe::common::type::Integer controllerId;
   138 			relpipe::common::type::Integer controllerId;
   143 
   143 
   144 		} recordContext;
   144 		} recordContext;
   145 
   145 
   146 	} relationContext;
   146 	} relationContext;
   147 
   147 
       
   148 	static void jackErrorCallback(const char * message) {
       
   149 		std::wstring_convert < std::codecvt_utf8<wchar_t>> convertor; // TODO: local system encoding
       
   150 		std::wcerr << L"JACK: " << convertor.from_bytes(message) << std::endl;
       
   151 	}
       
   152 
   148 public:
   153 public:
   149 
   154 
   150 	JackHandler(Configuration& configuration) : configuration(configuration) {
   155 	JackHandler(Configuration& configuration) : configuration(configuration) {
   151 		// Initialize JACK connection:
   156 		// Initialize JACK connection:
   152 		std::string clientName = convertor.to_bytes(configuration.jackClientName);
   157 		std::string clientName = convertor.to_bytes(configuration.jackClientName);
   155 
   160 
   156 		realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage));
   161 		realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage));
   157 
   162 
   158 		jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext);
   163 		jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext);
   159 		// TODO: report also other events (connections etc.)
   164 		// TODO: report also other events (connections etc.)
   160 		// TODO: jack_set_error_function() + avoid mixing char and wchar output
   165 		jack_set_error_function(jackErrorCallback);
       
   166 		jack_set_info_function(jackErrorCallback);
   161 
   167 
   162 		realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
   168 		realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "output", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
   163 		if (realTimeContext.jackPort == nullptr) throw JackException(L"Could not register port.");
   169 		if (realTimeContext.jackPort == nullptr) throw JackException(L"Could not register port.");
   164 
   170 
   165 		if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n");
   171 		if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n");
   192 		}
   198 		}
   193 
   199 
   194 		// TODO: check also data types and skipt relation if important attributes are missing
   200 		// TODO: check also data types and skipt relation if important attributes are missing
   195 		// TODO: configurable relation name
   201 		// TODO: configurable relation name
   196 
   202 
   197 		if (relationContext.indexOfEvent == -1 || relationContext.indexOfRaw == -1) {
   203 		if (relationContext.indexOfRaw == -1) {
   198 			relationContext.skip = true;
   204 			relationContext.skip = true;
   199 			fwprintf(stderr, L"Relation „%ls“ will be ignored because mandatory attributes are missing.\n", name.c_str());
   205 			fwprintf(stderr, L"Relation „%ls“ will be ignored because mandatory attribute „raw“ is missing.\n", name.c_str());
   200 		}
   206 		}
   201 
   207 
   202 	}
   208 	}
   203 
   209 
   204 	void attribute(const relpipe::common::type::StringX& value) override {
   210 	void attribute(const relpipe::common::type::StringX& value) override {
   205 		if (relationContext.skip) return;
   211 		if (relationContext.skip) return;
   206 		// TODO: switch to RelationalReaderStringHandler
   212 		// TODO: switch to RelationalReaderStringHandler
   207 		// TODO: if (continueProcessing) {} ?
   213 		// TODO: if (continueProcessing) {} ?
   208 
   214 
   209 		// memcpy(currentMidiMessage.buffer, ….buffer, ….size);
   215 		RelationContext& rel = relationContext;
   210 		// currentMidiMessage.size = …;
   216 		RelationContext::RecordContext& rec = rel.recordContext;
   211 		// currentMidiMessage.time = …;
   217 
   212 
   218 		if (rel.indexOfEvent == rec.attributeIndex) rec.event = rec.parseEventType(value);
   213 		{
   219 		else if (rel.indexOfChannel == rec.attributeIndex) rec.channel = std::stoi(value);
   214 			RelationContext& rel = relationContext;
   220 		else if (rel.indexOfControllerId == rec.attributeIndex) rec.controllerId = std::stoi(value);
   215 			RelationContext::RecordContext& rec = rel.recordContext;
   221 		else if (rel.indexOfControllerValue == rec.attributeIndex) rec.controllerValue = std::stoi(value);
   216 
   222 		else if (rel.indexOfNoteOn == rec.attributeIndex) rec.noteOn = value == L"true";
   217 			if (rel.indexOfEvent == rec.attributeIndex) rec.event = rec.parseEventType(value);
   223 		else if (rel.indexOfNotePitch == rec.attributeIndex) rec.notePitch = std::stoi(value);
   218 			else if (rel.indexOfChannel == rec.attributeIndex) rec.channel = std::stoi(value);
   224 		else if (rel.indexOfNoteVelocity == rec.attributeIndex) rec.noteVelocity = std::stoi(value);
   219 			else if (rel.indexOfControllerId == rec.attributeIndex) rec.controllerId = std::stoi(value);
   225 		else if (rel.indexOfRaw == rec.attributeIndex) rec.raw = value;
   220 			else if (rel.indexOfControllerValue == rec.attributeIndex) rec.controllerValue = std::stoi(value);
   226 
   221 			else if (rel.indexOfNoteOn == rec.attributeIndex) rec.noteOn = value == L"true";
   227 		rec.attributeIndex++;
   222 			else if (rel.indexOfNotePitch == rec.attributeIndex) rec.notePitch = std::stoi(value);
   228 
   223 			else if (rel.indexOfNoteVelocity == rec.attributeIndex) rec.noteVelocity = std::stoi(value);
   229 		if (rec.attributeIndex == rel.attributeCount) {
   224 			else if (rel.indexOfRaw == rec.attributeIndex) rec.raw = value;
       
   225 		}
       
   226 
       
   227 		relationContext.recordContext.attributeIndex++;
       
   228 
       
   229 		if (relationContext.recordContext.attributeIndex == relationContext.attributeCount) {
       
   230 
   230 
   231 			while (jack_ringbuffer_write_space(realTimeContext.ringBuffer) < sizeof (MidiMessage)) usleep(1000); // should not happen, the real-time thread should be faster
   231 			while (jack_ringbuffer_write_space(realTimeContext.ringBuffer) < sizeof (MidiMessage)) usleep(1000); // should not happen, the real-time thread should be faster
   232 
   232 
   233 			MidiMessage m;
   233 			MidiMessage m;
   234 
   234 
   235 			// TODO: convert relationContext.recordContext to m
       
   236 			// TODO: correct timing?
   235 			// TODO: correct timing?
   237 			m.time = 0;
   236 			m.time = 0;
   238 			m.size = 3;
   237 
   239 			m.buffer[0] = 0x90;
   238 			if (rec.event == RelationContext::RecordContext::Event::NOTE) {
   240 			m.buffer[1] = 0x24;
   239 				m.size = 3;
   241 			m.buffer[2] = 0x40;
   240 				m.buffer[0] = (rec.noteOn ? 0x90 : 0x80) | rec.channel;
       
   241 				m.buffer[1] = rec.notePitch;
       
   242 				m.buffer[2] = rec.noteVelocity;
       
   243 			} else if (rec.event == RelationContext::RecordContext::Event::CONTROL) {
       
   244 				m.size = 3;
       
   245 				m.buffer[0] = 0xB0 | rec.channel;
       
   246 				m.buffer[1] = rec.controllerId;
       
   247 				m.buffer[2] = rec.controllerValue;
       
   248 			} else { // SysEx and other raw messages
       
   249 				m.size = 0;
       
   250 				size_t nibble = 0;
       
   251 				for (int i = 0; i < rec.raw.size() && m.size < sizeof (m.buffer); i++) {
       
   252 					wchar_t ch = rec.raw[i];
       
   253 
       
   254 					if (ch == L' ') continue;
       
   255 					else if (ch >= L'0' && ch <= L'9') m.buffer[m.size] += (ch - '0') /**/ << (nibble % 2 ? 0 : 4);
       
   256 					else if (ch >= L'a' && ch <= L'f') m.buffer[m.size] += (ch - 'a' + 10) << (nibble % 2 ? 0 : 4);
       
   257 					else if (ch >= L'A' && ch <= L'F') m.buffer[m.size] += (ch - 'A' + 10) << (nibble % 2 ? 0 : 4);
       
   258 					else throw JackException(L"Invalid character in the hexadeximal sequence: „" + std::wstring(1, ch) + L"“.");
       
   259 
       
   260 					nibble++;
       
   261 					if (nibble % 2 == 0) m.size++;
       
   262 				}
       
   263 			}
       
   264 
       
   265 			// TODO: if (m.size == 0) fwprintf(stderr, L"Missing data\n");
   242 
   266 
   243 			jack_ringbuffer_write(realTimeContext.ringBuffer, (const char *) &m, sizeof (m));
   267 			jack_ringbuffer_write(realTimeContext.ringBuffer, (const char *) &m, sizeof (m));
   244 
   268 
   245 			relationContext.recordContext = RelationContext::RecordContext();
   269 			relationContext.recordContext = RelationContext::RecordContext();
   246 		}
   270 		}