245 |
245 |
246 JackCommand(Configuration& configuration) : configuration(configuration) { |
246 JackCommand(Configuration& configuration) : configuration(configuration) { |
247 pthread_mutex_lock(&realTimeContext.processingLock); |
247 pthread_mutex_lock(&realTimeContext.processingLock); |
248 |
248 |
249 // Initialize JACK connection: |
249 // Initialize JACK connection: |
250 std::string clientName = convertor.to_bytes(configuration.jackClientName); |
250 std::string clientName = convertor.to_bytes(configuration.client); |
251 realTimeContext.jackClient = jack_client_open(clientName.c_str(), JackNullOption, nullptr); |
251 realTimeContext.jackClient = jack_client_open(clientName.c_str(), JackNullOption, nullptr); |
252 if (realTimeContext.jackClient == nullptr) failInConstructor(L"Could not create JACK client."); |
252 if (realTimeContext.jackClient == nullptr) failInConstructor(L"Could not create JACK client."); |
253 |
253 |
254 realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage)); |
254 realTimeContext.ringBuffer = jack_ringbuffer_create(realTimeContext.RING_BUFFER_SIZE * sizeof (MidiMessage)); |
255 |
255 |
256 jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext); |
256 jack_set_process_callback(realTimeContext.jackClient, RealTimeContext::processCallback, &realTimeContext); |
257 // TODO: report also other events (connections etc.) |
257 // TODO: report also other events (connections etc.) |
258 jack_set_error_function(jackErrorCallback); |
258 jack_set_error_function(jackErrorCallback); |
259 jack_set_info_function(jackErrorCallback); |
259 jack_set_info_function(jackErrorCallback); |
260 |
260 |
261 realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, "input", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); |
261 realTimeContext.jackPort = jack_port_register(realTimeContext.jackClient, convertor.to_bytes(configuration.port).c_str(), JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); |
262 if (realTimeContext.jackPort == nullptr) failInConstructor(L"Could not register the JACK port."); |
262 if (realTimeContext.jackPort == nullptr) failInConstructor(L"Could not register the JACK port."); |
263 |
263 |
264 if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n"); |
264 if (mlockall(MCL_CURRENT | MCL_FUTURE)) fwprintf(stderr, L"Warning: Can not lock memory.\n"); |
265 |
265 |
266 int jackError = jack_activate(realTimeContext.jackClient); |
266 int jackError = jack_activate(realTimeContext.jackClient); |
267 if (jackError) failInConstructor(L"Could not activate the JACK client."); |
267 if (jackError) failInConstructor(L"Could not activate the JACK client."); |
268 |
268 |
269 |
269 |
270 // Connect to configured destination ports: |
270 // Connect to configured destination ports: |
271 const char* jackPortName = jack_port_name(realTimeContext.jackPort); |
271 const char* jackPortName = jack_port_name(realTimeContext.jackPort); |
272 for (auto sourcePort : configuration.portsToConnect) { |
272 for (auto sourcePort : configuration.connectTo) { |
273 int error = jack_connect(realTimeContext.jackClient, convertor.to_bytes(sourcePort).c_str(), jackPortName); |
273 int error = jack_connect(realTimeContext.jackClient, convertor.to_bytes(sourcePort).c_str(), jackPortName); |
274 if (error) failInConstructor(L"Connection to the JACK port failed: " + sourcePort); |
274 if (error) failInConstructor(L"Connection to the JACK port failed: " + sourcePort); |
275 } |
275 } |
276 |
276 |
277 } |
277 } |
279 void processJackStream(std::shared_ptr<relpipe::writer::RelationalWriter> writer, std::function<void() > relationalWriterFlush) { |
279 void processJackStream(std::shared_ptr<relpipe::writer::RelationalWriter> writer, std::function<void() > relationalWriterFlush) { |
280 // Relation headers: |
280 // Relation headers: |
281 using namespace relpipe::writer; |
281 using namespace relpipe::writer; |
282 vector<AttributeMetadata> metadata; |
282 vector<AttributeMetadata> metadata; |
283 |
283 |
284 if (configuration.listJackPorts) listPorts(writer); |
284 if (configuration.listPorts) listPorts(writer); |
285 if (!configuration.listMidiMessages) return; |
285 if (!configuration.listMidiMessages) return; |
286 |
286 |
287 metadata.push_back({L"event", TypeId::STRING}); |
287 metadata.push_back({L"event", TypeId::STRING}); |
288 metadata.push_back({L"channel", TypeId::INTEGER}); |
288 metadata.push_back({L"channel", TypeId::INTEGER}); |
289 metadata.push_back({L"note_on", TypeId::BOOLEAN}); |
289 metadata.push_back({L"note_on", TypeId::BOOLEAN}); |
304 relationalWriterFlush(); |
304 relationalWriterFlush(); |
305 } |
305 } |
306 waitForRTCycle(); |
306 waitForRTCycle(); |
307 |
307 |
308 // Once the Configuration::requiredJackConnections count was reached, we will disconnect if the count drops under this level. |
308 // Once the Configuration::requiredJackConnections count was reached, we will disconnect if the count drops under this level. |
309 if (configuration.requiredJackConnections) { |
309 if (configuration.requiredConnections) { |
310 int currentConnectionCount = jack_port_connected(realTimeContext.jackPort); |
310 int currentConnectionCount = jack_port_connected(realTimeContext.jackPort); |
311 if (currentConnectionCount > maxJackPortConnections) maxJackPortConnections = currentConnectionCount; |
311 if (currentConnectionCount > maxJackPortConnections) maxJackPortConnections = currentConnectionCount; |
312 else if (maxJackPortConnections >= configuration.requiredJackConnections && currentConnectionCount < configuration.requiredJackConnections) break; |
312 else if (maxJackPortConnections >= configuration.requiredConnections && currentConnectionCount < configuration.requiredConnections) break; |
313 } |
313 } |
314 } |
314 } |
315 } |
315 } |
316 |
316 |
317 void finish(int sig) { |
317 void finish(int sig) { |