Rename a pipe method, add docs
[carla.git] / source / backend / engine / CarlaEngineJack.cpp
blobdf4fffbc1b3c94f906bd3b968be1ade9956791af
1 /*
2 * Carla Plugin Host
3 * Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "CarlaEngineClient.hpp"
19 #include "CarlaEngineInit.hpp"
20 #include "CarlaEngineInternal.hpp"
21 #include "CarlaPlugin.hpp"
23 #include "CarlaBackendUtils.hpp"
24 #include "CarlaEngineUtils.hpp"
25 #include "CarlaMathUtils.hpp"
26 #include "CarlaMIDI.h"
27 #include "CarlaPatchbayUtils.hpp"
28 #include "CarlaStringList.hpp"
30 #include "jackey.h"
32 #ifdef USING_JUCE
33 # include "carla_juce/carla_juce.h"
34 #endif
36 #ifdef __SSE2_MATH__
37 # include <xmmintrin.h>
38 #endif
40 // must be last
41 #include "jackbridge/JackBridge.hpp"
43 #ifdef JACKBRIDGE_DIRECT
44 # define JackPortIsControlVoltage 0x100
45 #endif
47 #define URI_CANVAS_ICON "http://kxstudio.sf.net/ns/canvas/icon"
49 #define URI_MAIN_CLIENT_NAME "https://kx.studio/ns/carla/main-client-name"
50 #define URI_POSITION "https://kx.studio/ns/carla/position"
51 #define URI_PLUGIN_ICON "https://kx.studio/ns/carla/plugin-icon"
52 #define URI_PLUGIN_ID "https://kx.studio/ns/carla/plugin-id"
54 #define URI_TYPE_INTEGER "http://www.w3.org/2001/XMLSchema#integer"
55 #define URI_TYPE_STRING "text/plain"
57 CARLA_BACKEND_START_NAMESPACE
59 class CarlaEngineJack;
60 class CarlaEngineJackClient;
62 #ifndef BUILD_BRIDGE
63 struct CarlaJackPortHints {
64 bool isHardware : 1;
65 bool isInput : 1;
66 bool isAudio : 1;
67 bool isMIDI : 1;
68 bool isCV : 1;
69 bool isOSC : 1;
71 // NOTE: assumes fThreadSafeMetadataMutex lock done from caller
72 static CarlaJackPortHints fromPort(const jack_port_t* const jackPort)
74 CarlaJackPortHints ph = { false, false, false, false, false, false };
76 const int portFlags = jackbridge_port_flags(jackPort);
77 const char* const portType = jackbridge_port_type(jackPort);
79 ph.isHardware = portFlags & JackPortIsPhysical;
80 ph.isInput = portFlags & JackPortIsInput;
81 ph.isAudio = portType != nullptr && std::strcmp(portType, JACK_DEFAULT_AUDIO_TYPE) == 0;
82 ph.isMIDI = portType != nullptr && std::strcmp(portType, JACK_DEFAULT_MIDI_TYPE) == 0;
83 ph.isCV = false;
84 ph.isOSC = false;
86 if (ph.isAudio && portFlags & JackPortIsControlVoltage)
88 ph.isAudio = false;
89 ph.isCV = true;
92 if (const jack_uuid_t uuid = jackbridge_port_uuid(jackPort))
94 char* value = nullptr;
95 char* type = nullptr;
97 if (jackbridge_get_property(uuid, JACKEY_SIGNAL_TYPE, &value, &type)
98 && value != nullptr
99 && type != nullptr
100 && std::strcmp(type, URI_TYPE_STRING) == 0)
102 ph.isCV = (std::strcmp(value, "CV") == 0);
103 ph.isOSC = (std::strcmp(value, "OSC") == 0);
105 if (ph.isCV)
106 ph.isAudio = false;
107 if (ph.isOSC)
108 ph.isMIDI = false;
110 jackbridge_free(value);
111 jackbridge_free(type);
115 return ph;
118 #endif
120 // -----------------------------------------------------------------------
121 // Fallback data
123 #ifndef BUILD_BRIDGE
124 static const GroupNameToId kGroupNameToIdFallback = { 0, { '\0' } };
125 static /* */ PortNameToId kPortNameToIdFallbackNC = { 0, 0, { '\0' }, { '\0' }, { '\0' } };
126 static const PortNameToId kPortNameToIdFallback = { 0, 0, { '\0' }, { '\0' }, { '\0' } };
127 static const ConnectionToId kConnectionToIdFallback = { 0, 0, 0, 0, 0 };
128 #endif
129 static EngineEvent kFallbackJackEngineEvent = {
130 kEngineEventTypeNull, 0, 0, {{ kEngineControlEventTypeNull, 0, -1, 0.0f, true }}
133 // -----------------------------------------------------------------------
134 // Carla Engine Port removal helper
136 class CarlaEngineJackAudioPort;
137 class CarlaEngineJackCVPort;
138 class CarlaEngineJackEventPort;
140 struct JackPortDeletionCallback {
141 virtual ~JackPortDeletionCallback() noexcept {}
142 virtual void jackAudioPortDeleted(CarlaEngineJackAudioPort* const) noexcept = 0;
143 virtual void jackCVPortDeleted(CarlaEngineJackCVPort* const) noexcept = 0;
144 virtual void jackEventPortDeleted(CarlaEngineJackEventPort* const) noexcept = 0;
147 // -----------------------------------------------------------------------
148 // Carla Engine JACK-Audio port
150 class CarlaEngineJackAudioPort : public CarlaEngineAudioPort
152 public:
153 CarlaEngineJackAudioPort(const CarlaEngineClient& client,
154 const bool isInputPort,
155 const uint32_t indexOffset,
156 jack_client_t* const jackClient,
157 jack_port_t* const jackPort,
158 CarlaRecursiveMutex& rmutex,
159 JackPortDeletionCallback* const delCallback) noexcept
160 : CarlaEngineAudioPort(client, isInputPort, indexOffset),
161 fJackClient(jackClient),
162 fJackPort(jackPort),
163 fThreadSafeMetadataMutex(rmutex),
164 kDeletionCallback(delCallback)
166 carla_debug("CarlaEngineJackAudioPort::CarlaEngineJackAudioPort(%s, %p, %p)", bool2str(isInputPort), jackClient, jackPort);
168 switch (kClient.getEngine().getProccessMode())
170 case ENGINE_PROCESS_MODE_SINGLE_CLIENT:
171 case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
172 CARLA_SAFE_ASSERT_RETURN(jackClient != nullptr && jackPort != nullptr,);
174 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
176 if (const jack_uuid_t uuid = jackbridge_port_uuid(jackPort))
177 jackbridge_set_property(jackClient, uuid, JACKEY_SIGNAL_TYPE, "AUDIO", URI_TYPE_STRING);
179 break;
181 default:
182 CARLA_SAFE_ASSERT(jackClient == nullptr && jackPort == nullptr);
183 break;
187 ~CarlaEngineJackAudioPort() noexcept override
189 carla_debug("CarlaEngineJackAudioPort::~CarlaEngineJackAudioPort()");
191 if (fJackClient != nullptr && fJackPort != nullptr)
193 try {
194 jackbridge_port_unregister(fJackClient, fJackPort);
195 } CARLA_SAFE_EXCEPTION("Audio port unregister");
197 fJackClient = nullptr;
198 fJackPort = nullptr;
201 if (kDeletionCallback != nullptr)
202 kDeletionCallback->jackAudioPortDeleted(this);
205 void initBuffer() noexcept override
207 if (fJackPort == nullptr)
208 return CarlaEngineAudioPort::initBuffer();
210 const uint32_t bufferSize(kClient.getEngine().getBufferSize());
212 try {
213 fBuffer = (float*)jackbridge_port_get_buffer(fJackPort, bufferSize);
215 catch(...) {
216 fBuffer = nullptr;
217 return;
220 if (! kIsInput)
221 carla_zeroFloats(fBuffer, bufferSize);
224 void invalidate() noexcept
226 fJackClient = nullptr;
227 fJackPort = nullptr;
230 void setMetaData(const char* const key, const char* const value, const char* const type) override
232 if (fJackPort == nullptr)
233 return CarlaEngineAudioPort::setMetaData(key, value, type);
235 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
237 try {
238 if (const jack_uuid_t uuid = jackbridge_port_uuid(fJackPort))
239 jackbridge_set_property(fJackClient, uuid, key, value, type);
240 } CARLA_SAFE_EXCEPTION("Port setMetaData");
243 private:
244 jack_client_t* fJackClient;
245 jack_port_t* fJackPort;
247 CarlaRecursiveMutex& fThreadSafeMetadataMutex;
248 JackPortDeletionCallback* const kDeletionCallback;
250 friend class CarlaEngineJackClient;
252 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackAudioPort)
255 // -----------------------------------------------------------------------
256 // Carla Engine JACK-CV port
258 class CarlaEngineJackCVPort : public CarlaEngineCVPort
260 public:
261 CarlaEngineJackCVPort(const CarlaEngineClient& client,
262 const bool isInputPort,
263 const uint32_t indexOffset,
264 jack_client_t* const jackClient,
265 jack_port_t* const jackPort,
266 CarlaRecursiveMutex& rmutex,
267 JackPortDeletionCallback* const delCallback) noexcept
268 : CarlaEngineCVPort(client, isInputPort, indexOffset),
269 fJackClient(jackClient),
270 fJackPort(jackPort),
271 fThreadSafeMetadataMutex(rmutex),
272 kDeletionCallback(delCallback)
274 carla_debug("CarlaEngineJackCVPort::CarlaEngineJackCVPort(%s, %p, %p)", bool2str(isInputPort), jackClient, jackPort);
276 switch (kClient.getEngine().getProccessMode())
278 case ENGINE_PROCESS_MODE_SINGLE_CLIENT:
279 case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
280 CARLA_SAFE_ASSERT_RETURN(jackClient != nullptr && jackPort != nullptr,);
282 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
284 if (const jack_uuid_t uuid = jackbridge_port_uuid(jackPort))
285 jackbridge_set_property(jackClient, uuid, JACKEY_SIGNAL_TYPE, "CV", URI_TYPE_STRING);
287 break;
289 default:
290 CARLA_SAFE_ASSERT(jackClient == nullptr && jackPort == nullptr);
291 break;
295 ~CarlaEngineJackCVPort() noexcept override
297 carla_debug("CarlaEngineJackCVPort::~CarlaEngineJackCVPort()");
299 if (fJackClient != nullptr && fJackPort != nullptr)
301 try {
302 jackbridge_port_unregister(fJackClient, fJackPort);
303 } CARLA_SAFE_EXCEPTION("CV port unregister");
305 fJackClient = nullptr;
306 fJackPort = nullptr;
309 if (kDeletionCallback != nullptr)
310 kDeletionCallback->jackCVPortDeleted(this);
313 void initBuffer() noexcept override
315 if (fJackPort == nullptr)
316 return CarlaEngineCVPort::initBuffer();
318 const uint32_t bufferSize(kClient.getEngine().getBufferSize());
320 try {
321 fBuffer = (float*)jackbridge_port_get_buffer(fJackPort, bufferSize);
323 catch(...) {
324 fBuffer = nullptr;
325 return;
328 if (! kIsInput)
329 carla_zeroFloats(fBuffer, bufferSize);
332 void invalidate() noexcept
334 fJackClient = nullptr;
335 fJackPort = nullptr;
338 void setMetaData(const char* const key, const char* const value, const char* const type) override
340 if (fJackPort == nullptr)
341 return CarlaEngineCVPort::setMetaData(key, value, type);
343 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
345 try {
346 if (const jack_uuid_t uuid = jackbridge_port_uuid(fJackPort))
347 jackbridge_set_property(fJackClient, uuid, key, value, type);
348 } CARLA_SAFE_EXCEPTION("Port setMetaData");
351 private:
352 jack_client_t* fJackClient;
353 jack_port_t* fJackPort;
355 CarlaRecursiveMutex& fThreadSafeMetadataMutex;
356 JackPortDeletionCallback* const kDeletionCallback;
358 friend class CarlaEngineJackClient;
360 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackCVPort)
363 // -----------------------------------------------------------------------
364 // Carla Engine JACK-Event port
366 class CarlaEngineJackEventPort : public CarlaEngineEventPort
368 public:
369 CarlaEngineJackEventPort(const CarlaEngineClient& client,
370 const bool isInputPort,
371 const uint32_t indexOffset,
372 jack_client_t* const jackClient,
373 jack_port_t* const jackPort,
374 CarlaRecursiveMutex& rmutex,
375 JackPortDeletionCallback* const delCallback) noexcept
376 : CarlaEngineEventPort(client, isInputPort, indexOffset),
377 fJackClient(jackClient),
378 fJackPort(jackPort),
379 fJackBuffer(nullptr),
380 fRetEvent(kFallbackJackEngineEvent),
381 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
382 fCvSourceEvents(nullptr),
383 fCvSourceEventCount(0),
384 #endif
385 fThreadSafeMetadataMutex(rmutex),
386 kDeletionCallback(delCallback)
388 carla_debug("CarlaEngineJackEventPort::CarlaEngineJackEventPort(%s, %p, %p)", bool2str(isInputPort), jackClient, jackPort);
390 switch (kClient.getEngine().getProccessMode())
392 case ENGINE_PROCESS_MODE_SINGLE_CLIENT:
393 case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
394 CARLA_SAFE_ASSERT_RETURN(jackClient != nullptr && jackPort != nullptr,);
395 break;
396 default:
397 CARLA_SAFE_ASSERT(jackClient == nullptr && jackPort == nullptr);
398 break;
402 ~CarlaEngineJackEventPort() noexcept override
404 carla_debug("CarlaEngineJackEventPort::~CarlaEngineJackEventPort()");
406 if (fJackClient != nullptr && fJackPort != nullptr)
408 try {
409 jackbridge_port_unregister(fJackClient, fJackPort);
410 } CARLA_SAFE_EXCEPTION("Event port unregister");
412 fJackClient = nullptr;
413 fJackPort = nullptr;
416 if (kDeletionCallback != nullptr)
417 kDeletionCallback->jackEventPortDeleted(this);
420 void initBuffer() noexcept override
422 if (fJackPort == nullptr)
423 return CarlaEngineEventPort::initBuffer();
425 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
426 fCvSourceEvents = nullptr;
427 fCvSourceEventCount = 0;
428 #endif
430 try {
431 fJackBuffer = jackbridge_port_get_buffer(fJackPort, kClient.getEngine().getBufferSize());
433 catch(...) {
434 fJackBuffer = nullptr;
435 return;
438 if (! kIsInput)
439 jackbridge_midi_clear_buffer(fJackBuffer);
442 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
443 void setCvSourceEvents(EngineEvent* const events, const uint32_t eventCount) noexcept
445 fCvSourceEvents = events;
446 fCvSourceEventCount = eventCount;
448 #endif
450 uint32_t getEventCount() const noexcept override
452 if (fJackPort == nullptr)
453 return CarlaEngineEventPort::getEventCount();
455 CARLA_SAFE_ASSERT_RETURN(kIsInput, 0);
456 CARLA_SAFE_ASSERT_RETURN(fJackBuffer != nullptr, 0);
458 try {
459 return jackbridge_midi_get_event_count(fJackBuffer)
460 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
461 + fCvSourceEventCount
462 #endif
464 } CARLA_SAFE_EXCEPTION_RETURN("jack_midi_get_event_count", 0);
467 EngineEvent& getEvent(const uint32_t index) const noexcept override
469 if (fJackPort == nullptr)
470 return CarlaEngineEventPort::getEvent(index);
472 CARLA_SAFE_ASSERT_RETURN(kIsInput, kFallbackJackEngineEvent);
473 CARLA_SAFE_ASSERT_RETURN(fJackBuffer != nullptr, kFallbackJackEngineEvent);
475 return getEventUnchecked(index);
478 EngineEvent& getEventUnchecked(uint32_t index) const noexcept override
480 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
481 if (index < fCvSourceEventCount)
482 return fCvSourceEvents[index];
484 index -= fCvSourceEventCount;
485 #endif
487 jack_midi_event_t jackEvent;
489 bool test = false;
491 try {
492 test = jackbridge_midi_event_get(&jackEvent, fJackBuffer, index);
493 } CARLA_SAFE_EXCEPTION_RETURN("jack_midi_event_get", kFallbackJackEngineEvent);
495 if (! test)
496 return kFallbackJackEngineEvent;
498 CARLA_SAFE_ASSERT_RETURN(jackEvent.size < 0xFF /* uint8_t max */, kFallbackJackEngineEvent);
500 uint8_t port;
502 if (kIndexOffset < 0xFF /* uint8_t max */)
504 port = static_cast<uint8_t>(kIndexOffset);
506 else
508 port = 0;
509 carla_safe_assert_uint("kIndexOffset < 0xFF", __FILE__, __LINE__, kIndexOffset);
512 fRetEvent.time = jackEvent.time;
513 fRetEvent.fillFromMidiData(static_cast<uint8_t>(jackEvent.size), jackEvent.buffer, port);
515 return fRetEvent;
518 bool writeControlEvent(const uint32_t time, const uint8_t channel,
519 const EngineControlEventType type,
520 const uint16_t param,
521 const int8_t midiValue,
522 const float value) noexcept override
524 if (fJackPort == nullptr)
525 return CarlaEngineEventPort::writeControlEvent(time, channel, type, param, midiValue, value);
527 CARLA_SAFE_ASSERT_RETURN(! kIsInput, false);
528 CARLA_SAFE_ASSERT_RETURN(fJackBuffer != nullptr, false);
529 CARLA_SAFE_ASSERT_RETURN(type != kEngineControlEventTypeNull, false);
530 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, false);
531 CARLA_SAFE_ASSERT_RETURN(param < MAX_MIDI_VALUE, false);
532 CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
534 if (type == kEngineControlEventTypeParameter) {
535 CARLA_SAFE_ASSERT(! MIDI_IS_CONTROL_BANK_SELECT(param));
538 uint8_t data[3] = { 0, 0, 0 };
540 EngineControlEvent ctrlEvent = { type, param, midiValue, value, false };
541 const uint8_t size = ctrlEvent.convertToMidiData(channel, data);
543 if (size == 0)
544 return false;
546 try {
547 return jackbridge_midi_event_write(fJackBuffer, time, data, size);
548 } CARLA_SAFE_EXCEPTION_RETURN("jack_midi_event_write", false);
551 bool writeMidiEvent(const uint32_t time, const uint8_t channel, const uint8_t size, const uint8_t* const data) noexcept override
553 if (fJackPort == nullptr)
554 return CarlaEngineEventPort::writeMidiEvent(time, channel, size, data);
556 CARLA_SAFE_ASSERT_RETURN(! kIsInput, false);
557 CARLA_SAFE_ASSERT_RETURN(fJackBuffer != nullptr, false);
558 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS, false);
559 CARLA_SAFE_ASSERT_RETURN(size > 0, false);
560 CARLA_SAFE_ASSERT_RETURN(data != nullptr, false);
562 jack_midi_data_t jdata[size];
564 jdata[0] = static_cast<jack_midi_data_t>(MIDI_GET_STATUS_FROM_DATA(data) + channel);
566 for (uint8_t i=1; i < size; ++i)
567 jdata[i] = data[i];
569 try {
570 return jackbridge_midi_event_write(fJackBuffer, time, jdata, size);
571 } CARLA_SAFE_EXCEPTION_RETURN("jack_midi_event_write", false);
574 void invalidate() noexcept
576 fJackClient = nullptr;
577 fJackPort = nullptr;
580 void setMetaData(const char* const key, const char* const value, const char* const type) override
582 if (fJackPort == nullptr)
583 return CarlaEngineEventPort::setMetaData(key, value, type);
585 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
587 try {
588 if (const jack_uuid_t uuid = jackbridge_port_uuid(fJackPort))
589 jackbridge_set_property(fJackClient, uuid, key, value, type);
590 } CARLA_SAFE_EXCEPTION("Port setMetaData");
593 private:
594 jack_client_t* fJackClient;
595 jack_port_t* fJackPort;
596 void* fJackBuffer;
598 mutable EngineEvent fRetEvent;
600 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
601 EngineEvent* fCvSourceEvents;
602 uint32_t fCvSourceEventCount;
603 #endif
605 CarlaRecursiveMutex& fThreadSafeMetadataMutex;
606 JackPortDeletionCallback* const kDeletionCallback;
608 friend class CarlaEngineJackClient;
610 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackEventPort)
613 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
614 // -----------------------------------------------------------------------
615 // Jack Engine CV source ports
617 class CarlaEngineJackCVSourcePorts : public CarlaEngineCVSourcePorts
619 public:
620 CarlaEngineJackCVSourcePorts(const bool useClient)
621 : CarlaEngineCVSourcePorts(),
622 fUseClient(useClient),
623 fBuffer(nullptr),
624 fBufferToDeleteLater(nullptr)
627 ~CarlaEngineJackCVSourcePorts() override
629 if (fBufferToDeleteLater != nullptr)
631 delete[] fBufferToDeleteLater;
632 fBufferToDeleteLater = nullptr;
636 bool addCVSource(CarlaEngineCVPort* const port, const uint32_t portIndexOffset, const bool reconfigureNow) override
638 if (! fUseClient)
639 return CarlaEngineCVSourcePorts::addCVSource(port, portIndexOffset, reconfigureNow);
641 const CarlaRecursiveMutexLocker crml(pData->rmutex);
643 if (! CarlaEngineCVSourcePorts::addCVSource(port, portIndexOffset, reconfigureNow))
644 return false;
646 if (pData->cvs.size() == 1 && fBuffer == nullptr)
648 EngineEvent* const buffer = new EngineEvent[kMaxEngineEventInternalCount];
649 carla_zeroStructs(buffer, kMaxEngineEventInternalCount);
651 fBuffer = buffer;
654 return true;
657 bool removeCVSource(const uint32_t portIndexOffset) override
659 if (! fUseClient)
660 return CarlaEngineCVSourcePorts::removeCVSource(portIndexOffset);
662 const CarlaRecursiveMutexLocker crml(pData->rmutex);
664 if (! CarlaEngineCVSourcePorts::removeCVSource(portIndexOffset))
665 return false;
667 if (pData->cvs.size() == 0 && fBuffer != nullptr)
669 if (fBufferToDeleteLater != nullptr)
670 delete[] fBufferToDeleteLater;
672 fBufferToDeleteLater = fBuffer;
673 fBuffer = nullptr;
676 return true;
679 void initPortBuffers(const float* const* const buffers,
680 const uint32_t frames,
681 const bool sampleAccurate,
682 CarlaEngineEventPort* const eventPort) override
684 if (! fUseClient)
685 return CarlaEngineCVSourcePorts::initPortBuffers(buffers, frames, sampleAccurate, eventPort);
687 CARLA_SAFE_ASSERT_RETURN(buffers != nullptr,);
688 CARLA_SAFE_ASSERT_RETURN(eventPort != nullptr,);
690 const CarlaRecursiveMutexTryLocker crmtl(pData->rmutex);
692 if (! crmtl.wasLocked())
693 return;
695 const int numCVs = pData->cvs.size();
697 if (numCVs == 0)
698 return;
700 EngineEvent* const buffer = fBuffer;
701 CARLA_SAFE_ASSERT_RETURN(buffer != nullptr,);
703 uint32_t eventCount = 0;
704 float v, min, max;
706 for (int i = 0; i < numCVs && eventCount < kMaxEngineEventInternalCount; ++i)
708 CarlaEngineEventCV& ecv(pData->cvs.getReference(i));
709 CARLA_SAFE_ASSERT_CONTINUE(ecv.cvPort != nullptr);
710 CARLA_SAFE_ASSERT_CONTINUE(buffers[i] != nullptr);
712 float previousValue = ecv.previousValue;
713 ecv.cvPort->getRange(min, max);
715 v = buffers[i][0];
717 if (carla_isNotEqual(v, previousValue))
719 previousValue = v;
721 EngineEvent& event(buffer[eventCount++]);
723 event.type = kEngineEventTypeControl;
724 event.time = 0;
725 event.channel = kEngineEventNonMidiChannel;
727 event.ctrl.type = kEngineControlEventTypeParameter;
728 event.ctrl.param = static_cast<uint16_t>(ecv.indexOffset);
729 event.ctrl.midiValue = -1;
730 event.ctrl.normalizedValue = carla_fixedValue(0.0f, 1.0f, (v - min) / (max - min));
733 ecv.previousValue = previousValue;
736 if (eventCount != 0)
737 if (CarlaEngineJackEventPort* const jackEventPort = dynamic_cast<CarlaEngineJackEventPort*>(eventPort))
738 jackEventPort->setCvSourceEvents(buffer, eventCount);
741 CarlaRecursiveMutex& getMutex() const noexcept
743 return pData->rmutex;
746 uint32_t getPortCount() const noexcept
748 return static_cast<uint32_t>(pData->cvs.size());
751 CarlaEngineCVPort* getPort(const uint32_t portIndexOffset) const
753 const int ioffset = static_cast<int>(portIndexOffset);
754 return pData->cvs[ioffset].cvPort;
757 void resetGraphAndPlugin() noexcept
759 pData->graph = nullptr;
760 pData->plugin.reset();
763 void setGraphAndPlugin(PatchbayGraph* const graph, const CarlaPluginPtr plugin) noexcept
765 pData->graph = graph;
766 pData->plugin = plugin;
769 private:
770 const bool fUseClient;
771 EngineEvent* fBuffer;
772 EngineEvent* fBufferToDeleteLater;
774 CARLA_DECLARE_NON_COPYABLE(CarlaEngineJackCVSourcePorts)
776 #endif
778 // -----------------------------------------------------------------------
779 // Jack Engine client
781 class CarlaEngineJackClient : public CarlaEngineClientForSubclassing,
782 private JackPortDeletionCallback
784 public:
785 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
786 CarlaEngineJackClient(const CarlaEngine& engine,
787 EngineInternalGraph& egraph,
788 CarlaRecursiveMutex& rmutex,
789 const CarlaPluginPtr plugin,
790 const CarlaString& mainClientName,
791 jack_client_t* const jackClient)
792 : CarlaEngineClientForSubclassing(engine, egraph, plugin),
793 #else
794 CarlaEngineJackClient(const CarlaEngine& engine,
795 CarlaRecursiveMutex& rmutex,
796 const CarlaString& mainClientName,
797 jack_client_t* const jackClient)
798 : CarlaEngineClientForSubclassing(engine),
799 #endif
800 fJackClient(jackClient),
801 fUseClient(engine.getProccessMode() == ENGINE_PROCESS_MODE_SINGLE_CLIENT ||
802 engine.getProccessMode() == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS),
803 fAudioPorts(),
804 fCVPorts(),
805 fEventPorts(),
806 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
807 fCVSourcePorts(fUseClient),
808 fPreRenameMutex(),
809 fPreRenameConnections(),
810 fPreRenamePluginId(),
811 fPreRenamePluginIcon(),
812 fReservedPluginPtr(),
813 #endif
814 fThreadSafeMetadataMutex(rmutex),
815 fMainClientName(mainClientName)
817 carla_debug("CarlaEngineJackClient::CarlaEngineJackClient(%p)", jackClient);
819 if (fUseClient)
821 CARLA_SAFE_ASSERT(jackClient != nullptr);
823 else
825 CARLA_SAFE_ASSERT(jackClient == nullptr);
829 ~CarlaEngineJackClient() noexcept override
831 carla_debug("CarlaEngineJackClient::~CarlaEngineJackClient()");
833 if (getProcessMode() == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS && fJackClient != nullptr) // FIXME
834 jackbridge_client_close(fJackClient);
836 // ports must have been deleted by now!
837 //fAudioPorts.clear();
838 //fCVPorts.clear();
839 //fEventPorts.clear();
841 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
842 const CarlaMutexLocker cml(fPreRenameMutex);
844 fPreRenameConnections.clear();
845 fPreRenamePluginId.clear();
846 fPreRenamePluginIcon.clear();
847 #endif
850 void activate() noexcept override
852 carla_debug("CarlaEngineJackClient::activate()");
854 if (getProcessMode() == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
856 CARLA_SAFE_ASSERT_RETURN(fJackClient != nullptr && ! isActive(),);
858 try {
859 jackbridge_activate(fJackClient);
860 } catch(...) {}
863 CarlaEngineClient::activate();
865 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
866 const CarlaMutexLocker cml(fPreRenameMutex);
868 if (fJackClient != nullptr)
870 // restore pre-rename connections
871 const char* portNameA = nullptr;
872 const char* portNameB = nullptr;
873 bool doConnection = false;
875 for (CarlaStringList::Itenerator it = fPreRenameConnections.begin2(); it.valid(); it.next())
877 const bool connectNow = doConnection;
878 doConnection = !doConnection;
880 if (connectNow)
881 portNameB = it.getValue(nullptr);
882 else
883 portNameA = it.getValue(nullptr);
885 if (! connectNow)
886 continue;
888 CARLA_SAFE_ASSERT_CONTINUE(portNameA != nullptr && portNameA[0] != '\0');
889 CARLA_SAFE_ASSERT_CONTINUE(portNameB != nullptr && portNameB[0] != '\0');
891 jackbridge_connect(fJackClient, portNameA, portNameB);
894 if (fPreRenamePluginId.isNotEmpty())
896 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
898 if (char* const uuidstr = jackbridge_client_get_uuid(fJackClient))
900 jack_uuid_t uuid;
902 if (jackbridge_uuid_parse(uuidstr, &uuid))
904 jackbridge_set_property(fJackClient, uuid,
905 URI_MAIN_CLIENT_NAME,
906 fMainClientName,
907 URI_TYPE_STRING);
909 jackbridge_set_property(fJackClient, uuid,
910 URI_PLUGIN_ID,
911 fPreRenamePluginId,
912 URI_TYPE_INTEGER);
914 if (fPreRenamePluginIcon.isNotEmpty())
915 jackbridge_set_property(fJackClient, uuid,
916 URI_PLUGIN_ICON,
917 fPreRenamePluginIcon,
918 URI_TYPE_STRING);
921 jackbridge_free(uuidstr);
926 fPreRenameConnections.clear();
927 fPreRenamePluginId.clear();
928 fPreRenamePluginIcon.clear();
929 #endif
932 void deactivate(const bool willClose) noexcept override
934 carla_debug("CarlaEngineJackClient::deactivate(%s)", bool2str(willClose));
936 if (getProcessMode() == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
938 if (fJackClient != nullptr && isActive())
940 try {
941 jackbridge_deactivate(fJackClient);
942 } catch(...) {}
946 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
947 if (willClose)
949 fCVSourcePorts.resetGraphAndPlugin();
950 fReservedPluginPtr = nullptr;
952 #endif
954 CarlaEngineClient::deactivate(willClose);
957 bool isOk() const noexcept override
959 if (fUseClient)
960 return (fJackClient != nullptr);
962 return CarlaEngineClient::isOk();
965 CarlaEnginePort* addPort(const EnginePortType portType, const char* const name, const bool isInput, const uint32_t indexOffset) override
967 carla_debug("CarlaEngineJackClient::addPort(%i:%s, \"%s\", %s)", portType, EnginePortType2Str(portType), name, bool2str(isInput));
969 jack_port_t* jackPort = nullptr;
970 const char* realName = name;
972 // Create JACK port first, if needed
973 if (fUseClient)
975 CARLA_SAFE_ASSERT_RETURN(fJackClient != nullptr, nullptr);
977 realName = pData->getUniquePortName(name);
979 switch (portType)
981 case kEnginePortTypeNull:
982 break;
983 case kEnginePortTypeAudio:
984 jackPort = jackbridge_port_register(fJackClient,
985 realName,
986 JACK_DEFAULT_AUDIO_TYPE,
987 isInput ? JackPortIsInput : JackPortIsOutput,
989 break;
990 case kEnginePortTypeCV:
991 jackPort = jackbridge_port_register(fJackClient,
992 realName,
993 JACK_DEFAULT_AUDIO_TYPE,
994 static_cast<uint64_t>(JackPortIsControlVoltage |
995 (isInput ? JackPortIsInput
996 : JackPortIsOutput)),
998 break;
999 case kEnginePortTypeEvent:
1000 jackPort = jackbridge_port_register(fJackClient,
1001 realName,
1002 JACK_DEFAULT_MIDI_TYPE,
1003 isInput ? JackPortIsInput : JackPortIsOutput,
1005 break;
1008 CARLA_SAFE_ASSERT_RETURN(jackPort != nullptr, nullptr);
1011 // Create Engine port
1012 switch (portType)
1014 case kEnginePortTypeNull:
1015 break;
1016 case kEnginePortTypeAudio: {
1017 pData->addAudioPortName(isInput, realName);
1018 if (realName != name) delete[] realName;
1019 CarlaEngineJackAudioPort* const enginePort(new CarlaEngineJackAudioPort(*this,
1020 isInput,
1021 indexOffset,
1022 fJackClient,
1023 jackPort,
1024 fThreadSafeMetadataMutex,
1025 this));
1026 fAudioPorts.append(enginePort);
1027 return enginePort;
1029 case kEnginePortTypeCV: {
1030 pData->addCVPortName(isInput, realName);
1031 if (realName != name) delete[] realName;
1032 CarlaEngineJackCVPort* const enginePort(new CarlaEngineJackCVPort(*this,
1033 isInput,
1034 indexOffset,
1035 fJackClient,
1036 jackPort,
1037 fThreadSafeMetadataMutex,
1038 this));
1039 fCVPorts.append(enginePort);
1040 return enginePort;
1042 case kEnginePortTypeEvent: {
1043 pData->addEventPortName(isInput, realName);
1044 if (realName != name) delete[] realName;
1045 CarlaEngineJackEventPort* const enginePort(new CarlaEngineJackEventPort(*this,
1046 isInput,
1047 indexOffset,
1048 fJackClient,
1049 jackPort,
1050 fThreadSafeMetadataMutex,
1051 this));
1052 fEventPorts.append(enginePort);
1053 return enginePort;
1057 carla_stderr("CarlaEngineJackClient::addPort(%i, \"%s\", %s) - invalid type", portType, name, bool2str(isInput));
1058 return nullptr;
1061 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1062 CarlaEngineCVSourcePorts* createCVSourcePorts() override
1064 fCVSourcePorts.setGraphAndPlugin(getPatchbayGraphOrNull(), getPlugin());
1065 return &fCVSourcePorts;
1068 CarlaEngineJackCVSourcePorts& getCVSourcePorts() noexcept
1070 return fCVSourcePorts;
1072 #endif
1074 void invalidate() noexcept
1076 for (LinkedList<CarlaEngineJackAudioPort*>::Itenerator it = fAudioPorts.begin2(); it.valid(); it.next())
1078 CarlaEngineJackAudioPort* const port(it.getValue(nullptr));
1079 CARLA_SAFE_ASSERT_CONTINUE(port != nullptr);
1081 port->invalidate();
1084 for (LinkedList<CarlaEngineJackCVPort*>::Itenerator it = fCVPorts.begin2(); it.valid(); it.next())
1086 CarlaEngineJackCVPort* const port(it.getValue(nullptr));
1087 CARLA_SAFE_ASSERT_CONTINUE(port != nullptr);
1089 port->invalidate();
1092 for (LinkedList<CarlaEngineJackEventPort*>::Itenerator it = fEventPorts.begin2(); it.valid(); it.next())
1094 CarlaEngineJackEventPort* const port(it.getValue(nullptr));
1095 CARLA_SAFE_ASSERT_CONTINUE(port != nullptr);
1097 port->invalidate();
1100 fJackClient = nullptr;
1101 CarlaEngineClient::deactivate(true);
1104 const char* getJackClientName() const noexcept
1106 CARLA_SAFE_ASSERT_RETURN(fJackClient != nullptr, nullptr);
1108 try {
1109 return jackbridge_get_client_name(fJackClient);
1110 } CARLA_SAFE_EXCEPTION_RETURN("jack_get_client_name", nullptr);
1113 void jackAudioPortDeleted(CarlaEngineJackAudioPort* const port) noexcept override
1115 fAudioPorts.removeAll(port);
1118 void jackCVPortDeleted(CarlaEngineJackCVPort* const port) noexcept override
1120 fCVPorts.removeAll(port);
1123 void jackEventPortDeleted(CarlaEngineJackEventPort* const port) noexcept override
1125 fEventPorts.removeAll(port);
1128 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1129 bool renameInSingleClient(const CarlaString& newClientName)
1131 const CarlaString clientNamePrefix(newClientName + ":");
1133 return _renamePorts(fAudioPorts, clientNamePrefix) &&
1134 _renamePorts(fCVPorts, clientNamePrefix) &&
1135 _renamePorts(fEventPorts, clientNamePrefix);
1138 void closeForRename(jack_client_t* const newClient, const CarlaString& newClientName) noexcept
1140 if (fJackClient != nullptr)
1142 if (isActive())
1145 const CarlaString clientNamePrefix(newClientName + ":");
1147 // store current client connections
1148 const CarlaMutexLocker cml(fPreRenameMutex);
1150 fPreRenameConnections.clear();
1151 fPreRenamePluginId.clear();
1152 fPreRenamePluginIcon.clear();
1154 _savePortsConnections(fAudioPorts, clientNamePrefix);
1155 _savePortsConnections(fCVPorts, clientNamePrefix);
1156 _savePortsConnections(fEventPorts, clientNamePrefix);
1157 _saveProperties();
1160 try {
1161 jackbridge_deactivate(fJackClient);
1162 } catch(...) {}
1165 try {
1166 jackbridge_client_close(fJackClient);
1167 } catch(...) {}
1169 invalidate();
1172 fAudioPorts.clear();
1173 fCVPorts.clear();
1174 fEventPorts.clear();
1175 pData->clearPorts();
1177 fJackClient = newClient;
1180 void reservePluginPtr(CarlaPluginPtr* const pluginPtr)
1182 fReservedPluginPtr = pluginPtr;
1185 void setNewPluginId(const uint id) const
1187 CARLA_SAFE_ASSERT_RETURN(fJackClient != nullptr,);
1189 // NOTE: no fThreadSafeMetadataMutex lock here, assumed done from caller
1191 if (char* const uuidstr = jackbridge_client_get_uuid(fJackClient))
1193 jack_uuid_t uuid;
1195 if (jackbridge_uuid_parse(uuidstr, &uuid))
1197 char buf[32];
1198 std::snprintf(buf, 31, "%u", id);
1199 buf[31] = '\0';
1200 jackbridge_set_property(fJackClient, uuid,
1201 URI_PLUGIN_ID,
1202 buf,
1203 URI_TYPE_INTEGER);
1206 jackbridge_free(uuidstr);
1209 #endif
1211 private:
1212 jack_client_t* fJackClient;
1213 const bool fUseClient;
1215 LinkedList<CarlaEngineJackAudioPort*> fAudioPorts;
1216 LinkedList<CarlaEngineJackCVPort*> fCVPorts;
1217 LinkedList<CarlaEngineJackEventPort*> fEventPorts;
1219 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1220 CarlaEngineJackCVSourcePorts fCVSourcePorts;
1222 CarlaMutex fPreRenameMutex;
1223 CarlaStringList fPreRenameConnections;
1224 CarlaString fPreRenamePluginId;
1225 CarlaString fPreRenamePluginIcon;
1227 CarlaScopedPointer<CarlaPluginPtr> fReservedPluginPtr;
1229 template<typename T>
1230 bool _renamePorts(const LinkedList<T*>& t, const CarlaString& clientNamePrefix)
1232 for (typename LinkedList<T*>::Itenerator it = t.begin2(); it.valid(); it.next())
1234 T* const port(it.getValue(nullptr));
1235 CARLA_SAFE_ASSERT_CONTINUE(port != nullptr);
1236 CARLA_SAFE_ASSERT_CONTINUE(port->fJackPort != nullptr);
1238 const char* shortPortName(jackbridge_port_short_name(port->fJackPort));
1239 CARLA_SAFE_ASSERT_CONTINUE(shortPortName != nullptr && shortPortName[0] != '\0');
1241 const char* const oldClientNameSep(std::strstr(shortPortName, ":"));
1242 CARLA_SAFE_ASSERT_CONTINUE(oldClientNameSep != nullptr && oldClientNameSep[0] != '\0' && oldClientNameSep[1] != '\0');
1244 shortPortName += oldClientNameSep-shortPortName + 1;
1246 const CarlaString newPortName(clientNamePrefix + shortPortName);
1248 if (! jackbridge_port_rename(fJackClient, port->fJackPort, newPortName))
1249 return false;
1252 return true;
1255 template<typename T>
1256 void _savePortsConnections(const LinkedList<T*>& t, const CarlaString& clientNamePrefix)
1258 for (typename LinkedList<T*>::Itenerator it = t.begin2(); it.valid(); it.next())
1260 T* const port(it.getValue(nullptr));
1261 CARLA_SAFE_ASSERT_CONTINUE(port != nullptr);
1262 CARLA_SAFE_ASSERT_CONTINUE(port->fJackPort != nullptr);
1264 const char* const shortPortName(jackbridge_port_short_name(port->fJackPort));
1265 CARLA_SAFE_ASSERT_CONTINUE(shortPortName != nullptr && shortPortName[0] != '\0');
1267 const CarlaString portName(clientNamePrefix + shortPortName);
1269 if (const char** const connections = jackbridge_port_get_all_connections(fJackClient, port->fJackPort))
1271 for (int i=0; connections[i] != nullptr; ++i)
1273 if (port->kIsInput)
1275 fPreRenameConnections.append(connections[i]);
1276 fPreRenameConnections.append(portName);
1278 else
1280 fPreRenameConnections.append(portName);
1281 fPreRenameConnections.append(connections[i]);
1285 jackbridge_free(connections);
1290 void _saveProperties()
1292 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
1294 if (char* const uuidstr = jackbridge_client_get_uuid(fJackClient))
1296 jack_uuid_t uuid;
1298 const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
1299 jackbridge_free(uuidstr);
1301 CARLA_CUSTOM_SAFE_ASSERT_ONCE_RETURN("JACK meta-data support unavailable", parsed,);
1303 char* value = nullptr;
1304 char* type = nullptr;
1306 CARLA_SAFE_ASSERT_RETURN(jackbridge_get_property(uuid,
1307 URI_PLUGIN_ID,
1308 &value,
1309 &type),);
1310 CARLA_SAFE_ASSERT_RETURN(type != nullptr,);
1311 CARLA_SAFE_ASSERT_RETURN(std::strcmp(type, URI_TYPE_INTEGER) == 0,);
1312 fPreRenamePluginId = value;
1314 jackbridge_free(value);
1315 jackbridge_free(type);
1316 value = type = nullptr;
1318 if (jackbridge_get_property(uuid, URI_PLUGIN_ICON, &value, &type))
1320 CARLA_SAFE_ASSERT_RETURN(type != nullptr,);
1321 CARLA_SAFE_ASSERT_RETURN(std::strcmp(type, URI_TYPE_STRING) == 0,);
1322 fPreRenamePluginIcon = value;
1324 jackbridge_free(value);
1325 jackbridge_free(type);
1329 #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH
1331 CarlaRecursiveMutex& fThreadSafeMetadataMutex;
1332 const CarlaString& fMainClientName;
1334 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJackClient)
1337 // -----------------------------------------------------------------------
1338 // Jack Engine
1340 class CarlaEngineJack : public CarlaEngine
1341 #ifndef BUILD_BRIDGE
1342 , private CarlaThread
1343 #endif
1345 public:
1346 CarlaEngineJack()
1347 : CarlaEngine(),
1348 #ifndef BUILD_BRIDGE
1349 CarlaThread("CarlaEngineJackCallbacks"),
1350 #endif
1351 fClient(nullptr),
1352 fExternalPatchbayHost(true),
1353 fExternalPatchbayOsc(true),
1354 fFreewheel(false),
1355 fClientName(),
1356 fThreadSafeMetadataMutex(),
1357 #ifdef BUILD_BRIDGE
1358 fIsRunning(false)
1359 #else
1360 fClientNamePrefix(),
1361 fTimebaseMaster(false),
1362 fTimebaseRolling(false),
1363 fTimebaseUsecs(0),
1364 fUsedGroups(),
1365 fUsedPorts(),
1366 fUsedConnections(),
1367 fPatchbayProcThreadProtectionMutex(),
1368 fRetConns(),
1369 fLastPatchbaySetGroupPos(),
1370 fPostPonedEvents(),
1371 fPostPonedEventsMutex(),
1372 fIsInternalClient(false)
1373 #endif
1375 carla_debug("CarlaEngineJack::CarlaEngineJack()");
1377 #ifdef BUILD_BRIDGE
1378 pData->options.processMode = ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS;
1379 #else
1380 carla_zeroPointers(fRackPorts, kRackPortCount);
1381 #endif
1384 ~CarlaEngineJack() noexcept override
1386 carla_debug("CarlaEngineJack::~CarlaEngineJack()");
1387 CARLA_SAFE_ASSERT(fClient == nullptr);
1389 #ifndef BUILD_BRIDGE
1390 fUsedGroups.clear();
1391 fUsedPorts.clear();
1392 fUsedConnections.clear();
1393 CARLA_SAFE_ASSERT(fPostPonedEvents.count() == 0);
1394 #endif
1397 // -------------------------------------------------------------------
1398 // Maximum values
1400 uint getMaxClientNameSize() const noexcept override
1402 #ifndef BUILD_BRIDGE
1403 if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT ||
1404 pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
1405 #endif
1407 try {
1408 return static_cast<uint>(jackbridge_client_name_size()-1);
1409 } CARLA_SAFE_EXCEPTION_RETURN("jack_client_name_size", 32);
1412 return CarlaEngine::getMaxClientNameSize();
1415 uint getMaxPortNameSize() const noexcept override
1417 if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT || pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
1419 try {
1420 return static_cast<uint>(jackbridge_port_name_size()-1);
1421 } CARLA_SAFE_EXCEPTION_RETURN("jack_port_name_size", 255);
1424 return CarlaEngine::getMaxPortNameSize();
1427 // -------------------------------------------------------------------
1428 // Virtual, per-engine type calls
1430 bool init(const char* const clientName) override
1432 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr || (clientName != nullptr && clientName[0] != '\0'), false);
1433 carla_debug("CarlaEngineJack::init(\"%s\")", clientName);
1435 if (!jackbridge_is_ok())
1437 setLastError("JACK is not available or installed");
1438 return false;
1441 fFreewheel = false;
1442 fExternalPatchbayHost = true;
1443 fExternalPatchbayOsc = true;
1445 CarlaString truncatedClientName;
1447 if (fClient == nullptr && clientName != nullptr)
1449 truncatedClientName = clientName;
1450 truncatedClientName.truncate(getMaxClientNameSize());
1453 #ifdef BUILD_BRIDGE
1454 fIsRunning = true;
1456 if (! pData->init(truncatedClientName))
1458 close();
1459 setLastError("Failed to init internal data");
1460 return false;
1463 if (pData->bufferSize == 0 || carla_isEqual(pData->sampleRate, 0.0))
1465 // open temp client to get initial buffer-size and sample-rate values
1466 if (jack_client_t* const tmpClient = jackbridge_client_open(truncatedClientName, JackNoStartServer, nullptr))
1468 pData->bufferSize = jackbridge_get_buffer_size(tmpClient);
1469 pData->sampleRate = jackbridge_get_sample_rate(tmpClient);
1471 jackbridge_client_close(tmpClient);
1473 else
1475 close();
1476 setLastError("Failed to init temporary jack client");
1477 return false;
1481 return true;
1483 #else // BUILD_BRIDGE
1484 if (fClient == nullptr && clientName != nullptr)
1485 fClient = jackbridge_client_open(truncatedClientName, JackNoStartServer, nullptr);
1487 if (fClient == nullptr)
1489 setLastError("Failed to create new JACK client");
1490 return false;
1493 const char* const jackClientName = jackbridge_get_client_name(fClient);
1495 if (! pData->init(jackClientName))
1497 jackbridge_client_close(fClient);
1498 fClient = nullptr;
1499 setLastError("Failed to init internal data");
1500 return false;
1503 // if main jack client does not match our requested one, setup client name prefix as needed
1504 if (truncatedClientName != jackClientName)
1506 if (const char* const suffix = std::strrchr(jackClientName, '-'))
1508 if (fClientNamePrefix.isNotEmpty())
1510 fClientNamePrefix.truncate(fClientNamePrefix.rfind('.') + 1);
1512 else
1514 fClientNamePrefix = truncatedClientName;
1515 fClientNamePrefix += ".";
1518 fClientNamePrefix += suffix + 1;
1519 fClientNamePrefix += "/";
1523 fClientName = jackClientName;
1525 const EngineOptions& opts(pData->options);
1527 pData->bufferSize = jackbridge_get_buffer_size(fClient);
1528 pData->sampleRate = jackbridge_get_sample_rate(fClient);
1529 pData->initTime(opts.transportExtra);
1531 jackbridge_set_thread_init_callback(fClient, carla_jack_thread_init_callback, nullptr);
1532 jackbridge_set_buffer_size_callback(fClient, carla_jack_bufsize_callback, this);
1533 jackbridge_set_sample_rate_callback(fClient, carla_jack_srate_callback, this);
1534 jackbridge_set_freewheel_callback(fClient, carla_jack_freewheel_callback, this);
1535 // jackbridge_set_latency_callback(fClient, carla_jack_latency_callback, this);
1536 jackbridge_set_process_callback(fClient, carla_jack_process_callback, this);
1537 jackbridge_on_shutdown(fClient, carla_jack_shutdown_callback, this);
1539 fTimebaseRolling = false;
1541 if (opts.transportMode == ENGINE_TRANSPORT_MODE_JACK)
1542 fTimebaseMaster = jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this);
1543 else
1544 fTimebaseMaster = false;
1546 initJackPatchbay(true, false, jackClientName, pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY);
1548 jackbridge_set_client_registration_callback(fClient, carla_jack_client_registration_callback, this);
1549 jackbridge_set_port_registration_callback(fClient, carla_jack_port_registration_callback, this);
1550 jackbridge_set_port_connect_callback(fClient, carla_jack_port_connect_callback, this);
1551 jackbridge_set_port_rename_callback(fClient, carla_jack_port_rename_callback, this);
1552 jackbridge_set_property_change_callback(fClient, carla_jack_property_change_callback, this);
1553 jackbridge_set_xrun_callback(fClient, carla_jack_xrun_callback, this);
1555 if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK || opts.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
1557 fRackPorts[kRackPortAudioIn1] = jackbridge_port_register(fClient, "audio-in1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
1558 fRackPorts[kRackPortAudioIn2] = jackbridge_port_register(fClient, "audio-in2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0);
1559 fRackPorts[kRackPortAudioOut1] = jackbridge_port_register(fClient, "audio-out1", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
1560 fRackPorts[kRackPortAudioOut2] = jackbridge_port_register(fClient, "audio-out2", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
1561 fRackPorts[kRackPortEventIn] = jackbridge_port_register(fClient, "events-in", JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0);
1562 fRackPorts[kRackPortEventOut] = jackbridge_port_register(fClient, "events-out", JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0);
1564 if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
1566 // FIXME?
1567 pData->graph.create(0, 0, 0, 0);
1569 else
1571 pData->graph.create(2, 2, 0, 0);
1572 // pData->graph.setUsingExternalHost(true);
1573 // pData->graph.setUsingExternalOSC(true);
1574 patchbayRefresh(true, false, false);
1578 # ifdef HAVE_LIBLO
1580 const CarlaString& tcp(pData->osc.getServerPathTCP());
1581 const CarlaString& udp(pData->osc.getServerPathUDP());
1583 if (tcp.isNotEmpty() || udp.isNotEmpty())
1585 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
1587 if (char* const uuidstr = jackbridge_client_get_uuid(fClient))
1589 jack_uuid_t uuid;
1591 if (jackbridge_uuid_parse(uuidstr, &uuid))
1593 if (tcp.isNotEmpty())
1594 jackbridge_set_property(fClient, uuid,
1595 "https://kx.studio/ns/carla/osc-tcp", tcp, URI_TYPE_STRING);
1597 if (udp.isNotEmpty())
1598 jackbridge_set_property(fClient, uuid,
1599 "https://kx.studio/ns/carla/osc-udp", udp, URI_TYPE_STRING);
1602 jackbridge_free(uuidstr);
1606 # endif
1608 if (jackbridge_activate(fClient))
1610 if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
1611 opts.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
1613 if (pData->options.audioDevice != nullptr &&
1614 std::strcmp(pData->options.audioDevice, "Auto-Connect ON") == 0 &&
1615 std::getenv("LADISH_APP_NAME") == nullptr &&
1616 std::getenv("NSM_URL") == nullptr)
1618 char strBuf[STR_MAX];
1620 if (jackbridge_port_by_name(fClient, "system:capture_1") != nullptr)
1622 std::snprintf(strBuf, STR_MAX, "%s:audio-in1", jackClientName);
1623 strBuf[STR_MAX-1] = '\0';
1625 jackbridge_connect(fClient, "system:capture_1", strBuf);
1627 std::snprintf(strBuf, STR_MAX, "%s:audio-in2", jackClientName);
1628 strBuf[STR_MAX-1] = '\0';
1630 if (jackbridge_port_by_name(fClient, "system:capture_2") != nullptr)
1631 jackbridge_connect(fClient, "system:capture_2", strBuf);
1632 else
1633 jackbridge_connect(fClient, "system:capture_1", strBuf);
1636 if (jackbridge_port_by_name(fClient, "system:playback_1") != nullptr)
1638 std::snprintf(strBuf, STR_MAX, "%s:audio-out1", jackClientName);
1639 strBuf[STR_MAX-1] = '\0';
1641 jackbridge_connect(fClient, strBuf, "system:playback_1");
1643 std::snprintf(strBuf, STR_MAX, "%s:audio-out2", jackClientName);
1644 strBuf[STR_MAX-1] = '\0';
1646 if (jackbridge_port_by_name(fClient, "system:playback_2") != nullptr)
1647 jackbridge_connect(fClient, strBuf, "system:playback_2");
1648 else
1649 jackbridge_connect(fClient, strBuf, "system:playback_1");
1654 if (fIsInternalClient)
1655 startThread();
1657 callback(true, true,
1658 ENGINE_CALLBACK_ENGINE_STARTED, 0,
1659 opts.processMode,
1660 opts.transportMode,
1661 static_cast<int>(pData->bufferSize),
1662 static_cast<float>(pData->sampleRate),
1663 getCurrentDriverName());
1664 return true;
1667 if (opts.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
1668 opts.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
1670 pData->graph.destroy();
1673 pData->close();
1674 jackbridge_client_close(fClient);
1675 fClient = nullptr;
1677 setLastError("Failed to activate the JACK client");
1678 return false;
1679 #endif // BUILD_BRIDGE
1682 #ifndef BUILD_BRIDGE
1683 bool initInternal(jack_client_t* const client)
1685 fClient = client;
1686 fIsInternalClient = true;
1688 return init(nullptr);
1690 #endif
1692 bool close() override
1694 carla_debug("CarlaEngineJack::close()");
1696 #ifdef BUILD_BRIDGE
1697 fClient = nullptr;
1698 fIsRunning = false;
1699 CarlaEngine::close();
1700 return true;
1701 #else
1702 if (fIsInternalClient)
1703 stopThread(-1);
1705 // deactivate client ASAP
1706 if (fClient != nullptr)
1707 jackbridge_deactivate(fClient);
1709 // clear engine data
1710 CarlaEngine::close();
1712 // now close client
1713 if (fClient != nullptr)
1715 jackbridge_client_close(fClient);
1716 fClient = nullptr;
1719 fClientName.clear();
1720 fUsedGroups.clear();
1721 fUsedPorts.clear();
1722 fUsedConnections.clear();
1723 fPostPonedEvents.clear();
1725 // clear rack/patchbay stuff
1726 if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
1727 pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
1729 carla_zeroPointers(fRackPorts, kRackPortCount);
1730 pData->graph.destroy();
1733 return true;
1734 #endif
1737 bool hasIdleOnMainThread() const noexcept override
1739 #ifndef BUILD_BRIDGE
1740 return !fIsInternalClient;
1741 #else
1742 return true;
1743 #endif
1746 bool isRunning() const noexcept override
1748 #ifdef BUILD_BRIDGE
1749 return (fClient != nullptr || fIsRunning);
1750 #else
1751 return (fClient != nullptr);
1752 #endif
1755 bool isOffline() const noexcept override
1757 return fFreewheel;
1760 EngineType getType() const noexcept override
1762 return kEngineTypeJack;
1765 const char* getCurrentDriverName() const noexcept override
1767 return "JACK";
1770 #ifndef BUILD_BRIDGE
1771 float getDSPLoad() const noexcept override
1773 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, 0.0f);
1775 return jackbridge_cpu_load(fClient);
1778 void callback(const bool sendHost, const bool sendOsc,
1779 const EngineCallbackOpcode action, const uint pluginId,
1780 const int value1, const int value2, const int value3,
1781 const float valuef, const char* const valueStr) noexcept override
1783 if (action == ENGINE_CALLBACK_PROJECT_LOAD_FINISHED)
1785 if (fTimebaseMaster)
1787 // project finished loading, need to set bpm here, so we force an update of timebase master
1788 transportRelocate(pData->timeInfo.frame);
1792 CarlaEngine::callback(sendHost, sendOsc, action, pluginId, value1, value2, value3, valuef, valueStr);
1795 void idle() noexcept override
1797 LinkedList<PostPonedJackEvent> events;
1798 const PostPonedJackEvent nullEvent = {};
1801 const CarlaMutexLocker cml(fPostPonedEventsMutex);
1803 if (fPostPonedEvents.count() > 0)
1804 fPostPonedEvents.moveTo(events);
1807 for (LinkedList<PostPonedJackEvent>::Itenerator it = events.begin2(); it.valid(); it.next())
1809 const PostPonedJackEvent& ev(it.getValue(nullEvent));
1810 CARLA_SAFE_ASSERT_CONTINUE(ev.type != PostPonedJackEvent::kTypeNull);
1812 switch (ev.type)
1814 case PostPonedJackEvent::kTypeNull:
1815 break;
1816 case PostPonedJackEvent::kTypeClientUnregister:
1817 handleJackClientUnregistrationCallback(ev.clientUnregister.name);
1818 break;
1819 case PostPonedJackEvent::kTypePortRegister:
1820 handleJackPortRegistrationCallback(ev.portRegister.fullName,
1821 ev.portRegister.shortName,
1822 ev.portRegister.hints);
1823 break;
1824 case PostPonedJackEvent::kTypePortUnregister:
1825 handleJackPortUnregistrationCallback(ev.portUnregister.fullName);
1826 break;
1827 case PostPonedJackEvent::kTypePortConnect:
1828 handleJackPortConnectCallback(ev.portConnect.portNameA,
1829 ev.portConnect.portNameB);
1830 break;
1831 case PostPonedJackEvent::kTypePortDisconnect:
1832 handleJackPortDisconnectCallback(ev.portDisconnect.portNameA,
1833 ev.portDisconnect.portNameB);
1834 break;
1835 case PostPonedJackEvent::kTypePortRename:
1836 handleJackPortRenameCallback(ev.portRename.oldFullName,
1837 ev.portRename.newFullName,
1838 ev.portRename.newShortName);
1839 break;
1840 case PostPonedJackEvent::kTypeClientPositionChange:
1841 handleJackClientPositionChangeCallback(ev.clientPositionChange.uuid);
1842 break;
1846 events.clear();
1848 CarlaEngine::idle();
1850 #endif
1852 bool setBufferSizeAndSampleRate(const uint bufferSize, const double sampleRate) override
1854 CARLA_SAFE_ASSERT_RETURN(carla_isEqual(pData->sampleRate, sampleRate), false);
1855 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
1857 try {
1858 return jackbridge_set_buffer_size(fClient, bufferSize);
1859 } CARLA_SAFE_EXCEPTION_RETURN("setBufferSizeAndSampleRate", false);
1862 EngineTimeInfo getTimeInfo() const noexcept override
1864 if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK)
1865 return CarlaEngine::getTimeInfo();
1866 if (pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
1867 return CarlaEngine::getTimeInfo();
1869 jack_position_t jpos;
1871 // invalidate
1872 jpos.unique_1 = 1;
1873 jpos.unique_2 = 2;
1875 EngineTimeInfo timeInfo;
1876 const bool playing = jackbridge_transport_query(fClient, &jpos) == JackTransportRolling;
1878 if (jpos.unique_1 != jpos.unique_2)
1880 timeInfo.playing = false;
1881 timeInfo.frame = 0;
1882 timeInfo.usecs = 0;
1883 timeInfo.bbt.valid = false;
1884 return timeInfo;
1887 timeInfo.playing = playing;
1888 timeInfo.frame = jpos.frame;
1889 timeInfo.usecs = jpos.usecs;
1891 if (jpos.valid & JackPositionBBT)
1893 timeInfo.bbt.valid = true;
1894 timeInfo.bbt.bar = jpos.bar;
1895 timeInfo.bbt.beat = jpos.beat;
1896 #ifdef JACK_TICK_DOUBLE
1897 if (jpos.valid & JackTickDouble)
1898 timeInfo.bbt.tick = jpos.tick_double;
1899 else
1900 #endif
1901 timeInfo.bbt.tick = jpos.tick;
1902 timeInfo.bbt.barStartTick = jpos.bar_start_tick;
1903 timeInfo.bbt.beatsPerBar = jpos.beats_per_bar;
1904 timeInfo.bbt.beatType = jpos.beat_type;
1905 timeInfo.bbt.ticksPerBeat = jpos.ticks_per_beat;
1906 timeInfo.bbt.beatsPerMinute = jpos.beats_per_minute;
1908 else
1910 timeInfo.bbt.valid = false;
1913 return timeInfo;
1916 #ifndef BUILD_BRIDGE
1917 void setOption(const EngineOption option, const int value, const char* const valueStr) noexcept override
1919 if (option == ENGINE_OPTION_TRANSPORT_MODE && fClient != nullptr)
1921 CARLA_SAFE_ASSERT_INT_RETURN(value >= ENGINE_TRANSPORT_MODE_DISABLED &&
1922 value <= ENGINE_TRANSPORT_MODE_JACK, value,);
1924 if (value == ENGINE_TRANSPORT_MODE_JACK)
1926 fTimebaseMaster = jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this);
1928 else
1930 // jack transport cannot be disabled in multi-client
1931 callback(true, true,
1932 ENGINE_CALLBACK_TRANSPORT_MODE_CHANGED, 0,
1933 ENGINE_TRANSPORT_MODE_JACK,
1934 0, 0, 0.0f,
1935 pData->options.transportExtra);
1936 CARLA_SAFE_ASSERT_RETURN(pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS,);
1938 jackbridge_release_timebase(fClient);
1939 fTimebaseMaster = false;
1942 else if (option == ENGINE_OPTION_CLIENT_NAME_PREFIX)
1944 fClientNamePrefix = valueStr;
1946 if (fClientNamePrefix.isNotEmpty())
1948 if (! fClientNamePrefix.contains('.'))
1949 fClientNamePrefix += ".0";
1950 if (! fClientNamePrefix.endsWith('/'))
1951 fClientNamePrefix += "/";
1955 CarlaEngine::setOption(option, value, valueStr);
1957 #endif
1959 CarlaEngineClient* addClient(CarlaPluginPtr plugin) override
1961 jack_client_t* client = nullptr;
1963 #ifndef BUILD_BRIDGE
1964 CARLA_CUSTOM_SAFE_ASSERT_RETURN("Not connected to JACK", fClient != nullptr, nullptr);
1966 CarlaPluginPtr* pluginReserve = nullptr;
1968 if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1970 client = fClient;
1972 else if (pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
1973 #endif
1975 #ifndef BUILD_BRIDGE
1976 if (fClientNamePrefix.isNotEmpty())
1978 client = jackbridge_client_open(fClientNamePrefix + plugin->getName(), JackNoStartServer, nullptr);
1980 else
1981 #endif
1983 client = jackbridge_client_open(plugin->getName(), JackNoStartServer, nullptr);
1985 CARLA_CUSTOM_SAFE_ASSERT_RETURN("Failure to open client", client != nullptr, nullptr);
1987 jackbridge_set_thread_init_callback(client, carla_jack_thread_init_callback, nullptr);
1989 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
1991 if (char* const uuidstr = jackbridge_client_get_uuid(client))
1993 jack_uuid_t uuid;
1995 if (jackbridge_uuid_parse(uuidstr, &uuid))
1997 char strBufId[24];
1998 std::snprintf(strBufId, 23, "%u", plugin->getId());
1999 strBufId[23] = '\0';
2001 #ifndef BUILD_BRIDGE
2002 jackbridge_set_property(client, uuid,
2003 URI_MAIN_CLIENT_NAME,
2004 fClientName,
2005 URI_TYPE_STRING);
2007 jackbridge_set_property(client, uuid,
2008 URI_PLUGIN_ID,
2009 strBufId,
2010 URI_TYPE_INTEGER);
2011 #endif
2013 if (const char* const pluginIcon = plugin->getIconName())
2014 jackbridge_set_property(client, uuid,
2015 URI_PLUGIN_ICON,
2016 pluginIcon,
2017 URI_TYPE_STRING);
2020 jackbridge_free(uuidstr);
2023 #ifndef BUILD_BRIDGE
2024 pluginReserve = new CarlaPluginPtr(plugin);
2026 jackbridge_set_buffer_size_callback(fClient, carla_jack_bufsize_callback_plugin, pluginReserve);
2027 jackbridge_set_sample_rate_callback(fClient, carla_jack_srate_callback_plugin, pluginReserve);
2029 // jackbridge_set_latency_callback(client, carla_jack_latency_callback_plugin, pluginReserve);
2030 jackbridge_set_process_callback(client, carla_jack_process_callback_plugin, pluginReserve);
2031 jackbridge_on_shutdown(client, carla_jack_shutdown_callback_plugin, pluginReserve);
2032 #else
2033 fClient = client;
2034 pData->bufferSize = jackbridge_get_buffer_size(client);
2035 pData->sampleRate = jackbridge_get_sample_rate(client);
2036 pData->initTime(nullptr);
2038 jackbridge_set_buffer_size_callback(client, carla_jack_bufsize_callback, this);
2039 jackbridge_set_sample_rate_callback(client, carla_jack_srate_callback, this);
2040 jackbridge_set_freewheel_callback(client, carla_jack_freewheel_callback, this);
2041 // jackbridge_set_latency_callback(client, carla_jack_latency_callback, this);
2042 jackbridge_set_process_callback(client, carla_jack_process_callback, this);
2043 jackbridge_on_shutdown(client, carla_jack_shutdown_callback, this);
2045 fClientName = jackbridge_get_client_name(client);
2046 #endif
2049 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2050 carla_debug("new CarlaEngineJackClient");
2051 CarlaEngineJackClient* const jclient = new CarlaEngineJackClient(*this,
2052 pData->graph,
2053 fThreadSafeMetadataMutex,
2054 plugin, fClientName, client);
2055 # ifndef BUILD_BRIDGE
2056 if (pluginReserve != nullptr)
2057 jclient->reservePluginPtr(pluginReserve);
2058 # endif
2059 return jclient;
2061 #else
2062 return new CarlaEngineJackClient(*this, fThreadSafeMetadataMutex, fClientName, client);
2063 #endif
2066 #ifndef BUILD_BRIDGE
2067 bool removePlugin(const uint id) override
2069 if (! CarlaEngine::removePlugin(id))
2070 return false;
2072 if (pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
2073 return true;
2075 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
2077 for (uint i=id; i < pData->curPluginCount; ++i)
2079 const CarlaPluginPtr plugin = pData->plugins[i].plugin;
2080 CARLA_SAFE_ASSERT_BREAK(plugin.get() != nullptr);
2082 CarlaEngineJackClient* const client = dynamic_cast<CarlaEngineJackClient*>(plugin->getEngineClient());
2083 CARLA_SAFE_ASSERT_BREAK(client != nullptr);
2085 client->setNewPluginId(i);
2088 return true;
2091 bool switchPlugins(const uint idA, const uint idB) noexcept override
2093 if (! CarlaEngine::switchPlugins(idA, idB))
2094 return false;
2096 if (pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
2097 return true;
2099 CarlaPluginPtr newPluginA = pData->plugins[idA].plugin;
2100 CARLA_SAFE_ASSERT_RETURN(newPluginA.get() != nullptr, true);
2102 CarlaPluginPtr newPluginB = pData->plugins[idB].plugin;
2103 CARLA_SAFE_ASSERT_RETURN(newPluginB.get() != nullptr, true);
2105 CarlaEngineJackClient* const clientA = dynamic_cast<CarlaEngineJackClient*>(newPluginA->getEngineClient());
2106 CARLA_SAFE_ASSERT_RETURN(clientA != nullptr, true);
2108 CarlaEngineJackClient* const clientB = dynamic_cast<CarlaEngineJackClient*>(newPluginB->getEngineClient());
2109 CARLA_SAFE_ASSERT_RETURN(clientB != nullptr, true);
2112 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
2113 clientA->setNewPluginId(idA);
2114 clientB->setNewPluginId(idB);
2117 return true;
2120 bool renamePlugin(const uint id, const char* const newName) override
2122 if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
2123 pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
2125 return CarlaEngine::renamePlugin(id, newName);
2128 CARLA_SAFE_ASSERT_RETURN(pData->plugins != nullptr, false);
2129 CARLA_SAFE_ASSERT_RETURN(pData->curPluginCount != 0, false);
2130 CARLA_SAFE_ASSERT_RETURN(id < pData->curPluginCount, false);
2131 CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0', false);
2133 CarlaPluginPtr plugin = pData->plugins[id].plugin;
2134 CARLA_SAFE_ASSERT_RETURN_ERR(plugin.get() != nullptr, "Could not find plugin to rename");
2135 CARLA_SAFE_ASSERT_RETURN_ERR(plugin->getId() == id, "Invalid engine internal data");
2137 // before we stop the engine thread we might need to get the plugin data
2138 const bool needsReinit = (pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS);
2139 const CarlaStateSave* saveStatePtr = nullptr;
2141 if (needsReinit)
2143 const CarlaStateSave& saveState(plugin->getStateSave());
2144 saveStatePtr = &saveState;
2147 CarlaString uniqueName;
2149 try {
2150 const char* const tmpName = getUniquePluginName(newName);
2151 uniqueName = tmpName;
2152 delete[] tmpName;
2153 } CARLA_SAFE_EXCEPTION("JACK renamePlugin getUniquePluginName");
2155 if (uniqueName.isEmpty())
2157 setLastError("Failed to request new unique plugin name");
2158 return false;
2161 const ScopedRunnerStopper srs(this);
2163 // rename on client client mode, just rename the ports
2164 if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
2166 CarlaEngineJackClient* const client((CarlaEngineJackClient*)plugin->getEngineClient());
2168 if (! client->renameInSingleClient(uniqueName))
2170 setLastError("Failed to rename some JACK ports, does your JACK version support proper port renaming?");
2171 return false;
2174 // rename in multiple client mode
2175 else if (pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
2177 CarlaEngineJackClient* const client((CarlaEngineJackClient*)plugin->getEngineClient());
2179 // we should not be able to do this, jack really needs to allow client rename
2180 if (jack_client_t* const jackClient = jackbridge_client_open(fClientNamePrefix + uniqueName,
2181 JackNoStartServer, nullptr))
2183 // get new client name
2184 fClientName = jackbridge_get_client_name(jackClient);
2186 if (fClientNamePrefix.isNotEmpty())
2187 uniqueName = fClientName.buffer() + fClientNamePrefix.length();
2188 else
2189 uniqueName = fClientName;
2191 // close client
2192 client->closeForRename(jackClient, fClientName);
2194 // disable plugin
2195 plugin->setEnabled(false);
2197 // set new client data
2198 CarlaPluginPtr* const pluginReserve = new CarlaPluginPtr(plugin);
2199 client->reservePluginPtr(pluginReserve);
2200 // jackbridge_set_latency_callback(jackClient, carla_jack_latency_callback_plugin, pluginReserve);
2201 jackbridge_set_process_callback(jackClient, carla_jack_process_callback_plugin, pluginReserve);
2202 jackbridge_on_shutdown(jackClient, carla_jack_shutdown_callback_plugin, pluginReserve);
2204 // NOTE: jack1 locks up here
2205 if (jackbridge_get_version_string() != nullptr)
2206 jackbridge_set_thread_init_callback(jackClient, carla_jack_thread_init_callback, nullptr);
2208 /* The following code is because of a tricky situation.
2209 We cannot lock or do jack operations during jack callbacks on jack1. jack2 events are asynchronous.
2210 When we close the client jack will trigger unregister-port callbacks, which we handle on a separate thread ASAP.
2211 But before that happens we already registered a new client with the same ports (the "renamed" one),
2212 and at this point the port we receive during that callback is actually the new one from the new client..
2213 JACK2 seems to be reusing ports to save space, which is understandable.
2214 Anyway, this means we have to remove all our port-related data before the new client ports are created.
2215 (we also stop the separate jack-events thread to avoid any race conditions while modying our port data) */
2217 if (fIsInternalClient)
2218 stopThread(-1);
2220 LinkedList<PortNameToId> ports;
2221 LinkedList<ConnectionToId> conns;
2224 const CarlaMutexLocker cml1(fUsedGroups.mutex);
2226 if (const uint groupId = fUsedGroups.getGroupId(plugin->getName()))
2228 const CarlaMutexLocker cml2(fUsedPorts.mutex);
2230 for (LinkedList<PortNameToId>::Itenerator it = fUsedPorts.list.begin2(); it.valid(); it.next())
2232 const PortNameToId& portNameToId(it.getValue(kPortNameToIdFallback));
2233 CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);
2235 if (portNameToId.group != groupId)
2236 continue;
2238 ports.append(portNameToId);
2239 fUsedPorts.list.remove(it);
2242 const CarlaMutexLocker cml3(fUsedConnections.mutex);
2244 for (LinkedList<ConnectionToId>::Itenerator it = fUsedConnections.list.begin2(); it.valid(); it.next())
2246 const ConnectionToId& connectionToId = it.getValue(kConnectionToIdFallback);
2247 CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
2249 if (connectionToId.groupA != groupId && connectionToId.groupB != groupId)
2250 continue;
2252 conns.append(connectionToId);
2253 fUsedConnections.list.remove(it);
2258 for (LinkedList<ConnectionToId>::Itenerator it = conns.begin2(); it.valid(); it.next())
2260 const ConnectionToId& connectionToId = it.getValue(kConnectionToIdFallback);
2261 CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
2263 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
2264 ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED,
2265 connectionToId.id,
2266 0, 0, 0, 0.0f, nullptr);
2269 for (LinkedList<PortNameToId>::Itenerator it = ports.begin2(); it.valid(); it.next())
2271 const PortNameToId& portNameToId(it.getValue(kPortNameToIdFallback));
2272 CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);
2274 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
2275 ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED,
2276 portNameToId.group,
2277 static_cast<int>(portNameToId.port),
2278 0, 0, 0.0f, nullptr);
2281 ports.clear();
2282 conns.clear();
2284 if (fIsInternalClient)
2285 startThread();
2287 else
2289 setLastError("Failed to create new JACK client");
2290 return false;
2294 // Rename
2295 plugin->setName(uniqueName);
2297 if (needsReinit)
2299 // reload plugin to recreate its ports
2300 plugin->reload();
2301 plugin->loadStateSave(*saveStatePtr);
2302 plugin->setEnabled(true);
2305 callback(true, true, ENGINE_CALLBACK_PLUGIN_RENAMED, id, 0, 0, 0, 0.0f, uniqueName);
2306 return true;
2309 // -------------------------------------------------------------------
2310 // Patchbay
2312 bool patchbayConnect(const bool external,
2313 const uint groupA, const uint portA, const uint groupB, const uint portB) override
2315 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
2317 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
2318 return CarlaEngine::patchbayConnect(false, groupA, portA, groupB, portB);
2320 const CarlaMutexLocker cml(fUsedPorts.mutex);
2322 const char* const fullPortNameA = fUsedPorts.getFullPortName(groupA, portA);
2323 CARLA_SAFE_ASSERT_RETURN(fullPortNameA != nullptr && fullPortNameA[0] != '\0', false);
2325 const char* const fullPortNameB = fUsedPorts.getFullPortName(groupB, portB);
2326 CARLA_SAFE_ASSERT_RETURN(fullPortNameB != nullptr && fullPortNameB[0] != '\0', false);
2328 if (! jackbridge_connect(fClient, fullPortNameA, fullPortNameB))
2330 setLastError("JACK operation failed");
2331 return false;
2334 return true;
2337 bool patchbayDisconnect(const bool external, const uint connectionId) override
2339 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
2341 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
2342 return CarlaEngine::patchbayDisconnect(false, connectionId);
2344 ConnectionToId connectionToId = { 0, 0, 0, 0, 0 };
2347 const CarlaMutexLocker cml(fUsedConnections.mutex);
2349 for (LinkedList<ConnectionToId>::Itenerator it = fUsedConnections.list.begin2(); it.valid(); it.next())
2351 connectionToId = it.getValue(kConnectionToIdFallback);
2352 CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
2354 if (connectionToId.id == connectionId)
2355 break;
2359 if (connectionToId.id == 0 || connectionToId.id != connectionId)
2361 setLastError("Failed to find the requested connection");
2362 return false;
2365 const CarlaMutexLocker cml(fUsedPorts.mutex);
2367 const char* const fullPortNameA = fUsedPorts.getFullPortName(connectionToId.groupA, connectionToId.portA);
2368 CARLA_SAFE_ASSERT_RETURN(fullPortNameA != nullptr && fullPortNameA[0] != '\0', false);
2370 const char* const fullPortNameB = fUsedPorts.getFullPortName(connectionToId.groupB, connectionToId.portB);
2371 CARLA_SAFE_ASSERT_RETURN(fullPortNameB != nullptr && fullPortNameB[0] != '\0', false);
2373 if (! jackbridge_disconnect(fClient, fullPortNameA, fullPortNameB))
2375 setLastError("JACK operation failed");
2376 return false;
2379 return true;
2382 bool patchbaySetGroupPos(const bool sendHost, const bool sendOSC, const bool external,
2383 const uint groupId, const int x1, const int y1, const int x2, const int y2) override
2385 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
2386 CARLA_SAFE_ASSERT_RETURN(! pData->loadingProject, false);
2387 carla_debug("CarlaEngineJack::patchbaySetGroupPos(%u, %i, %i, %i, %i)", groupId, x1, y1, x2, y2);
2389 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
2390 return CarlaEngine::patchbaySetGroupPos(sendHost, sendOSC, false, groupId, x1, y1, x2, y2);
2392 const char* groupName;
2395 const CarlaMutexLocker cml(fUsedGroups.mutex);
2397 groupName = fUsedGroups.getGroupName(groupId);
2398 CARLA_SAFE_ASSERT_RETURN(groupName != nullptr && groupName[0] != '\0', false);
2401 bool ok;
2404 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
2406 jack_uuid_t uuid;
2408 char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, groupName);
2409 CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0', false);
2411 const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
2412 jackbridge_free(uuidstr);
2414 /* if parsing fails, meta-data is not available..
2415 this could be because JACK version is old, or perhaps this is an internal client */
2416 if (! parsed)
2417 return false;
2420 fLastPatchbaySetGroupPos.set(x1, y1, x2, y2);
2422 char valueStr[STR_MAX];
2423 std::snprintf(valueStr, STR_MAX-1, "%i:%i:%i:%i", x1, y1, x2, y2);
2424 valueStr[STR_MAX-1] = '\0';
2426 ok = jackbridge_set_property(fClient, uuid, URI_POSITION, valueStr, URI_TYPE_STRING);
2429 callback(sendHost, sendOSC,
2430 ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
2431 groupId, x1, y1, x2, static_cast<float>(y2),
2432 nullptr);
2434 return ok;
2437 bool patchbayRefresh(const bool sendHost, const bool sendOSC, const bool external) override
2439 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
2440 carla_debug("patchbayRefresh(%s, %s, %s)", bool2str(sendHost), bool2str(sendOSC), bool2str(external));
2442 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
2444 if (sendHost)
2446 fExternalPatchbayHost = external;
2447 pData->graph.setUsingExternalHost(external);
2449 if (sendOSC)
2451 fExternalPatchbayOsc = external;
2452 pData->graph.setUsingExternalOSC(external);
2455 if (! external)
2456 CarlaEngine::patchbayRefresh(sendHost, sendOSC, false);
2459 initJackPatchbay(sendHost, sendOSC, jackbridge_get_client_name(fClient),
2460 pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && !external);
2461 return true;
2464 // -------------------------------------------------------------------
2465 // Transport
2467 void transportPlay() noexcept override
2469 if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK)
2470 return CarlaEngine::transportPlay();
2472 if (fClient != nullptr)
2474 if (! pData->timeInfo.bbt.valid)
2476 // old timebase master no longer active, make ourselves master again
2477 pData->time.setNeedsReset();
2478 fTimebaseMaster = jackbridge_set_timebase_callback(fClient, true, carla_jack_timebase_callback, this);
2481 try {
2482 jackbridge_transport_start(fClient);
2483 } catch(...) {}
2487 void transportPause() noexcept override
2489 if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK)
2490 return CarlaEngine::transportPause();
2492 if (fClient != nullptr)
2494 try {
2495 jackbridge_transport_stop(fClient);
2496 } catch(...) {}
2500 void transportBPM(const double bpm) noexcept override
2502 if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK || fTimebaseMaster)
2503 return CarlaEngine::transportBPM(bpm);
2505 if (fClient == nullptr)
2506 return;
2508 jack_position_t jpos;
2510 // invalidate
2511 jpos.unique_1 = 1;
2512 jpos.unique_2 = 2;
2513 jackbridge_transport_query(fClient, &jpos);
2515 if (jpos.unique_1 == jpos.unique_2 && (jpos.valid & JackPositionBBT) != 0)
2517 carla_stdout("NOTE: Changing BPM without being JACK timebase master");
2518 jpos.beats_per_minute = bpm;
2520 try {
2521 jackbridge_transport_reposition(fClient, &jpos);
2522 } catch(...) {}
2526 void transportRelocate(const uint64_t frame) noexcept override
2528 if (pData->options.transportMode != ENGINE_TRANSPORT_MODE_JACK)
2529 return CarlaEngine::transportRelocate(frame);
2531 if (fClient != nullptr)
2533 try {
2534 jackbridge_transport_locate(fClient, static_cast<jack_nframes_t>(frame));
2535 } catch(...) {}
2539 // -------------------------------------------------------------------
2540 // Patchbay stuff
2542 const char* const* getPatchbayConnections(const bool external) const override
2544 CARLA_CUSTOM_SAFE_ASSERT_RETURN("Not connected to JACK, will not save patchbay connections",
2545 fClient != nullptr, nullptr);
2546 carla_debug("CarlaEngineJack::getPatchbayConnections(%s)", bool2str(external));
2548 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
2549 return CarlaEngine::getPatchbayConnections(external);
2551 CarlaStringList connList;
2553 if (const char** const ports = jackbridge_get_ports(fClient, nullptr, nullptr, JackPortIsOutput))
2555 for (int i=0; ports[i] != nullptr; ++i)
2557 const jack_port_t* const jackPort(jackbridge_port_by_name(fClient, ports[i]));
2558 const char* const fullPortName(ports[i]);
2560 CARLA_SAFE_ASSERT_CONTINUE(jackPort != nullptr);
2562 if (const char** const connections = jackbridge_port_get_all_connections(fClient, jackPort))
2564 for (int j=0; connections[j] != nullptr; ++j)
2566 connList.append(fullPortName);
2567 connList.append(connections[j]);
2570 jackbridge_free(connections);
2574 jackbridge_free(ports);
2577 if (connList.count() == 0)
2578 return nullptr;
2580 fRetConns = connList.toCharStringListPtr();
2582 return fRetConns;
2585 const PatchbayPosition* getPatchbayPositions(const bool external, uint& count) const override
2587 CARLA_CUSTOM_SAFE_ASSERT_RETURN("Not connected to JACK, will not save patchbay positions",
2588 fClient != nullptr, nullptr);
2589 carla_debug("CarlaEngineJack::getPatchbayPositions(%s)", bool2str(external));
2591 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
2592 return CarlaEngine::getPatchbayPositions(external, count);
2594 const CarlaMutexLocker cml(fUsedGroups.mutex);
2595 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
2597 if (const std::size_t maxCount = fUsedGroups.list.count())
2599 PatchbayPosition* ret;
2601 try {
2602 ret = new CarlaEngine::PatchbayPosition[maxCount];
2603 } CARLA_SAFE_EXCEPTION_RETURN("new CarlaEngine::PatchbayPosition", nullptr);
2605 count = 0;
2607 GroupNameToId groupNameToId;
2609 for (LinkedList<GroupNameToId>::Itenerator it = fUsedGroups.list.begin2(); it.valid(); it.next())
2611 groupNameToId = it.getValue(kGroupNameToIdFallback);
2612 CARLA_SAFE_ASSERT_CONTINUE(groupNameToId.group != 0);
2614 jack_uuid_t uuid;
2616 char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, groupNameToId.name);
2618 if (uuidstr == nullptr || uuidstr[0] == '\0')
2619 continue;
2621 const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
2622 jackbridge_free(uuidstr);
2624 /* if parsing fails, meta-data is not available..
2625 this could be because JACK version is old, or perhaps this is an internal client */
2626 if (! parsed)
2627 continue;
2630 char* value = nullptr;
2631 char* type = nullptr;
2633 if (jackbridge_get_property(uuid, URI_POSITION, &value, &type)
2634 && value != nullptr
2635 && type != nullptr
2636 && std::strcmp(type, URI_TYPE_STRING) == 0)
2638 CarlaEngine::PatchbayPosition& ppos(ret[count++]);
2640 ppos.name = carla_strdup_safe(groupNameToId.name);
2641 ppos.dealloc = true;
2642 ppos.pluginId = -1;
2644 if (char* sep1 = std::strstr(value, ":"))
2646 *sep1++ = '\0';
2647 ppos.x1 = std::atoi(value);
2649 if (char* sep2 = std::strstr(sep1, ":"))
2651 *sep2++ = '\0';
2652 ppos.y1 = std::atoi(sep1);
2654 if (char* sep3 = std::strstr(sep2, ":"))
2656 *sep3++ = '\0';
2657 ppos.x2 = std::atoi(sep2);
2658 ppos.y2 = std::atoi(sep3);
2663 jackbridge_free(value);
2664 jackbridge_free(type);
2665 value = type = nullptr;
2667 const bool clientBelongsToUs = (jackbridge_get_property(uuid, URI_MAIN_CLIENT_NAME, &value, &type)
2668 && value != nullptr
2669 && type != nullptr
2670 && std::strcmp(type, URI_TYPE_STRING) == 0
2671 && fClientName == value);
2672 jackbridge_free(value);
2673 jackbridge_free(type);
2674 value = type = nullptr;
2676 if (! clientBelongsToUs)
2677 continue;
2679 if (jackbridge_get_property(uuid, URI_PLUGIN_ID, &value, &type)
2680 && value != nullptr
2681 && type != nullptr
2682 && std::strcmp(type, URI_TYPE_INTEGER) == 0)
2684 ppos.pluginId = std::atoi(value);
2687 jackbridge_free(value);
2688 jackbridge_free(type);
2692 return ret;
2695 return nullptr;
2698 void restorePatchbayConnection(const bool external,
2699 const char* const connSource, const char* const connTarget) override
2701 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr,);
2702 CARLA_SAFE_ASSERT_RETURN(connSource != nullptr && connSource[0] != '\0',);
2703 CARLA_SAFE_ASSERT_RETURN(connTarget != nullptr && connTarget[0] != '\0',);
2704 carla_debug("CarlaEngineJack::restorePatchbayConnection(%s, \"%s\", \"%s\")",
2705 bool2str(external), connSource, connTarget);
2707 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
2708 return CarlaEngine::restorePatchbayConnection(external, connSource, connTarget);
2710 if (const jack_port_t* const port = jackbridge_port_by_name(fClient, connSource))
2712 if (jackbridge_port_by_name(fClient, connTarget) == nullptr)
2713 return;
2715 if (! jackbridge_port_connected_to(port, connTarget))
2716 jackbridge_connect(fClient, connSource, connTarget);
2720 bool restorePatchbayGroupPosition(const bool external, PatchbayPosition& ppos) override
2722 CARLA_SAFE_ASSERT_RETURN(fClient != nullptr, false);
2723 carla_debug("CarlaEngineJack::restorePatchbayGroupPosition(%s, {%i, %i, %i, %i, %i, \"%s\"})",
2724 bool2str(external), ppos.pluginId, ppos.x1, ppos.y1, ppos.x2, ppos.y2, ppos.name);
2726 if (pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY && ! external)
2727 return CarlaEngine::restorePatchbayGroupPosition(external, ppos);
2729 uint groupId = 0;
2730 const char* const orig_name = ppos.name;
2732 /* NOTE: When loading a project, it might take a bit to receive plugins' jack client registration callbacks.
2733 * We try to wait a little for it, but not too much.
2735 if (ppos.pluginId >= 0)
2737 // strip client name prefix if already in place
2738 if (const char* const rname2 = std::strstr(ppos.name, "."))
2739 if (const char* const rname3 = std::strstr(rname2 + 1, "/"))
2740 ppos.name = rname3 + 1;
2742 if (pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
2744 if (fClientNamePrefix.isNotEmpty())
2746 char* nname = (char*)std::malloc(fClientNamePrefix.length() + std::strlen(ppos.name) + 1);
2747 std::strcpy(nname, fClientNamePrefix.buffer());
2748 std::strcat(nname, ppos.name);
2750 ppos.name = nname;
2751 ppos.dealloc = true;
2754 for (int i=20; --i >=0;)
2757 const CarlaMutexLocker cml(fUsedGroups.mutex);
2759 if (fUsedGroups.list.count() == 0)
2760 break;
2762 groupId = fUsedGroups.getGroupId(ppos.name);
2765 if (groupId != 0)
2766 break;
2768 carla_msleep(100);
2769 callback(true, true, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);
2773 else
2775 const CarlaMutexLocker cml(fUsedGroups.mutex);
2777 if (fUsedGroups.list.count() != 0)
2778 groupId = fUsedGroups.getGroupId(ppos.name);
2781 if (groupId == 0)
2783 if (ppos.pluginId < 0 || pData->options.processMode == ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
2784 carla_stdout("Previously saved client '%s' not found", ppos.name);
2786 else
2788 for (;;)
2790 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
2792 jack_uuid_t uuid;
2794 char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, ppos.name);
2795 CARLA_SAFE_ASSERT_BREAK(uuidstr != nullptr && uuidstr[0] != '\0');
2797 const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
2798 jackbridge_free(uuidstr);
2799 CARLA_CUSTOM_SAFE_ASSERT_ONCE_BREAK("JACK meta-data support unavailable", parsed);
2802 char valueStr[STR_MAX];
2803 std::snprintf(valueStr, STR_MAX-1, "%i:%i:%i:%i", ppos.x1, ppos.y1, ppos.x2, ppos.y2);
2804 valueStr[STR_MAX-1] = '\0';
2806 jackbridge_set_property(fClient, uuid, URI_POSITION, valueStr, URI_TYPE_STRING);
2807 break;
2810 callback(true, true,
2811 ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
2812 groupId, ppos.x1, ppos.y1, ppos.x2, static_cast<float>(ppos.y2),
2813 nullptr);
2816 return ppos.name != orig_name;
2818 #endif
2820 // -------------------------------------------------------------------
2822 protected:
2823 void handleJackBufferSizeCallback(const uint32_t newBufferSize)
2825 if (pData->bufferSize == newBufferSize)
2826 return;
2828 #ifndef BUILD_BRIDGE
2829 const CarlaMutexLocker cml(fPatchbayProcThreadProtectionMutex);
2830 #endif
2832 pData->bufferSize = newBufferSize;
2833 bufferSizeChanged(newBufferSize);
2836 void handleJackSampleRateCallback(const double newSampleRate)
2838 if (carla_isEqual(pData->sampleRate, newSampleRate))
2839 return;
2841 #ifndef BUILD_BRIDGE
2842 const CarlaMutexLocker cml(fPatchbayProcThreadProtectionMutex);
2843 #endif
2845 pData->sampleRate = newSampleRate;
2846 sampleRateChanged(newSampleRate);
2849 void handleJackFreewheelCallback(const bool isFreewheel)
2851 if (fFreewheel == isFreewheel)
2852 return;
2854 #ifndef BUILD_BRIDGE
2855 const CarlaMutexLocker cml(fPatchbayProcThreadProtectionMutex);
2856 #endif
2858 fFreewheel = isFreewheel;
2859 offlineModeChanged(isFreewheel);
2862 void handleJackProcessCallback(const uint32_t nframes)
2864 const PendingRtEventsRunner prt(this, nframes);
2866 CARLA_SAFE_ASSERT_INT2_RETURN(nframes == pData->bufferSize, nframes, pData->bufferSize,);
2868 #ifdef BUILD_BRIDGE
2869 CarlaPluginPtr plugin = pData->plugins[0].plugin;
2871 if (plugin.get() != nullptr && plugin->isEnabled() && plugin->tryLock(fFreewheel))
2873 plugin->initBuffers();
2874 processPlugin(plugin, nframes);
2875 plugin->unlock();
2877 #else
2878 if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_JACK && !fTimebaseMaster)
2880 jack_position_t jpos;
2882 // invalidate
2883 jpos.unique_1 = 1;
2884 jpos.unique_2 = 2;
2886 EngineTimeInfo timeInfo;
2887 const bool playing = jackbridge_transport_query(fClient, &jpos) == JackTransportRolling;
2889 if (jpos.unique_1 != jpos.unique_2)
2891 timeInfo.playing = false;
2892 timeInfo.frame = 0;
2893 timeInfo.usecs = 0;
2894 timeInfo.bbt.valid = false;
2896 else
2898 timeInfo.playing = playing;
2899 timeInfo.frame = jpos.frame;
2900 timeInfo.usecs = jpos.usecs;
2902 if (jpos.valid & JackPositionBBT)
2904 timeInfo.bbt.valid = true;
2905 timeInfo.bbt.bar = jpos.bar;
2906 timeInfo.bbt.beat = jpos.beat;
2907 #ifdef JACK_TICK_DOUBLE
2908 if (jpos.valid & JackTickDouble)
2909 timeInfo.bbt.tick = jpos.tick_double;
2910 else
2911 #endif
2912 timeInfo.bbt.tick = jpos.tick;
2913 timeInfo.bbt.barStartTick = jpos.bar_start_tick;
2914 timeInfo.bbt.beatsPerBar = jpos.beats_per_bar;
2915 timeInfo.bbt.beatType = jpos.beat_type;
2916 timeInfo.bbt.ticksPerBeat = jpos.ticks_per_beat;
2917 timeInfo.bbt.beatsPerMinute = jpos.beats_per_minute;
2919 else
2921 timeInfo.bbt.valid = false;
2925 pData->timeInfo = timeInfo;
2928 if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
2930 if (pData->aboutToClose)
2932 if (float* const audioOut1 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioOut1], nframes))
2933 carla_zeroFloats(audioOut1, nframes);
2935 if (float* const audioOut2 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioOut2], nframes))
2936 carla_zeroFloats(audioOut2, nframes);
2938 else if (pData->curPluginCount == 0)
2940 float* const audioIn1 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioIn1], nframes);
2941 float* const audioIn2 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioIn2], nframes);
2942 float* const audioOut1 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioOut1], nframes);
2943 float* const audioOut2 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioOut2], nframes);
2945 // assert buffers
2946 CARLA_SAFE_ASSERT_RETURN(audioIn1 != nullptr,);
2947 CARLA_SAFE_ASSERT_RETURN(audioIn2 != nullptr,);
2948 CARLA_SAFE_ASSERT_RETURN(audioOut1 != nullptr,);
2949 CARLA_SAFE_ASSERT_RETURN(audioOut2 != nullptr,);
2951 // pass-through
2952 carla_copyFloats(audioOut1, audioIn1, nframes);
2953 carla_copyFloats(audioOut2, audioIn2, nframes);
2955 // TODO pass-through MIDI as well
2956 if (void* const eventOut = jackbridge_port_get_buffer(fRackPorts[kRackPortEventOut], nframes))
2957 jackbridge_midi_clear_buffer(eventOut);
2959 return;
2963 if (pData->options.processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
2965 for (uint i=0; i < pData->curPluginCount; ++i)
2967 if (CarlaPluginPtr plugin = pData->plugins[i].plugin)
2969 if (plugin->isEnabled() && plugin->tryLock(fFreewheel))
2971 plugin->initBuffers();
2972 processPlugin(plugin, nframes);
2973 plugin->unlock();
2978 else if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK ||
2979 pData->options.processMode == ENGINE_PROCESS_MODE_PATCHBAY)
2981 CARLA_SAFE_ASSERT_RETURN(pData->events.in != nullptr,);
2982 CARLA_SAFE_ASSERT_RETURN(pData->events.out != nullptr,);
2984 // get buffers from jack
2985 float* const audioIn1 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioIn1], nframes);
2986 float* const audioIn2 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioIn2], nframes);
2987 float* const audioOut1 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioOut1], nframes);
2988 float* const audioOut2 = (float*)jackbridge_port_get_buffer(fRackPorts[kRackPortAudioOut2], nframes);
2989 void* const eventIn = jackbridge_port_get_buffer(fRackPorts[kRackPortEventIn], nframes);
2990 void* const eventOut = jackbridge_port_get_buffer(fRackPorts[kRackPortEventOut], nframes);
2992 // assert buffers
2993 CARLA_SAFE_ASSERT_RETURN(audioIn1 != nullptr,);
2994 CARLA_SAFE_ASSERT_RETURN(audioIn2 != nullptr,);
2995 CARLA_SAFE_ASSERT_RETURN(audioOut1 != nullptr,);
2996 CARLA_SAFE_ASSERT_RETURN(audioOut2 != nullptr,);
2998 // create audio buffers
2999 const float* inBuf[2] = { audioIn1, audioIn2 };
3000 /**/ float* outBuf[2] = { audioOut1, audioOut2 };
3002 // initialize events
3003 carla_zeroStructs(pData->events.in, kMaxEngineEventInternalCount);
3004 carla_zeroStructs(pData->events.out, kMaxEngineEventInternalCount);
3006 if (eventIn != nullptr)
3008 ushort engineEventIndex = 0;
3010 jack_midi_event_t jackEvent;
3011 const uint32_t jackEventCount(jackbridge_midi_get_event_count(eventIn));
3013 for (uint32_t jackEventIndex=0; jackEventIndex < jackEventCount; ++jackEventIndex)
3015 if (! jackbridge_midi_event_get(&jackEvent, eventIn, jackEventIndex))
3016 continue;
3018 CARLA_SAFE_ASSERT_CONTINUE(jackEvent.size < 0xFF /* uint8_t max */);
3020 EngineEvent& engineEvent(pData->events.in[engineEventIndex++]);
3022 engineEvent.time = jackEvent.time;
3023 engineEvent.fillFromMidiData(static_cast<uint8_t>(jackEvent.size), jackEvent.buffer, 0);
3025 if (engineEventIndex >= kMaxEngineEventInternalCount)
3026 break;
3030 if (pData->options.processMode == ENGINE_PROCESS_MODE_CONTINUOUS_RACK)
3032 pData->graph.processRack(pData, inBuf, outBuf, nframes);
3034 else
3036 const CarlaMutexLocker cml(fPatchbayProcThreadProtectionMutex);
3037 pData->graph.process(pData, inBuf, outBuf, nframes);
3040 // output control
3041 if (eventOut != nullptr)
3043 jackbridge_midi_clear_buffer(eventOut);
3045 uint8_t size = 0;
3046 uint8_t mdata[3] = { 0, 0, 0 };
3047 uint8_t mdataTmp[EngineMidiEvent::kDataSize];
3048 const uint8_t* mdataPtr;
3050 for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
3052 const EngineEvent& engineEvent(pData->events.out[i]);
3054 /**/ if (engineEvent.type == kEngineEventTypeNull)
3056 break;
3058 else if (engineEvent.type == kEngineEventTypeControl)
3060 const EngineControlEvent& ctrlEvent(engineEvent.ctrl);
3062 size = ctrlEvent.convertToMidiData(engineEvent.channel, mdata);
3063 mdataPtr = mdata;
3065 else if (engineEvent.type == kEngineEventTypeMidi)
3067 const EngineMidiEvent& midiEvent(engineEvent.midi);
3069 size = midiEvent.size;
3070 CARLA_SAFE_ASSERT_CONTINUE(size > 0);
3072 if (size > EngineMidiEvent::kDataSize)
3074 CARLA_SAFE_ASSERT_CONTINUE(midiEvent.dataExt != nullptr);
3075 mdataPtr = midiEvent.dataExt;
3077 else
3079 // set first byte
3080 mdataTmp[0] = static_cast<uint8_t>(midiEvent.data[0] | (engineEvent.channel & MIDI_CHANNEL_BIT));
3082 if (size > 1)
3084 // copy rest
3085 carla_copy<uint8_t>(mdataTmp+1, midiEvent.data+1, size-1U);
3088 // done
3089 mdataPtr = mdataTmp;
3092 else
3094 continue;
3097 if (size > 0)
3098 jackbridge_midi_event_write(eventOut, engineEvent.time, mdataPtr, size);
3103 if (pData->options.transportMode == ENGINE_TRANSPORT_MODE_JACK)
3105 if (fTimebaseMaster)
3107 const bool playing = jackbridge_transport_query(fClient, nullptr) == JackTransportRolling;
3109 if (fTimebaseRolling != playing)
3111 fTimebaseRolling = playing;
3112 pData->timeInfo.playing = playing;
3115 // Check if we are no longer timebase master
3116 if (playing && fTimebaseUsecs != 0 && fTimebaseUsecs == pData->timeInfo.usecs)
3118 carla_debug("No longer timerbase master");
3119 fTimebaseMaster = false;
3123 fTimebaseUsecs = pData->timeInfo.usecs;
3125 #endif // ! BUILD_BRIDGE
3128 void handleJackLatencyCallback(const jack_latency_callback_mode_t /*mode*/)
3130 // TODO
3133 #ifndef BUILD_BRIDGE
3134 void handleJackTimebaseCallback(jack_nframes_t nframes, jack_position_t* const pos, const int new_pos)
3136 if (new_pos)
3137 pData->time.setNeedsReset();
3139 pData->timeInfo.playing = fTimebaseRolling;
3140 pData->timeInfo.frame = pos->frame;
3141 pData->timeInfo.usecs = pos->usecs;
3142 pData->time.fillJackTimeInfo(pos, nframes);
3145 void handleJackClientUnregistrationCallback(const char* const name)
3147 CARLA_SAFE_ASSERT_RETURN(name != nullptr && name[0] != '\0',);
3149 uint groupId;
3152 const CarlaMutexLocker cml(fUsedGroups.mutex);
3153 groupId = fUsedGroups.getGroupId(name);
3155 // clients might have been registered without ports
3156 if (groupId == 0) return;
3158 GroupNameToId groupNameToId;
3159 groupNameToId.setData(groupId, name);
3161 fUsedGroups.list.removeOne(groupNameToId);
3164 // ignore callback if on internal patchbay mode
3165 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3166 if (! (fExternalPatchbayHost || (fExternalPatchbayOsc && pData->osc.isControlRegisteredForTCP()))) return;
3167 #else
3168 if (! fExternalPatchbayHost) return;
3169 #endif
3171 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3172 ENGINE_CALLBACK_PATCHBAY_CLIENT_REMOVED,
3173 groupId,
3174 0, 0, 0, 0.0f, nullptr);
3177 void handleJackClientPositionChangeCallback(const jack_uuid_t uuid)
3179 // ignore this if on internal patchbay mode
3180 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3181 if (! (fExternalPatchbayHost || (fExternalPatchbayOsc && pData->osc.isControlRegisteredForTCP()))) return;
3182 #else
3183 if (! fExternalPatchbayHost) return;
3184 #endif
3186 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
3188 char uuidstr[JACK_UUID_STRING_SIZE] = {};
3189 jackbridge_uuid_unparse(uuid, uuidstr);
3191 if (char* const clientName = jackbridge_get_client_name_by_uuid(fClient, uuidstr))
3193 CARLA_SAFE_ASSERT_RETURN(clientName != nullptr && clientName[0] != '\0',);
3195 uint groupId;
3198 const CarlaMutexLocker cml(fUsedGroups.mutex);
3199 groupId = fUsedGroups.getGroupId(clientName);
3202 jackbridge_free(clientName);
3203 CARLA_SAFE_ASSERT_RETURN(groupId != 0,);
3205 char* value = nullptr;
3206 char* type = nullptr;
3208 if (jackbridge_get_property(uuid, URI_POSITION, &value, &type)
3209 && value != nullptr
3210 && type != nullptr
3211 && std::strcmp(type, URI_TYPE_STRING) == 0)
3213 if (char* sep1 = std::strstr(value, ":"))
3215 LastPatchbaySetGroupPos pos;
3216 *sep1++ = '\0';
3217 pos.x1 = std::atoi(value);
3219 if (char* sep2 = std::strstr(sep1, ":"))
3221 *sep2++ = '\0';
3222 pos.y1 = std::atoi(sep1);
3224 if (char* sep3 = std::strstr(sep2, ":"))
3226 *sep3++ = '\0';
3227 pos.x2 = std::atoi(sep2);
3228 pos.y2 = std::atoi(sep3);
3231 if (fLastPatchbaySetGroupPos != pos)
3233 fLastPatchbaySetGroupPos.clear();
3235 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3236 ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
3237 groupId, pos.x1, pos.y1, pos.x2, static_cast<float>(pos.y2),
3238 nullptr);
3243 jackbridge_free(value);
3244 jackbridge_free(type);
3249 void handleJackPortRegistrationCallback(const char* const portName,
3250 const char* const shortPortName,
3251 const CarlaJackPortHints& jackPortHints)
3253 bool groupFound;
3254 CarlaString groupName(portName);
3255 groupName.truncate(groupName.rfind(shortPortName, &groupFound)-1);
3256 CARLA_SAFE_ASSERT_RETURN(groupFound,);
3258 groupFound = false;
3259 GroupToIdData groupData;
3260 PortToIdData portData;
3263 const CarlaMutexLocker cml1(fUsedGroups.mutex);
3265 groupData.id = fUsedGroups.getGroupId(groupName);
3267 if (groupData.id == 0)
3269 groupData.id = ++fUsedGroups.lastId;
3271 GroupNameToId groupNameToId;
3272 groupNameToId.setData(groupData.id, groupName);
3274 int pluginId = -1;
3275 PatchbayIcon icon = jackPortHints.isHardware ? PATCHBAY_ICON_HARDWARE : PATCHBAY_ICON_APPLICATION;
3277 findPluginIdAndIcon(groupName, pluginId, icon);
3279 fUsedGroups.list.append(groupNameToId);
3281 groupFound = true;
3282 groupData.icon = icon;
3283 groupData.pluginId = pluginId;
3284 std::strncpy(groupData.strVal, groupName, STR_MAX-1);
3285 groupData.strVal[STR_MAX-1] = '\0';
3289 // ignore the rest if on internal patchbay mode
3290 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3291 if (! (fExternalPatchbayHost || (fExternalPatchbayOsc && pData->osc.isControlRegisteredForTCP()))) return;
3292 #else
3293 if (! fExternalPatchbayHost) return;
3294 #endif
3297 uint canvasPortFlags = 0x0;
3298 canvasPortFlags |= jackPortHints.isInput ? PATCHBAY_PORT_IS_INPUT : 0x0;
3300 /**/ if (jackPortHints.isCV)
3301 canvasPortFlags |= PATCHBAY_PORT_TYPE_CV;
3302 else if (jackPortHints.isOSC)
3303 canvasPortFlags |= PATCHBAY_PORT_TYPE_OSC;
3304 else if (jackPortHints.isAudio)
3305 canvasPortFlags |= PATCHBAY_PORT_TYPE_AUDIO;
3306 else if (jackPortHints.isMIDI)
3307 canvasPortFlags |= PATCHBAY_PORT_TYPE_MIDI;
3309 const CarlaMutexLocker cml2(fUsedPorts.mutex);
3311 portData.group = groupData.id;
3312 portData.port = ++fUsedPorts.lastId;
3313 portData.flags = canvasPortFlags;
3314 std::strncpy(portData.strVal, shortPortName, STR_MAX-1);
3315 portData.strVal[STR_MAX-1] = '\0';
3317 PortNameToId portNameToId;
3318 portNameToId.setData(portData.group, portData.port, shortPortName, portName);
3319 fUsedPorts.list.append(portNameToId);
3322 if (groupFound)
3324 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3325 ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED,
3326 groupData.id,
3327 groupData.icon,
3328 groupData.pluginId,
3329 0, 0.0f,
3330 groupData.strVal);
3333 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3334 ENGINE_CALLBACK_PATCHBAY_PORT_ADDED,
3335 portData.group,
3336 static_cast<int>(portData.port),
3337 static_cast<int>(portData.flags),
3338 0, 0.0f,
3339 portData.strVal);
3342 void handleJackPortUnregistrationCallback(const char* const portName)
3344 // ignore this if on internal patchbay mode
3345 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3346 if (! (fExternalPatchbayHost || (fExternalPatchbayOsc && pData->osc.isControlRegisteredForTCP()))) return;
3347 #else
3348 if (! fExternalPatchbayHost) return;
3349 #endif
3351 uint groupId, portId;
3354 const CarlaMutexLocker cml(fUsedPorts.mutex);
3356 const PortNameToId& portNameToId(fUsedPorts.getPortNameToId(portName));
3358 /* NOTE: Due to JACK2 async behaviour the port we get here might be the same of a previous rename-plugin request.
3359 See the comment on CarlaEngineJack::renamePlugin() for more information. */
3360 if (portNameToId.group <= 0 || portNameToId.port <= 0) return;
3362 groupId = portNameToId.group;
3363 portId = portNameToId.port;
3365 fUsedPorts.list.removeOne(portNameToId);
3368 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3369 ENGINE_CALLBACK_PATCHBAY_PORT_REMOVED,
3370 groupId,
3371 static_cast<int>(portId),
3372 0, 0, 0.0f, nullptr);
3375 void handleJackPortConnectCallback(const char* const portNameA, const char* const portNameB)
3377 // ignore this if on internal patchbay mode
3378 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3379 if (! (fExternalPatchbayHost || (fExternalPatchbayOsc && pData->osc.isControlRegisteredForTCP()))) return;
3380 #else
3381 if (! fExternalPatchbayHost) return;
3382 #endif
3384 char strBuf[STR_MAX];
3385 uint connectionId;
3388 const CarlaMutexLocker cml1(fUsedPorts.mutex);
3390 const PortNameToId& portNameToIdA(fUsedPorts.getPortNameToId(portNameA));
3391 const PortNameToId& portNameToIdB(fUsedPorts.getPortNameToId(portNameB));
3393 /* NOTE: Due to JACK2 async behaviour the port we get here might be the same of a previous rename-plugin request.
3394 See the comment on CarlaEngineJack::renamePlugin() for more information. */
3395 if (portNameToIdA.group <= 0 || portNameToIdA.port <= 0) return;
3396 if (portNameToIdB.group <= 0 || portNameToIdB.port <= 0) return;
3398 const CarlaMutexLocker cml2(fUsedConnections.mutex);
3400 std::snprintf(strBuf, STR_MAX-1, "%i:%i:%i:%i",
3401 portNameToIdA.group, portNameToIdA.port,
3402 portNameToIdB.group, portNameToIdB.port);
3403 strBuf[STR_MAX-1] = '\0';
3405 connectionId = ++fUsedConnections.lastId;
3407 ConnectionToId connectionToId;
3408 connectionToId.setData(connectionId,
3409 portNameToIdA.group, portNameToIdA.port,
3410 portNameToIdB.group, portNameToIdB.port);
3412 fUsedConnections.list.append(connectionToId);
3415 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3416 ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED,
3417 connectionId,
3418 0, 0, 0, 0.0f,
3419 strBuf);
3422 void handleJackPortDisconnectCallback(const char* const portNameA, const char* const portNameB)
3424 // ignore this if on internal patchbay mode
3425 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3426 if (! (fExternalPatchbayHost || (fExternalPatchbayOsc && pData->osc.isControlRegisteredForTCP()))) return;
3427 #else
3428 if (! fExternalPatchbayHost) return;
3429 #endif
3431 uint connectionId = 0;
3434 const CarlaMutexLocker cml1(fUsedPorts.mutex);
3436 const PortNameToId& portNameToIdA(fUsedPorts.getPortNameToId(portNameA));
3437 const PortNameToId& portNameToIdB(fUsedPorts.getPortNameToId(portNameB));
3439 /* NOTE: Due to JACK2 async behaviour the port we get here might be the same of a previous rename-plugin request.
3440 See the comment on CarlaEngineJack::renamePlugin() for more information. */
3441 if (portNameToIdA.group <= 0 || portNameToIdA.port <= 0) return;
3442 if (portNameToIdB.group <= 0 || portNameToIdB.port <= 0) return;
3444 const CarlaMutexLocker cml2(fUsedConnections.mutex);
3446 for (LinkedList<ConnectionToId>::Itenerator it = fUsedConnections.list.begin2(); it.valid(); it.next())
3448 const ConnectionToId& connectionToId = it.getValue(kConnectionToIdFallback);
3449 CARLA_SAFE_ASSERT_CONTINUE(connectionToId.id != 0);
3451 if (connectionToId.groupA == portNameToIdA.group && connectionToId.portA == portNameToIdA.port &&
3452 connectionToId.groupB == portNameToIdB.group && connectionToId.portB == portNameToIdB.port)
3454 connectionId = connectionToId.id;
3455 fUsedConnections.list.remove(it);
3456 break;
3461 if (connectionId != 0) {
3462 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3463 ENGINE_CALLBACK_PATCHBAY_CONNECTION_REMOVED,
3464 connectionId,
3465 0, 0, 0, 0.0f, nullptr);
3469 void handleJackPortRenameCallback(const char* const oldFullName,
3470 const char* const newFullName,
3471 const char* const newShortName)
3473 // ignore this if on internal patchbay mode
3474 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3475 if (! (fExternalPatchbayHost || (fExternalPatchbayOsc && pData->osc.isControlRegisteredForTCP()))) return;
3476 #else
3477 if (! fExternalPatchbayHost) return;
3478 #endif
3480 CARLA_SAFE_ASSERT_RETURN(oldFullName != nullptr && oldFullName[0] != '\0',);
3481 CARLA_SAFE_ASSERT_RETURN(newFullName != nullptr && newFullName[0] != '\0',);
3483 bool found;
3484 CarlaString groupName(newFullName);
3485 groupName.truncate(groupName.rfind(newShortName, &found)-1);
3486 CARLA_SAFE_ASSERT_RETURN(found,);
3488 uint groupId, portId = 0;
3489 char portName[STR_MAX];
3490 found = false;
3493 const CarlaMutexLocker cml1(fUsedGroups.mutex);
3495 groupId = fUsedGroups.getGroupId(groupName);
3496 CARLA_SAFE_ASSERT_RETURN(groupId != 0,);
3498 const CarlaMutexLocker cml2(fUsedPorts.mutex);
3500 for (LinkedList<PortNameToId>::Itenerator it = fUsedPorts.list.begin2(); it.valid(); it.next())
3502 PortNameToId& portNameToId(it.getValue(kPortNameToIdFallbackNC));
3503 CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group != 0);
3505 if (std::strncmp(portNameToId.fullName, oldFullName, STR_MAX) == 0)
3507 CARLA_SAFE_ASSERT_CONTINUE(portNameToId.group == groupId);
3509 found = true;
3510 portId = portNameToId.port;
3511 std::strncpy(portName, newShortName, STR_MAX-1);
3512 portName[STR_MAX-1] = '\0';
3514 portNameToId.rename(newShortName, newFullName);
3515 break;
3520 if (found)
3522 callback(fExternalPatchbayHost, fExternalPatchbayOsc,
3523 ENGINE_CALLBACK_PATCHBAY_PORT_CHANGED,
3524 groupId,
3525 static_cast<int>(portId),
3526 0, 0, 0.0f,
3527 portName);
3530 #endif
3532 void handleJackShutdownCallback()
3534 #ifndef BUILD_BRIDGE
3535 if (fIsInternalClient)
3536 stopThread(-1);
3537 #endif
3540 const PendingRtEventsRunner prt(this, pData->bufferSize);
3542 for (uint i=0; i < pData->curPluginCount; ++i)
3544 if (const CarlaPluginPtr plugin = pData->plugins[i].plugin)
3546 plugin->tryLock(true);
3548 if (CarlaEngineJackClient* const client = (CarlaEngineJackClient*)plugin->getEngineClient())
3549 client->invalidate();
3551 plugin->unlock();
3556 pData->runner.stopRunner();
3557 fClient = nullptr;
3559 #ifdef BUILD_BRIDGE
3560 fIsRunning = false;
3561 #else
3562 carla_zeroPointers(fRackPorts, kRackPortCount);
3563 #endif
3565 callback(true, true, ENGINE_CALLBACK_ERROR, 0, 0, 0, 0, 0.0f,
3566 "Carla has been killed by JACK, or JACK has stopped.\n"
3567 "You can still save if you want, but you will lose patchbay connections and positions.");
3570 // -------------------------------------------------------------------
3572 void handlePluginJackShutdownCallback(const CarlaPluginPtr plugin)
3574 CarlaEngineJackClient* const engineClient((CarlaEngineJackClient*)plugin->getEngineClient());
3575 CARLA_SAFE_ASSERT_RETURN(engineClient != nullptr,);
3577 plugin->tryLock(true);
3578 engineClient->invalidate();
3579 plugin->unlock();
3581 callback(true, true, ENGINE_CALLBACK_PLUGIN_UNAVAILABLE, plugin->getId(), 0, 0, 0, 0.0f, "Killed by JACK");
3584 // -------------------------------------------------------------------
3586 private:
3587 jack_client_t* fClient;
3588 bool fExternalPatchbayHost;
3589 bool fExternalPatchbayOsc;
3590 bool fFreewheel;
3592 CarlaString fClientName;
3593 CarlaRecursiveMutex fThreadSafeMetadataMutex;
3595 // -------------------------------------------------------------------
3597 #ifdef BUILD_BRIDGE
3598 bool fIsRunning;
3599 #else
3600 CarlaString fClientNamePrefix;
3602 enum RackPorts {
3603 kRackPortAudioIn1 = 0,
3604 kRackPortAudioIn2 = 1,
3605 kRackPortAudioOut1 = 2,
3606 kRackPortAudioOut2 = 3,
3607 kRackPortEventIn = 4,
3608 kRackPortEventOut = 5,
3609 kRackPortCount = 6
3612 jack_port_t* fRackPorts[kRackPortCount];
3614 bool fTimebaseMaster;
3615 bool fTimebaseRolling;
3616 uint64_t fTimebaseUsecs;
3618 PatchbayGroupList fUsedGroups;
3619 PatchbayPortList fUsedPorts;
3620 PatchbayConnectionList fUsedConnections;
3621 CarlaMutex fPatchbayProcThreadProtectionMutex;
3623 mutable CharStringListPtr fRetConns;
3625 void findPluginIdAndIcon(const char* const clientName, int& pluginId, PatchbayIcon& icon) const noexcept
3627 carla_debug("CarlaEngineJack::findPluginIdAndIcon(\"%s\", ...)", clientName);
3629 // TODO - this currently only works in multi-client mode
3630 if (pData->options.processMode != ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS)
3631 return;
3633 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
3635 jack_uuid_t uuid;
3637 char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, clientName);
3638 CARLA_SAFE_ASSERT_RETURN(uuidstr != nullptr && uuidstr[0] != '\0',);
3640 const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
3641 jackbridge_free(uuidstr);
3643 /* if parsing fails, meta-data is not available..
3644 this could be because JACK version is old, or perhaps this is an internal client */
3645 if (! parsed)
3646 return;
3649 bool clientBelongsToUs;
3652 char* value = nullptr;
3653 char* type = nullptr;
3655 if (! jackbridge_get_property(uuid, URI_MAIN_CLIENT_NAME, &value, &type))
3656 return;
3658 CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
3659 CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',);
3660 CARLA_SAFE_ASSERT_RETURN(std::strcmp(type, URI_TYPE_STRING) == 0,);
3662 clientBelongsToUs = fClientName == value;
3664 jackbridge_free(value);
3665 jackbridge_free(type);
3669 char* value = nullptr;
3670 char* type = nullptr;
3672 if (! jackbridge_get_property(uuid, URI_PLUGIN_ID, &value, &type))
3673 return;
3675 CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
3676 CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',);
3677 CARLA_SAFE_ASSERT_RETURN(std::strcmp(type, URI_TYPE_INTEGER) == 0,);
3679 if (clientBelongsToUs)
3680 pluginId = std::atoi(value);
3682 icon = PATCHBAY_ICON_PLUGIN;
3684 jackbridge_free(value);
3685 jackbridge_free(type);
3689 char* value = nullptr;
3690 char* type = nullptr;
3692 if (! jackbridge_get_property(uuid, URI_PLUGIN_ICON, &value, &type))
3693 return;
3695 CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
3696 CARLA_SAFE_ASSERT_RETURN(value != nullptr && value[0] != '\0',);
3697 CARLA_SAFE_ASSERT_RETURN(std::strcmp(type, URI_TYPE_STRING) == 0,);
3699 /**/ if (std::strcmp(value, "app") == 0)
3700 icon = PATCHBAY_ICON_APPLICATION;
3701 else if (std::strcmp(value, "application") == 0)
3702 icon = PATCHBAY_ICON_APPLICATION;
3703 else if (std::strcmp(value, "plugin") == 0)
3704 icon = PATCHBAY_ICON_PLUGIN;
3705 else if (std::strcmp(value, "hardware") == 0)
3706 icon = PATCHBAY_ICON_HARDWARE;
3707 else if (std::strcmp(value, "carla") == 0)
3708 icon = PATCHBAY_ICON_CARLA;
3709 else if (std::strcmp(value, "distrho") == 0)
3710 icon = PATCHBAY_ICON_DISTRHO;
3711 else if (std::strcmp(value, "file") == 0)
3712 icon = PATCHBAY_ICON_FILE;
3714 jackbridge_free(value);
3715 jackbridge_free(type);
3719 // prevent recursion on patchbay group position changes
3720 struct LastPatchbaySetGroupPos {
3721 int x1, y1, x2, y2;
3723 LastPatchbaySetGroupPos()
3724 : x1(0), y1(0), x2(0), y2(0) {}
3726 void clear() noexcept
3728 x1 = y1 = x2 = y2 = 0;
3731 void set(const int _x1, const int _y1, const int _x2, const int _y2) noexcept
3733 x1 = _x1;
3734 y1 = _y1;
3735 x2 = _x2;
3736 y2 = _y2;
3739 bool operator!=(const LastPatchbaySetGroupPos& pos) const noexcept
3741 return pos.x1 != x1 || pos.y1 != y1 || pos.x2 != x2 || pos.y2 != y2;
3743 } fLastPatchbaySetGroupPos;
3745 // handy stuff only needed for initJackPatchbay
3746 struct GroupToIdData {
3747 uint id;
3748 PatchbayIcon icon;
3749 int pluginId;
3750 char strVal[STR_MAX];
3752 struct PortToIdData {
3753 uint group;
3754 uint port;
3755 uint flags;
3756 char strVal[STR_MAX];
3758 struct ConnectionToIdData {
3759 uint id;
3760 char strVal[STR_MAX];
3763 void initJackPatchbay(const bool sendHost, const bool sendOSC, const char* const ourName, const bool groupsOnly)
3765 CARLA_SAFE_ASSERT_RETURN(ourName != nullptr && ourName[0] != '\0',);
3767 fLastPatchbaySetGroupPos.clear();
3769 uint id, carlaId;
3770 CarlaStringList parsedGroups;
3771 LinkedList<GroupToIdData> groupCallbackData;
3772 LinkedList<PortToIdData> portsCallbackData;
3773 LinkedList<ConnectionToIdData> connCallbackData;
3776 const CarlaMutexLocker cml1(fUsedGroups.mutex);
3777 const CarlaMutexLocker cml2(fUsedPorts.mutex);
3778 const CarlaMutexLocker cml3(fUsedConnections.mutex);
3779 const CarlaMutexLocker cml4(fPostPonedEventsMutex);
3781 fUsedGroups.clear();
3782 fUsedPorts.clear();
3783 fUsedConnections.clear();
3784 fPostPonedEvents.clear();
3786 // add our client first
3788 carlaId = ++fUsedGroups.lastId;
3789 parsedGroups.append(ourName);
3791 GroupNameToId groupNameToId;
3792 groupNameToId.setData(carlaId, ourName);
3793 fUsedGroups.list.append(groupNameToId);
3796 // query all jack ports
3798 const char** const ports = jackbridge_get_ports(fClient, nullptr, nullptr, 0);
3799 CARLA_SAFE_ASSERT_RETURN(ports != nullptr,);
3801 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
3803 for (int i=0; ports[i] != nullptr; ++i)
3805 const char* const fullPortName(ports[i]);
3806 CARLA_SAFE_ASSERT_CONTINUE(fullPortName != nullptr && fullPortName[0] != '\0');
3808 const jack_port_t* const jackPort(jackbridge_port_by_name(fClient, fullPortName));
3809 CARLA_SAFE_ASSERT_CONTINUE(jackPort != nullptr);
3811 const char* const shortPortName(jackbridge_port_short_name(jackPort));
3812 CARLA_SAFE_ASSERT_CONTINUE(shortPortName != nullptr && shortPortName[0] != '\0');
3814 const CarlaJackPortHints jackPortHints(CarlaJackPortHints::fromPort(jackPort));
3816 uint groupId = 0;
3818 bool found;
3819 CarlaString groupName(fullPortName);
3820 groupName.truncate(groupName.rfind(shortPortName, &found)-1);
3822 CARLA_SAFE_ASSERT_CONTINUE(found);
3824 if (parsedGroups.contains(groupName))
3826 groupId = fUsedGroups.getGroupId(groupName);
3827 CARLA_SAFE_ASSERT_CONTINUE(groupId > 0);
3829 else
3831 groupId = ++fUsedGroups.lastId;
3832 parsedGroups.append(groupName);
3834 GroupNameToId groupNameToId;
3835 groupNameToId.setData(groupId, groupName);
3837 int pluginId = -1;
3838 PatchbayIcon icon = jackPortHints.isHardware ? PATCHBAY_ICON_HARDWARE : PATCHBAY_ICON_APPLICATION;
3840 findPluginIdAndIcon(groupName, pluginId, icon);
3842 fUsedGroups.list.append(groupNameToId);
3844 if (! groupsOnly)
3846 GroupToIdData groupData;
3847 groupData.id = groupId;
3848 groupData.icon = icon;
3849 groupData.pluginId = pluginId;
3850 std::strncpy(groupData.strVal, groupName, STR_MAX-1);
3851 groupData.strVal[STR_MAX-1] = '\0';
3852 groupCallbackData.append(groupData);
3856 if (groupsOnly)
3857 continue;
3859 uint canvasPortFlags = 0x0;
3860 canvasPortFlags |= jackPortHints.isInput ? PATCHBAY_PORT_IS_INPUT : 0x0;
3862 /**/ if (jackPortHints.isCV)
3863 canvasPortFlags |= PATCHBAY_PORT_TYPE_CV;
3864 else if (jackPortHints.isOSC)
3865 canvasPortFlags |= PATCHBAY_PORT_TYPE_OSC;
3866 else if (jackPortHints.isAudio)
3867 canvasPortFlags |= PATCHBAY_PORT_TYPE_AUDIO;
3868 else if (jackPortHints.isMIDI)
3869 canvasPortFlags |= PATCHBAY_PORT_TYPE_MIDI;
3871 id = ++fUsedPorts.lastId;
3873 PortNameToId portNameToId;
3874 portNameToId.setData(groupId, id, shortPortName, fullPortName);
3875 fUsedPorts.list.append(portNameToId);
3877 PortToIdData portData;
3878 portData.group = groupId;
3879 portData.port = id;
3880 portData.flags = canvasPortFlags;
3881 std::strncpy(portData.strVal, shortPortName, STR_MAX-1);
3882 portData.strVal[STR_MAX-1] = '\0';
3883 portsCallbackData.append(portData);
3886 jackbridge_free(ports);
3889 if (groupsOnly)
3890 return;
3892 // query connections, after all ports are in place
3893 if (const char** const ports = jackbridge_get_ports(fClient, nullptr, nullptr, JackPortIsOutput))
3895 for (int i=0; ports[i] != nullptr; ++i)
3897 const char* const fullPortName(ports[i]);
3898 CARLA_SAFE_ASSERT_CONTINUE(fullPortName != nullptr && fullPortName[0] != '\0');
3900 const jack_port_t* const jackPort(jackbridge_port_by_name(fClient, fullPortName));
3901 CARLA_SAFE_ASSERT_CONTINUE(jackPort != nullptr);
3903 const PortNameToId& thisPort(fUsedPorts.getPortNameToId(fullPortName));
3905 CARLA_SAFE_ASSERT_CONTINUE(thisPort.group > 0);
3906 CARLA_SAFE_ASSERT_CONTINUE(thisPort.port > 0);
3908 if (const char** const connections = jackbridge_port_get_all_connections(fClient, jackPort))
3910 for (int j=0; connections[j] != nullptr; ++j)
3912 const char* const connection(connections[j]);
3913 CARLA_SAFE_ASSERT_CONTINUE(connection != nullptr && connection[0] != '\0');
3915 const PortNameToId& targetPort(fUsedPorts.getPortNameToId(connection));
3917 CARLA_SAFE_ASSERT_CONTINUE(targetPort.group > 0);
3918 CARLA_SAFE_ASSERT_CONTINUE(targetPort.port > 0);
3920 id = ++fUsedConnections.lastId;
3922 ConnectionToId connectionToId;
3923 connectionToId.setData(id, thisPort.group, thisPort.port, targetPort.group, targetPort.port);
3924 fUsedConnections.list.append(connectionToId);
3926 ConnectionToIdData connData;
3927 connData.id = id;
3928 std::snprintf(connData.strVal, STR_MAX-1, "%i:%i:%i:%i",
3929 thisPort.group, thisPort.port, targetPort.group, targetPort.port);
3930 connData.strVal[STR_MAX-1] = '\0';
3931 connCallbackData.append(connData);
3934 jackbridge_free(connections);
3938 jackbridge_free(ports);
3942 const GroupToIdData groupFallback = { 0, PATCHBAY_ICON_PLUGIN, -1, { '\0' } };
3943 const PortToIdData portFallback = { 0, 0, 0, { '\0' } };
3944 const ConnectionToIdData connFallback = { 0, { '\0' } };
3946 callback(sendHost, sendOSC,
3947 ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED,
3948 carlaId,
3949 PATCHBAY_ICON_CARLA,
3950 MAIN_CARLA_PLUGIN_ID,
3951 0, 0.0f,
3952 ourName);
3955 const CarlaRecursiveMutexLocker crml(fThreadSafeMetadataMutex);
3957 for (LinkedList<GroupToIdData>::Itenerator it = groupCallbackData.begin2(); it.valid(); it.next())
3959 const GroupToIdData& group(it.getValue(groupFallback));
3961 callback(sendHost, sendOSC,
3962 ENGINE_CALLBACK_PATCHBAY_CLIENT_ADDED,
3963 group.id,
3964 group.icon,
3965 group.pluginId,
3966 0, 0.0f,
3967 group.strVal);
3969 jack_uuid_t uuid;
3971 char* const uuidstr = jackbridge_get_uuid_for_client_name(fClient, group.strVal);
3972 CARLA_SAFE_ASSERT_CONTINUE(uuidstr != nullptr && uuidstr[0] != '\0');
3974 const bool parsed = jackbridge_uuid_parse(uuidstr, &uuid);
3975 jackbridge_free(uuidstr);
3977 /* if parsing fails, meta-data is not available..
3978 this could be because JACK version is old, or perhaps this is an internal client */
3979 if (! parsed)
3980 continue;
3983 char* value = nullptr;
3984 char* type = nullptr;
3986 if (jackbridge_get_property(uuid, URI_POSITION, &value, &type)
3987 && value != nullptr
3988 && type != nullptr
3989 && std::strcmp(type, URI_TYPE_STRING) == 0)
3991 if (char* sep1 = std::strstr(value, ":"))
3993 int x1, y1 = 0, x2 = 0, y2 = 0;
3994 *sep1++ = '\0';
3995 x1 = std::atoi(value);
3997 if (char* sep2 = std::strstr(sep1, ":"))
3999 *sep2++ = '\0';
4000 y1 = std::atoi(sep1);
4002 if (char* sep3 = std::strstr(sep2, ":"))
4004 *sep3++ = '\0';
4005 x2 = std::atoi(sep2);
4006 y2 = std::atoi(sep3);
4010 jackbridge_free(value);
4011 jackbridge_free(type);
4013 callback(sendHost, sendOSC,
4014 ENGINE_CALLBACK_PATCHBAY_CLIENT_POSITION_CHANGED,
4015 group.id, x1, y1, x2, static_cast<float>(y2),
4016 nullptr);
4022 for (LinkedList<PortToIdData>::Itenerator it = portsCallbackData.begin2(); it.valid(); it.next())
4024 const PortToIdData& port(it.getValue(portFallback));
4026 callback(sendHost, sendOSC,
4027 ENGINE_CALLBACK_PATCHBAY_PORT_ADDED,
4028 port.group,
4029 static_cast<int>(port.port),
4030 static_cast<int>(port.flags),
4031 0, 0.0f,
4032 port.strVal);
4035 for (LinkedList<ConnectionToIdData>::Itenerator it = connCallbackData.begin2(); it.valid(); it.next())
4037 const ConnectionToIdData& conn(it.getValue(connFallback));
4039 callback(sendHost, sendOSC,
4040 ENGINE_CALLBACK_PATCHBAY_CONNECTION_ADDED,
4041 conn.id,
4042 0, 0, 0, 0.0f,
4043 conn.strVal);
4046 groupCallbackData.clear();
4047 portsCallbackData.clear();
4048 connCallbackData.clear();
4050 #endif
4052 // -------------------------------------------------------------------
4054 void processPlugin(CarlaPluginPtr& plugin, const uint32_t nframes)
4056 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
4057 CarlaEngineJackClient* const client = (CarlaEngineJackClient*)plugin->getEngineClient();
4058 CarlaEngineJackCVSourcePorts& cvSourcePorts(client->getCVSourcePorts());
4060 const CarlaRecursiveMutexTryLocker crmtl(cvSourcePorts.getMutex(), fFreewheel);
4061 // const CarlaRecursiveMutexLocker crml(cvSourcePorts.getMutex());
4062 #endif
4065 const uint32_t audioInCount = client->getPortCount(kEnginePortTypeAudio, true);
4066 const uint32_t audioOutCount = client->getPortCount(kEnginePortTypeAudio, false);
4067 const uint32_t cvInCount = client->getPortCount(kEnginePortTypeCV, true);
4068 const uint32_t cvOutCount = client->getPortCount(kEnginePortTypeCV, false);
4071 const uint32_t audioInCount = plugin->getAudioInCount();
4072 const uint32_t audioOutCount = plugin->getAudioOutCount();
4073 const uint32_t cvInCount = plugin->getCVInCount();
4074 const uint32_t cvOutCount = plugin->getCVOutCount();
4075 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
4076 const uint32_t cvsInCount = crmtl.wasLocked() ? cvSourcePorts.getPortCount() : 0;
4077 #else
4078 const uint32_t cvsInCount = 0;
4079 #endif
4081 const float* audioIn[audioInCount];
4082 /* */ float* audioOut[audioOutCount];
4083 const float* cvIn[cvInCount+cvsInCount];
4084 /* */ float* cvOut[cvOutCount];
4086 for (uint32_t i=0; i < audioInCount; ++i)
4088 if (CarlaEngineAudioPort* const port = plugin->getAudioInPort(i))
4089 audioIn[i] = port->getBuffer();
4090 else
4091 audioIn[i] = nullptr;
4094 for (uint32_t i=0; i < audioOutCount; ++i)
4096 if (CarlaEngineAudioPort* const port = plugin->getAudioOutPort(i))
4097 audioOut[i] = port->getBuffer();
4098 else
4099 audioOut[i] = nullptr;
4102 for (uint32_t i=0; i < cvInCount; ++i)
4104 if (CarlaEngineCVPort* const port = plugin->getCVInPort(i))
4105 cvIn[i] = port->getBuffer();
4106 else
4107 cvIn[i] = nullptr;
4110 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
4111 for (uint32_t i=cvInCount, j=0; j < cvsInCount; ++i, ++j)
4113 if (CarlaEngineCVPort* const port = cvSourcePorts.getPort(j))
4115 port->initBuffer();
4116 cvIn[i] = port->getBuffer();
4118 else
4120 cvIn[i] = nullptr;
4123 #endif
4125 for (uint32_t i=0; i < cvOutCount; ++i)
4127 if (CarlaEngineCVPort* const port = plugin->getCVOutPort(i))
4128 cvOut[i] = port->getBuffer();
4129 else
4130 cvOut[i] = nullptr;
4133 float inPeaks[2] = { 0.0f };
4134 float outPeaks[2] = { 0.0f };
4136 for (uint32_t i=0; i < audioInCount && i < 2; ++i)
4138 for (uint32_t j=0; j < nframes; ++j)
4140 const float absV(std::abs(audioIn[i][j]));
4142 if (absV > inPeaks[i])
4143 inPeaks[i] = absV;
4147 plugin->process(audioIn, audioOut, cvIn, cvOut, nframes);
4149 for (uint32_t i=0; i < audioOutCount && i < 2; ++i)
4151 for (uint32_t j=0; j < nframes; ++j)
4153 const float absV(std::abs(audioOut[i][j]));
4155 if (absV > outPeaks[i])
4156 outPeaks[i] = absV;
4160 setPluginPeaksRT(plugin->getId(), inPeaks, outPeaks);
4163 #ifndef BUILD_BRIDGE
4164 // -------------------------------------------------------------------
4166 struct PostPonedJackEvent {
4167 enum Type {
4168 kTypeNull = 0,
4169 kTypeClientUnregister,
4170 kTypeClientPositionChange,
4171 kTypePortRegister,
4172 kTypePortUnregister,
4173 kTypePortConnect,
4174 kTypePortDisconnect,
4175 kTypePortRename
4178 Type type;
4180 union {
4181 struct {
4182 char name[STR_MAX+1];
4183 } clientRegister;
4184 struct {
4185 char name[STR_MAX+1];
4186 } clientUnregister;
4187 struct {
4188 jack_uuid_t uuid;
4189 } clientPositionChange;
4190 struct {
4191 char shortName[STR_MAX+1];
4192 char fullName[STR_MAX+1];
4193 CarlaJackPortHints hints;
4194 } portRegister;
4195 struct {
4196 char fullName[STR_MAX+1];
4197 } portUnregister;
4198 struct {
4199 char oldFullName[STR_MAX+1];
4200 char newFullName[STR_MAX+1];
4201 char newShortName[STR_MAX+1];
4202 } portRename;
4203 struct {
4204 char portNameA[STR_MAX+1];
4205 char portNameB[STR_MAX+1];
4206 } portConnect;
4207 struct {
4208 char portNameA[STR_MAX+1];
4209 char portNameB[STR_MAX+1];
4210 } portDisconnect;
4214 LinkedList<PostPonedJackEvent> fPostPonedEvents;
4215 CarlaMutex fPostPonedEventsMutex;
4217 bool fIsInternalClient;
4219 void postponeJackCallback(PostPonedJackEvent& ev)
4221 const CarlaMutexLocker cml(fPostPonedEventsMutex);
4222 fPostPonedEvents.append(ev);
4225 void run() override
4227 for (; ! shouldThreadExit();)
4229 if (fIsInternalClient)
4230 idle();
4232 if (fClient == nullptr)
4233 break;
4235 carla_msleep(200);
4238 #endif // BUILD_BRIDGE
4240 // -------------------------------------------------------------------
4242 // disable -Wattributes warnings
4243 #if defined(__clang__)
4244 # pragma clang diagnostic push
4245 # pragma clang diagnostic ignored "-Wattributes"
4246 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
4247 # pragma GCC diagnostic push
4248 # pragma GCC diagnostic ignored "-Wattributes"
4249 #endif
4251 #define handlePtr ((CarlaEngineJack*)arg)
4253 static void JACKBRIDGE_API carla_jack_thread_init_callback(void*)
4255 #ifdef __SSE2_MATH__
4256 // Set FTZ and DAZ flags
4257 _mm_setcsr(_mm_getcsr() | 0x8040);
4258 #endif
4261 static int JACKBRIDGE_API carla_jack_bufsize_callback(jack_nframes_t newBufferSize, void* arg)
4263 handlePtr->handleJackBufferSizeCallback(newBufferSize);
4264 return 0;
4267 static int JACKBRIDGE_API carla_jack_srate_callback(jack_nframes_t newSampleRate, void* arg)
4269 handlePtr->handleJackSampleRateCallback(newSampleRate);
4270 return 0;
4273 static void JACKBRIDGE_API carla_jack_freewheel_callback(int starting, void* arg)
4275 handlePtr->handleJackFreewheelCallback(bool(starting));
4278 static void JACKBRIDGE_API carla_jack_latency_callback(jack_latency_callback_mode_t mode, void* arg)
4280 handlePtr->handleJackLatencyCallback(mode);
4283 static int JACKBRIDGE_API carla_jack_process_callback(jack_nframes_t nframes, void* arg) __attribute__((annotate("realtime")))
4285 handlePtr->handleJackProcessCallback(nframes);
4286 return 0;
4289 #ifndef BUILD_BRIDGE
4290 static void JACKBRIDGE_API carla_jack_timebase_callback(jack_transport_state_t, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg) __attribute__((annotate("realtime")))
4292 handlePtr->handleJackTimebaseCallback(nframes, pos, new_pos);
4295 static void JACKBRIDGE_API carla_jack_client_registration_callback(const char* name, int reg, void* arg)
4297 if (reg == 0)
4298 return;
4300 PostPonedJackEvent ev;
4301 carla_zeroStruct(ev);
4302 ev.type = PostPonedJackEvent::kTypeClientUnregister;
4303 std::strncpy(ev.clientUnregister.name, name, STR_MAX);
4304 handlePtr->postponeJackCallback(ev);
4307 static void JACKBRIDGE_API carla_jack_port_registration_callback(jack_port_id_t port_id, int reg, void* arg)
4309 const jack_port_t* const port = jackbridge_port_by_id(handlePtr->fClient, port_id);
4310 CARLA_SAFE_ASSERT_RETURN(port != nullptr,);
4312 const char* const fullName = jackbridge_port_name(port);
4313 CARLA_SAFE_ASSERT_RETURN(fullName != nullptr && fullName[0] != '\0',);
4315 PostPonedJackEvent ev;
4316 carla_zeroStruct(ev);
4318 if (reg != 0)
4320 const char* const shortName = jackbridge_port_short_name(port);
4321 CARLA_SAFE_ASSERT_RETURN(shortName != nullptr && shortName[0] != '\0',);
4323 ev.type = PostPonedJackEvent::kTypePortRegister;
4324 std::strncpy(ev.portRegister.fullName, fullName, STR_MAX);
4325 std::strncpy(ev.portRegister.shortName, shortName, STR_MAX);
4327 const CarlaRecursiveMutexLocker crml(handlePtr->fThreadSafeMetadataMutex);
4328 ev.portRegister.hints = CarlaJackPortHints::fromPort(port);
4330 else
4332 ev.type = PostPonedJackEvent::kTypePortUnregister;
4333 std::strncpy(ev.portUnregister.fullName, fullName, STR_MAX);
4336 handlePtr->postponeJackCallback(ev);
4339 static void JACKBRIDGE_API carla_jack_port_connect_callback(jack_port_id_t a, jack_port_id_t b, int connect, void* arg)
4341 const jack_port_t* const portA = jackbridge_port_by_id(handlePtr->fClient, a);
4342 CARLA_SAFE_ASSERT_RETURN(portA != nullptr,);
4344 const jack_port_t* const portB = jackbridge_port_by_id(handlePtr->fClient, b);
4345 CARLA_SAFE_ASSERT_RETURN(portB != nullptr,);
4347 const char* const fullNameA = jackbridge_port_name(portA);
4348 CARLA_SAFE_ASSERT_RETURN(fullNameA != nullptr && fullNameA[0] != '\0',);
4350 const char* const fullNameB = jackbridge_port_name(portB);
4351 CARLA_SAFE_ASSERT_RETURN(fullNameB != nullptr && fullNameB[0] != '\0',);
4353 PostPonedJackEvent ev;
4354 carla_zeroStruct(ev);
4356 if (connect != 0)
4358 ev.type = PostPonedJackEvent::kTypePortConnect;
4359 std::strncpy(ev.portConnect.portNameA, fullNameA, STR_MAX);
4360 std::strncpy(ev.portConnect.portNameB, fullNameB, STR_MAX);
4362 else
4364 ev.type = PostPonedJackEvent::kTypePortDisconnect;
4365 std::strncpy(ev.portDisconnect.portNameA, fullNameA, STR_MAX);
4366 std::strncpy(ev.portDisconnect.portNameB, fullNameB, STR_MAX);
4369 handlePtr->postponeJackCallback(ev);
4372 static void JACKBRIDGE_API carla_jack_port_rename_callback(jack_port_id_t port_id, const char* oldName, const char* newName, void* arg)
4374 const jack_port_t* const port = jackbridge_port_by_id(handlePtr->fClient, port_id);
4375 CARLA_SAFE_ASSERT_RETURN(port != nullptr,);
4377 const char* const shortName = jackbridge_port_short_name(port);
4378 CARLA_SAFE_ASSERT_RETURN(shortName != nullptr && shortName[0] != '\0',);
4380 PostPonedJackEvent ev;
4381 carla_zeroStruct(ev);
4382 ev.type = PostPonedJackEvent::kTypePortRename;
4383 std::strncpy(ev.portRename.oldFullName, oldName, STR_MAX);
4384 std::strncpy(ev.portRename.newFullName, newName, STR_MAX);
4385 std::strncpy(ev.portRename.newShortName, shortName, STR_MAX);
4386 handlePtr->postponeJackCallback(ev);
4389 static void carla_jack_property_change_callback(jack_uuid_t subject, const char* key, jack_property_change_t change, void* arg)
4391 if (change != PropertyChanged)
4392 return;
4393 if (std::strcmp(key, URI_POSITION) != 0)
4394 return;
4396 PostPonedJackEvent ev;
4397 carla_zeroStruct(ev);
4398 ev.type = PostPonedJackEvent::kTypeClientPositionChange;
4399 ev.clientPositionChange.uuid = subject;
4400 handlePtr->postponeJackCallback(ev);
4403 static int JACKBRIDGE_API carla_jack_xrun_callback(void* arg)
4405 ++(handlePtr->pData->xruns);
4406 return 0;
4408 #endif
4410 static void JACKBRIDGE_API carla_jack_shutdown_callback(void* arg)
4412 handlePtr->handleJackShutdownCallback();
4415 #undef handlePtr
4417 // -------------------------------------------------------------------
4419 #ifndef BUILD_BRIDGE
4420 static int JACKBRIDGE_API carla_jack_process_callback_plugin(jack_nframes_t nframes, void* arg) __attribute__((annotate("realtime")))
4422 CarlaPluginPtr* const pluginPtr = static_cast<CarlaPluginPtr*>(arg);
4423 CARLA_SAFE_ASSERT_RETURN(pluginPtr != nullptr, 0);
4425 CarlaPluginPtr plugin = *pluginPtr;
4426 CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr && plugin->isEnabled(), 0);
4428 CarlaEngineJack* const engine((CarlaEngineJack*)plugin->getEngine());
4429 CARLA_SAFE_ASSERT_RETURN(engine != nullptr, 0);
4431 if (plugin->tryLock(engine->fFreewheel))
4433 plugin->initBuffers();
4434 engine->processPlugin(plugin, nframes);
4435 plugin->unlock();
4438 return 0;
4442 static int JACKBRIDGE_API carla_jack_bufsize_callback_plugin(jack_nframes_t nframes, void* arg)
4444 CarlaPlugin* const plugin((CarlaPlugin*)arg);
4445 CARLA_SAFE_ASSERT_RETURN(plugin != nullptr && plugin->isEnabled(), 0);
4447 plugin->bufferSizeChanged(nframes);
4448 return 1;
4451 static int JACKBRIDGE_API carla_jack_srate_callback_plugin(jack_nframes_t nframes, void* arg)
4453 CarlaPlugin* const plugin((CarlaPlugin*)arg);
4454 CARLA_SAFE_ASSERT_RETURN(plugin != nullptr && plugin->isEnabled(), 0);
4456 plugin->sampleRateChanged(nframes);
4457 return 1;
4461 static void JACKBRIDGE_API carla_jack_latency_callback_plugin(jack_latency_callback_mode_t /*mode*/, void* /*arg*/)
4463 // TODO
4466 static void JACKBRIDGE_API carla_jack_shutdown_callback_plugin(void* arg)
4468 CarlaPluginPtr* const pluginPtr = static_cast<CarlaPluginPtr*>(arg);
4469 CARLA_SAFE_ASSERT_RETURN(pluginPtr != nullptr,);
4471 CarlaPluginPtr plugin = *pluginPtr;
4472 CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr,);
4474 CarlaEngineJack* const engine((CarlaEngineJack*)plugin->getEngine());
4475 CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
4477 engine->handlePluginJackShutdownCallback(plugin);
4479 #endif
4481 // enable -Wattributes again
4482 #if defined(__clang__)
4483 # pragma clang diagnostic pop
4484 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
4485 # pragma GCC diagnostic pop
4486 #endif
4488 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineJack)
4491 // -----------------------------------------------------------------------
4493 namespace EngineInit {
4495 CarlaEngine* newJack()
4497 carla_debug("EngineInit::newJack()");
4498 return new CarlaEngineJack();
4503 // -----------------------------------------------------------------------
4505 CARLA_BACKEND_END_NAMESPACE
4507 #if defined(JACKBRIDGE_DIRECT) && !defined(BUILD_BRIDGE)
4508 // -----------------------------------------------------------------------
4509 // internal jack client
4511 CARLA_PLUGIN_EXPORT
4512 int jack_initialize(jack_client_t *client, const char *load_init);
4514 CARLA_PLUGIN_EXPORT
4515 void jack_finish(void *arg);
4517 #ifdef CARLA_OS_UNIX
4518 # include "ThreadSafeFFTW.hpp"
4519 #endif
4521 // -----------------------------------------------------------------------
4523 CARLA_PLUGIN_EXPORT
4524 int jack_initialize(jack_client_t* const client, const char* const load_init)
4526 CARLA_BACKEND_USE_NAMESPACE
4528 #ifdef CARLA_OS_UNIX
4529 static const ThreadSafeFFTW sThreadSafeFFTW;
4530 #endif
4532 EngineProcessMode mode;
4533 if (load_init != nullptr && std::strcmp(load_init, "rack") == 0)
4534 mode = ENGINE_PROCESS_MODE_CONTINUOUS_RACK;
4535 else
4536 mode = ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS;
4538 #ifdef USING_JUCE
4539 CarlaJUCE::initialiseJuce_GUI();
4540 #endif
4542 CarlaEngineJack* const engine = new CarlaEngineJack();
4544 engine->setOption(ENGINE_OPTION_FORCE_STEREO, 1, nullptr);
4545 engine->setOption(ENGINE_OPTION_AUDIO_DRIVER, 0, "JACK");
4546 engine->setOption(ENGINE_OPTION_AUDIO_DEVICE, 0, "Auto-Connect ON");
4547 engine->setOption(ENGINE_OPTION_OSC_ENABLED, 1, nullptr);
4548 engine->setOption(ENGINE_OPTION_OSC_PORT_TCP, 22752, nullptr);
4549 engine->setOption(ENGINE_OPTION_OSC_PORT_UDP, 22752, nullptr);
4551 engine->setOption(ENGINE_OPTION_PROCESS_MODE, mode, nullptr);
4552 engine->setOption(ENGINE_OPTION_TRANSPORT_MODE, ENGINE_TRANSPORT_MODE_JACK, nullptr);
4554 #ifdef __MOD_DEVICES__
4555 engine->setOption(ENGINE_OPTION_FILE_PATH, FILE_AUDIO, "/data/user-files/Audio Loops:/data/user-files/Audio Tracks");
4556 engine->setOption(ENGINE_OPTION_FILE_PATH, FILE_MIDI, "/data/user-files/MIDI Songs");
4557 #endif
4559 // FIXME
4560 engine->setOption(ENGINE_OPTION_PATH_BINARIES, 0, "/usr/lib/carla");
4561 engine->setOption(ENGINE_OPTION_PATH_RESOURCES, 0, "/usr/share/resources");
4563 if (engine->initInternal(client))
4564 return 0;
4566 delete engine;
4567 #ifdef USING_JUCE
4568 CarlaJUCE::shutdownJuce_GUI();
4569 #endif
4570 return 1;
4573 CARLA_PLUGIN_EXPORT
4574 void jack_finish(void *arg)
4576 CARLA_BACKEND_USE_NAMESPACE
4578 CarlaEngineJack* const engine = (CarlaEngineJack*)arg;;
4579 CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
4581 engine->setAboutToClose();
4582 engine->removeAllPlugins();
4583 engine->close();
4584 delete engine;
4586 #ifdef USING_JUCE
4587 CarlaJUCE::shutdownJuce_GUI();
4588 #endif
4591 // -----------------------------------------------------------------------
4592 #endif // defined(JACKBRIDGE_DIRECT) && !defined(BUILD_BRIDGE)