Clean water File(const String&) usage
[carla.git] / source / backend / engine / CarlaEngineBridge.cpp
blobce6d3c26ba0495f89d293c1601ef26c22029874d
1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
4 #ifndef BUILD_BRIDGE
5 # error This file should not be compiled if not building bridge
6 #endif
8 // must be first so we can undef CARLA_SAFE_*_RETURN_ERR* macros
9 #include "CarlaPluginInternal.hpp"
10 #undef CARLA_SAFE_ASSERT_RETURN_ERR
11 #undef CARLA_SAFE_ASSERT_RETURN_ERRN
12 #undef CARLA_SAFE_EXCEPTION_RETURN_ERR
13 #undef CARLA_SAFE_EXCEPTION_RETURN_ERRN
15 #include "CarlaEngineClient.hpp"
16 #include "CarlaEngineInit.hpp"
18 #include "CarlaBackendUtils.hpp"
19 #include "CarlaBase64Utils.hpp"
20 #include "CarlaBridgeUtils.hpp"
21 #include "CarlaTimeUtils.hpp"
22 #include "CarlaMIDI.h"
24 #ifdef __SSE2_MATH__
25 # include <xmmintrin.h>
26 #endif
28 #include "water/files/File.h"
29 #include "water/misc/Time.h"
31 // must be last
32 #include "jackbridge/JackBridge.hpp"
34 using water::File;
35 using water::MemoryBlock;
36 using water::String;
38 CARLA_BACKEND_START_NAMESPACE
40 // -----------------------------------------------------------------------
41 // Bridge Engine client
43 struct LatencyChangedCallback {
44 virtual ~LatencyChangedCallback() noexcept {}
45 virtual void latencyChanged(const uint32_t samples) noexcept = 0;
48 class CarlaEngineBridgeClient : public CarlaEngineClientForSubclassing
50 public:
51 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
52 CarlaEngineBridgeClient(const CarlaEngine& engine,
53 EngineInternalGraph& egraph,
54 const CarlaPluginPtr plugin,
55 LatencyChangedCallback* const cb)
56 : CarlaEngineClientForSubclassing(engine, egraph, plugin),
57 fLatencyCallback(cb) {}
58 #else
59 CarlaEngineBridgeClient(const CarlaEngine& engine, LatencyChangedCallback* const cb)
60 : CarlaEngineClientForSubclassing(engine),
61 fLatencyCallback(cb) {}
62 #endif
64 protected:
65 void setLatency(const uint32_t samples) noexcept override
67 if (getLatency() == samples)
68 return;
70 fLatencyCallback->latencyChanged(samples);
71 CarlaEngineClient::setLatency(samples);
74 private:
75 LatencyChangedCallback* const fLatencyCallback;
77 CARLA_DECLARE_NON_COPYABLE(CarlaEngineBridgeClient)
80 // -------------------------------------------------------------------
82 struct BridgeTextReader {
83 char* text;
85 BridgeTextReader(BridgeNonRtClientControl& nonRtClientCtrl)
86 : text(nullptr)
88 const uint32_t size = nonRtClientCtrl.readUInt();
89 CARLA_SAFE_ASSERT_RETURN(size != 0,);
91 text = new char[size + 1];
92 nonRtClientCtrl.readCustomData(text, size);
93 text[size] = '\0';
96 BridgeTextReader(BridgeNonRtClientControl& nonRtClientCtrl, const uint32_t size)
97 : text(nullptr)
99 text = new char[size + 1];
101 if (size != 0)
102 nonRtClientCtrl.readCustomData(text, size);
104 text[size] = '\0';
107 ~BridgeTextReader() noexcept
109 delete[] text;
112 CARLA_DECLARE_NON_COPYABLE(BridgeTextReader)
115 // -------------------------------------------------------------------
117 class CarlaEngineBridge : public CarlaEngine,
118 private CarlaThread,
119 private LatencyChangedCallback
121 public:
122 CarlaEngineBridge(const char* const audioPoolBaseName, const char* const rtClientBaseName, const char* const nonRtClientBaseName, const char* const nonRtServerBaseName)
123 : CarlaEngine(),
124 CarlaThread("CarlaEngineBridge"),
125 fShmAudioPool(),
126 fShmRtClientControl(),
127 fShmNonRtClientControl(),
128 fShmNonRtServerControl(),
129 fBaseNameAudioPool(audioPoolBaseName),
130 fBaseNameRtClientControl(rtClientBaseName),
131 fBaseNameNonRtClientControl(nonRtClientBaseName),
132 fBaseNameNonRtServerControl(nonRtServerBaseName),
133 fClosingDown(false),
134 fIsOffline(false),
135 fFirstIdle(true),
136 fBridgeVersion(0),
137 fLastPingTime(UINT32_MAX)
139 carla_debug("CarlaEngineBridge::CarlaEngineBridge(\"%s\", \"%s\", \"%s\", \"%s\")", audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName);
142 ~CarlaEngineBridge() noexcept override
144 carla_debug("CarlaEngineBridge::~CarlaEngineBridge()");
146 clear();
149 // -------------------------------------
150 // CarlaEngine virtual calls
152 bool init(const char* const clientName) override
154 carla_debug("CarlaEngineBridge::init(\"%s\")", clientName);
156 if (! pData->init(clientName))
158 setLastError("Failed to init internal data");
159 return false;
162 if (! fShmAudioPool.attachClient(fBaseNameAudioPool))
164 pData->close();
165 setLastError("Failed to attach to audio pool shared memory");
166 return false;
169 if (! fShmRtClientControl.attachClient(fBaseNameRtClientControl))
171 pData->close();
172 clear();
173 setLastError("Failed to attach to rt client control shared memory");
174 return false;
177 if (! fShmRtClientControl.mapData())
179 pData->close();
180 clear();
181 setLastError("Failed to map rt client control shared memory");
182 return false;
185 if (! fShmNonRtClientControl.attachClient(fBaseNameNonRtClientControl))
187 pData->close();
188 clear();
189 setLastError("Failed to attach to non-rt client control shared memory");
190 return false;
193 if (! fShmNonRtClientControl.mapData())
195 pData->close();
196 clear();
197 setLastError("Failed to map non-rt control client shared memory");
198 return false;
201 if (! fShmNonRtServerControl.attachClient(fBaseNameNonRtServerControl))
203 pData->close();
204 clear();
205 setLastError("Failed to attach to non-rt server control shared memory");
206 return false;
209 if (! fShmNonRtServerControl.mapData())
211 pData->close();
212 clear();
213 setLastError("Failed to map non-rt control server shared memory");
214 return false;
217 PluginBridgeNonRtClientOpcode opcode;
219 opcode = fShmNonRtClientControl.readOpcode();
220 CARLA_SAFE_ASSERT_RETURN(opcode == kPluginBridgeNonRtClientVersion, false);
222 const uint32_t apiVersion = fShmNonRtClientControl.readUInt();
223 CARLA_SAFE_ASSERT_RETURN(apiVersion >= CARLA_PLUGIN_BRIDGE_API_VERSION_MINIMUM, false);
225 const uint32_t shmRtClientDataSize = fShmNonRtClientControl.readUInt();
226 CARLA_SAFE_ASSERT_INT2(shmRtClientDataSize == sizeof(BridgeRtClientData), shmRtClientDataSize, sizeof(BridgeRtClientData));
228 const uint32_t shmNonRtClientDataSize = fShmNonRtClientControl.readUInt();
229 CARLA_SAFE_ASSERT_INT2(shmNonRtClientDataSize == sizeof(BridgeNonRtClientData), shmNonRtClientDataSize, sizeof(BridgeNonRtClientData));
231 const uint32_t shmNonRtServerDataSize = fShmNonRtClientControl.readUInt();
232 CARLA_SAFE_ASSERT_INT2(shmNonRtServerDataSize == sizeof(BridgeNonRtServerData), shmNonRtServerDataSize, sizeof(BridgeNonRtServerData));
234 if (shmRtClientDataSize != sizeof(BridgeRtClientData) ||
235 shmNonRtClientDataSize != sizeof(BridgeNonRtClientData) ||
236 shmNonRtServerDataSize != sizeof(BridgeNonRtServerData))
238 pData->close();
239 clear();
240 setLastError("Shared memory data size mismatch");
241 return false;
244 opcode = fShmNonRtClientControl.readOpcode();
245 CARLA_SAFE_ASSERT_RETURN(opcode == kPluginBridgeNonRtClientInitialSetup, false);
247 pData->bufferSize = fShmNonRtClientControl.readUInt();
248 pData->sampleRate = fShmNonRtClientControl.readDouble();
250 if (pData->bufferSize == 0 || carla_isZero(pData->sampleRate))
252 pData->close();
253 clear();
254 setLastError("Shared memory has invalid data");
255 return false;
258 pData->initTime(nullptr);
260 // tell backend we're live
262 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
264 // kPluginBridgeNonRtServerVersion was added in API 7
265 if (apiVersion >= 7)
267 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerVersion);
268 fShmNonRtServerControl.writeUInt(CARLA_PLUGIN_BRIDGE_API_VERSION_CURRENT);
270 else
272 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPong);
275 fShmNonRtServerControl.commitWrite();
278 startThread(true);
279 return true;
282 bool close() override
284 carla_debug("CarlaEngineBridge::close()");
285 fLastPingTime = UINT32_MAX;
287 CarlaEngine::close();
289 stopThread(5000);
290 clear();
292 return true;
295 bool hasIdleOnMainThread() const noexcept override
297 return true;
300 bool isRunning() const noexcept override
302 if (fClosingDown)
303 return false;
305 return isThreadRunning() || ! fFirstIdle;
308 bool isOffline() const noexcept override
310 return fIsOffline;
313 EngineType getType() const noexcept override
315 return kEngineTypeBridge;
318 const char* getCurrentDriverName() const noexcept override
320 return "Bridge";
323 void touchPluginParameter(const uint id, const uint32_t parameterId, const bool touch) noexcept override
325 CARLA_SAFE_ASSERT_RETURN(id == 0,);
327 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
328 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterTouch);
329 fShmNonRtServerControl.writeUInt(parameterId);
330 fShmNonRtServerControl.writeBool(touch);
331 fShmNonRtServerControl.commitWrite();
334 CarlaEngineClient* addClient(const CarlaPluginPtr plugin) override
336 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
337 return new CarlaEngineBridgeClient(*this, pData->graph, plugin, this);
338 #else
339 return new CarlaEngineBridgeClient(*this, this);
341 // unused
342 (void)plugin;
343 #endif
346 void idle() noexcept override
348 const CarlaPluginPtr plugin = pData->plugins[0].plugin;
350 if (plugin.get() == nullptr)
352 if (const uint32_t length = static_cast<uint32_t>(pData->lastError.length()))
354 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
355 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError);
356 fShmNonRtServerControl.writeUInt(length);
357 fShmNonRtServerControl.writeCustomData(pData->lastError.buffer(), length);
358 fShmNonRtServerControl.commitWrite();
361 signalThreadShouldExit();
362 callback(true, true, ENGINE_CALLBACK_QUIT, 0, 0, 0, 0, 0.0f, nullptr);
363 return;
366 const bool wasFirstIdle = fFirstIdle;
368 if (wasFirstIdle)
370 fFirstIdle = false;
371 fLastPingTime = carla_gettime_ms();
373 char bufStr[STR_MAX+1];
374 carla_zeroChars(bufStr, STR_MAX+1);
376 uint32_t bufStrSize;
378 const CarlaEngineClient* const client(plugin->getEngineClient());
379 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
381 // kPluginBridgeNonRtServerPluginInfo1
383 // uint/category, uint/hints, uint/optionsAvailable, uint/optionsEnabled, long/uniqueId
384 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPluginInfo1);
385 fShmNonRtServerControl.writeUInt(plugin->getCategory());
386 fShmNonRtServerControl.writeUInt(plugin->getHints());
387 fShmNonRtServerControl.writeUInt(plugin->getOptionsAvailable());
388 fShmNonRtServerControl.writeUInt(plugin->getOptionsEnabled());
389 fShmNonRtServerControl.writeLong(plugin->getUniqueId());
390 fShmNonRtServerControl.commitWrite();
393 // kPluginBridgeNonRtServerPluginInfo2
395 // uint/size, str[] (realName), uint/size, str[] (label), uint/size, str[] (maker), uint/size, str[] (copyright)
396 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPluginInfo2);
398 if (! plugin->getRealName(bufStr))
399 bufStr[0] = '\0';
400 bufStrSize = carla_fixedValue(1U, 64U, static_cast<uint32_t>(std::strlen(bufStr)));
401 fShmNonRtServerControl.writeUInt(bufStrSize);
402 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
404 if (! plugin->getLabel(bufStr))
405 bufStr[0] = '\0';
406 bufStrSize = carla_fixedValue(1U, 256U, static_cast<uint32_t>(std::strlen(bufStr)));
407 fShmNonRtServerControl.writeUInt(bufStrSize);
408 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
410 if (! plugin->getMaker(bufStr))
411 bufStr[0] = '\0';
412 bufStrSize = carla_fixedValue(1U, 64U, static_cast<uint32_t>(std::strlen(bufStr)));
413 fShmNonRtServerControl.writeUInt(bufStrSize);
414 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
416 if (! plugin->getCopyright(bufStr))
417 bufStr[0] = '\0';
418 bufStrSize = carla_fixedValue(1U, 64U, static_cast<uint32_t>(std::strlen(bufStr)));
419 fShmNonRtServerControl.writeUInt(bufStrSize);
420 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
422 fShmNonRtServerControl.commitWrite();
425 fShmNonRtServerControl.waitIfDataIsReachingLimit();
427 // kPluginBridgeNonRtServerAudioCount
429 const uint32_t aIns = plugin->getAudioInCount();
430 const uint32_t aOuts = plugin->getAudioOutCount();
432 // uint/ins, uint/outs
433 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerAudioCount);
434 fShmNonRtServerControl.writeUInt(aIns);
435 fShmNonRtServerControl.writeUInt(aOuts);
436 fShmNonRtServerControl.commitWrite();
438 // kPluginBridgeNonRtServerPortName
439 for (uint32_t i=0; i<aIns; ++i)
441 const char* const portName(client->getAudioPortName(true, i));
442 CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0');
444 // byte/type, uint/index, uint/size, str[] (name)
445 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPortName);
446 fShmNonRtServerControl.writeByte(kPluginBridgePortAudioInput);
447 fShmNonRtServerControl.writeUInt(i);
449 bufStrSize = static_cast<uint32_t>(std::strlen(portName));
450 fShmNonRtServerControl.writeUInt(bufStrSize);
451 fShmNonRtServerControl.writeCustomData(portName, bufStrSize);
454 // kPluginBridgeNonRtServerPortName
455 for (uint32_t i=0; i<aOuts; ++i)
457 const char* const portName(client->getAudioPortName(false, i));
458 CARLA_SAFE_ASSERT_CONTINUE(portName != nullptr && portName[0] != '\0');
460 // byte/type, uint/index, uint/size, str[] (name)
461 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPortName);
462 fShmNonRtServerControl.writeByte(kPluginBridgePortAudioOutput);
463 fShmNonRtServerControl.writeUInt(i);
465 bufStrSize = static_cast<uint32_t>(std::strlen(portName));
466 fShmNonRtServerControl.writeUInt(bufStrSize);
467 fShmNonRtServerControl.writeCustomData(portName, bufStrSize);
471 fShmNonRtServerControl.waitIfDataIsReachingLimit();
473 // kPluginBridgeNonRtServerMidiCount
475 // uint/ins, uint/outs
476 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerMidiCount);
477 fShmNonRtServerControl.writeUInt(plugin->getMidiInCount());
478 fShmNonRtServerControl.writeUInt(plugin->getMidiOutCount());
479 fShmNonRtServerControl.commitWrite();
482 fShmNonRtServerControl.waitIfDataIsReachingLimit();
484 // kPluginBridgeNonRtServerCvCount
486 // uint/ins, uint/outs
487 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerCvCount);
488 fShmNonRtServerControl.writeUInt(plugin->getCVInCount());
489 fShmNonRtServerControl.writeUInt(plugin->getCVOutCount());
490 fShmNonRtServerControl.commitWrite();
493 fShmNonRtServerControl.waitIfDataIsReachingLimit();
495 // kPluginBridgeNonRtServerParameter*
496 if (const uint32_t count = plugin->getParameterCount())
498 // uint/count
499 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterCount);
500 fShmNonRtServerControl.writeUInt(count);
501 fShmNonRtServerControl.commitWrite();
503 for (uint32_t i=0; i<count; ++i)
505 const ParameterData& paramData(plugin->getParameterData(i));
507 if (paramData.type != PARAMETER_INPUT && paramData.type != PARAMETER_OUTPUT)
508 continue;
509 if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
510 continue;
512 // kPluginBridgeNonRtServerParameterData1
514 // uint/index, int/rindex, uint/type, uint/hints, short/cc
515 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterData1);
516 fShmNonRtServerControl.writeUInt(i);
517 fShmNonRtServerControl.writeInt(paramData.rindex);
518 fShmNonRtServerControl.writeUInt(paramData.type);
519 fShmNonRtServerControl.writeUInt(paramData.hints);
520 fShmNonRtServerControl.writeShort(paramData.mappedControlIndex);
521 fShmNonRtServerControl.commitWrite();
524 // kPluginBridgeNonRtServerParameterData2
526 // uint/index, uint/size, str[] (name), uint/size, str[] (symbol), uint/size, str[] (unit)
527 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterData2);
528 fShmNonRtServerControl.writeUInt(i);
530 if (! plugin->getParameterName(i, bufStr))
531 std::snprintf(bufStr, STR_MAX, "Param %u", i+1);
532 bufStrSize = carla_fixedValue(1U, 32U, static_cast<uint32_t>(std::strlen(bufStr)));
533 fShmNonRtServerControl.writeUInt(bufStrSize);
534 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
536 if (! plugin->getParameterSymbol(i, bufStr))
537 bufStr[0] = '\0';
538 bufStrSize = carla_fixedValue(1U, 64U, static_cast<uint32_t>(std::strlen(bufStr)));
539 fShmNonRtServerControl.writeUInt(bufStrSize);
540 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
542 if (! plugin->getParameterUnit(i, bufStr))
543 bufStr[0] = '\0';
544 bufStrSize = carla_fixedValue(1U, 32U, static_cast<uint32_t>(std::strlen(bufStr)));
545 fShmNonRtServerControl.writeUInt(bufStrSize);
546 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
548 fShmNonRtServerControl.commitWrite();
551 // kPluginBridgeNonRtServerParameterRanges
553 const ParameterRanges& paramRanges(plugin->getParameterRanges(i));
555 // uint/index, float/def, float/min, float/max, float/step, float/stepSmall, float/stepLarge
556 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterRanges);
557 fShmNonRtServerControl.writeUInt(i);
558 fShmNonRtServerControl.writeFloat(paramRanges.def);
559 fShmNonRtServerControl.writeFloat(paramRanges.min);
560 fShmNonRtServerControl.writeFloat(paramRanges.max);
561 fShmNonRtServerControl.writeFloat(paramRanges.step);
562 fShmNonRtServerControl.writeFloat(paramRanges.stepSmall);
563 fShmNonRtServerControl.writeFloat(paramRanges.stepLarge);
564 fShmNonRtServerControl.commitWrite();
567 // kPluginBridgeNonRtServerParameterValue2
569 // uint/index float/value (used for init/output parameters only, don't resend values)
570 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterValue2);
571 fShmNonRtServerControl.writeUInt(i);
572 fShmNonRtServerControl.writeFloat(plugin->getParameterValue(i));
573 fShmNonRtServerControl.commitWrite();
576 fShmNonRtServerControl.waitIfDataIsReachingLimit();
580 // kPluginBridgeNonRtServerProgram*
581 if (const uint32_t count = plugin->getProgramCount())
583 // uint/count
584 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerProgramCount);
585 fShmNonRtServerControl.writeUInt(count);
586 fShmNonRtServerControl.commitWrite();
588 for (uint32_t i=0; i < count; ++i)
590 // uint/index, uint/size, str[] (name)
591 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerProgramName);
592 fShmNonRtServerControl.writeUInt(i);
594 if (! plugin->getProgramName(i, bufStr))
595 bufStr[0] = '\0';
596 bufStrSize = carla_fixedValue(1U, 32U, static_cast<uint32_t>(std::strlen(bufStr)));
597 fShmNonRtServerControl.writeUInt(bufStrSize);
598 fShmNonRtServerControl.writeCustomData(bufStr, bufStrSize);
600 fShmNonRtServerControl.commitWrite();
601 fShmNonRtServerControl.waitIfDataIsReachingLimit();
605 // kPluginBridgeNonRtServerMidiProgram*
606 if (const uint32_t count = plugin->getMidiProgramCount())
608 // uint/count
609 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerMidiProgramCount);
610 fShmNonRtServerControl.writeUInt(count);
611 fShmNonRtServerControl.commitWrite();
613 for (uint32_t i=0; i < count; ++i)
615 const MidiProgramData& mpData(plugin->getMidiProgramData(i));
616 CARLA_SAFE_ASSERT_CONTINUE(mpData.name != nullptr);
618 // uint/index, uint/bank, uint/program, uint/size, str[] (name)
619 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerMidiProgramData);
620 fShmNonRtServerControl.writeUInt(i);
621 fShmNonRtServerControl.writeUInt(mpData.bank);
622 fShmNonRtServerControl.writeUInt(mpData.program);
624 bufStrSize = carla_fixedValue(1U, 32U, static_cast<uint32_t>(std::strlen(mpData.name)));
625 fShmNonRtServerControl.writeUInt(bufStrSize);
626 fShmNonRtServerControl.writeCustomData(mpData.name, bufStrSize);
628 fShmNonRtServerControl.commitWrite();
629 fShmNonRtServerControl.waitIfDataIsReachingLimit();
633 if (const uint32_t latency = plugin->getLatencyInFrames())
635 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSetLatency);
636 fShmNonRtServerControl.writeUInt(latency);
637 fShmNonRtServerControl.commitWrite();
640 // ready!
641 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerReady);
642 fShmNonRtServerControl.commitWrite();
643 fShmNonRtServerControl.waitIfDataIsReachingLimit();
645 carla_stdout("Carla Bridge Ready!");
646 fLastPingTime = carla_gettime_ms();
649 // send parameter outputs
650 if (const uint32_t count = plugin->getParameterCount())
652 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
654 for (uint32_t i=0; i < count; ++i)
656 if (! plugin->isParameterOutput(i))
657 continue;
659 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterValue2);
660 fShmNonRtServerControl.writeUInt(i);
661 fShmNonRtServerControl.writeFloat(plugin->getParameterValue(i));
663 // parameter outputs are not that important, we can skip some
664 if (! fShmNonRtServerControl.commitWrite())
665 break;
669 CarlaEngine::idle();
671 try {
672 handleNonRtData();
673 } CARLA_SAFE_EXCEPTION("handleNonRtData");
675 if (fLastPingTime != UINT32_MAX && carla_gettime_ms() > fLastPingTime + 30000 && ! wasFirstIdle)
677 carla_stderr("Did not receive ping message from server for 30 secs, closing...");
678 signalThreadShouldExit();
679 callback(true, true, ENGINE_CALLBACK_QUIT, 0, 0, 0, 0, 0.0f, nullptr);
683 void callback(const bool sendHost, const bool sendOsc,
684 const EngineCallbackOpcode action, const uint pluginId,
685 const int value1, const int value2, const int value3,
686 const float valuef, const char* const valueStr) noexcept override
688 CarlaEngine::callback(sendHost, sendOsc, action, pluginId, value1, value2, value3, valuef, valueStr);
690 if (fClosingDown || ! sendHost)
691 return;
693 switch (action)
695 // uint/index float/value
696 case ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED: {
697 CARLA_SAFE_ASSERT_BREAK(value1 >= 0);
698 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
699 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterValue);
700 fShmNonRtServerControl.writeUInt(static_cast<uint>(value1));
701 fShmNonRtServerControl.writeFloat(valuef);
702 fShmNonRtServerControl.commitWrite();
703 } break;
705 // uint/index float/value
706 case ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED: {
707 CARLA_SAFE_ASSERT_BREAK(value1 >= 0);
708 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
709 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerDefaultValue);
710 fShmNonRtServerControl.writeUInt(static_cast<uint>(value1));
711 fShmNonRtServerControl.writeFloat(valuef);
712 fShmNonRtServerControl.commitWrite();
713 } break;
715 // int/index
716 case ENGINE_CALLBACK_PROGRAM_CHANGED: {
717 CARLA_SAFE_ASSERT_BREAK(value1 >= -1);
718 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
719 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerCurrentProgram);
720 fShmNonRtServerControl.writeInt(value1);
721 fShmNonRtServerControl.commitWrite();
722 } break;
724 // int/index
725 case ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED: {
726 CARLA_SAFE_ASSERT_BREAK(value1 >= -1);
727 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
728 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerCurrentMidiProgram);
729 fShmNonRtServerControl.writeInt(value1);
730 fShmNonRtServerControl.commitWrite();
731 } break;
733 case ENGINE_CALLBACK_UI_STATE_CHANGED:
734 if (value1 != 1)
736 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
737 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerUiClosed);
738 fShmNonRtServerControl.commitWrite();
740 break;
742 case ENGINE_CALLBACK_EMBED_UI_RESIZED: {
743 CARLA_SAFE_ASSERT_BREAK(value1 > 1);
744 CARLA_SAFE_ASSERT_BREAK(value2 > 1);
746 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
748 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerResizeEmbedUI);
749 fShmNonRtServerControl.writeUInt(static_cast<uint>(value1));
750 fShmNonRtServerControl.writeUInt(static_cast<uint>(value2));
751 fShmNonRtServerControl.commitWrite();
752 } break;
754 case ENGINE_CALLBACK_RELOAD_PARAMETERS:
755 if (const CarlaPluginPtr plugin = pData->plugins[0].plugin)
757 if (const uint32_t count = plugin->getParameterCount())
759 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
761 for (uint32_t i=0; i<count; ++i)
763 const ParameterData& paramData(plugin->getParameterData(i));
765 if (paramData.type != PARAMETER_INPUT && paramData.type != PARAMETER_OUTPUT)
766 continue;
767 if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
768 continue;
770 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerParameterValue);
771 fShmNonRtServerControl.writeUInt(i);
772 fShmNonRtServerControl.writeFloat(plugin->getParameterValue(i));
773 fShmNonRtServerControl.commitWrite();
775 fShmNonRtServerControl.waitIfDataIsReachingLimit();
779 break;
781 default:
782 break;
786 // -------------------------------------------------------------------
788 void clear() noexcept
790 fShmAudioPool.clear();
791 fShmRtClientControl.clear();
792 fShmNonRtClientControl.clear();
793 fShmNonRtServerControl.clear();
796 void handleNonRtData()
798 const CarlaPluginPtr plugin = pData->plugins[0].plugin;
799 CARLA_SAFE_ASSERT_RETURN(plugin.get() != nullptr,);
801 for (; fShmNonRtClientControl.isDataAvailableForReading();)
803 const PluginBridgeNonRtClientOpcode opcode = fShmNonRtClientControl.readOpcode();
805 #ifdef DEBUG
806 if (opcode != kPluginBridgeNonRtClientPing) {
807 carla_debug("CarlaEngineBridge::handleNonRtData() - got opcode: %i:%s",
808 opcode, PluginBridgeNonRtClientOpcode2str(opcode));
810 #endif
812 if (opcode != kPluginBridgeNonRtClientNull &&
813 opcode != kPluginBridgeNonRtClientPingOnOff && fLastPingTime != UINT32_MAX)
814 fLastPingTime = carla_gettime_ms();
816 switch (opcode)
818 case kPluginBridgeNonRtClientNull:
819 break;
821 case kPluginBridgeNonRtClientVersion: {
822 fBridgeVersion = fShmNonRtServerControl.readUInt();
823 CARLA_SAFE_ASSERT_UINT2(fBridgeVersion >= CARLA_PLUGIN_BRIDGE_API_VERSION_MINIMUM,
824 fBridgeVersion, CARLA_PLUGIN_BRIDGE_API_VERSION_MINIMUM);
825 } break;
827 case kPluginBridgeNonRtClientPing: {
828 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
830 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerPong);
831 fShmNonRtServerControl.commitWrite();
832 } break;
834 case kPluginBridgeNonRtClientPingOnOff:
835 fLastPingTime = fShmNonRtClientControl.readBool() ? carla_gettime_ms() : UINT32_MAX;
836 break;
838 case kPluginBridgeNonRtClientActivate:
839 if (plugin->isEnabled())
840 plugin->setActive(true, false, false);
841 break;
843 case kPluginBridgeNonRtClientDeactivate:
844 if (plugin->isEnabled())
845 plugin->setActive(false, false, false);
846 break;
848 case kPluginBridgeNonRtClientInitialSetup:
849 // should never happen!!
850 fShmNonRtServerControl.readUInt();
851 fShmNonRtServerControl.readDouble();
852 break;
854 case kPluginBridgeNonRtClientSetParameterValue: {
855 const uint32_t index(fShmNonRtClientControl.readUInt());
856 const float value(fShmNonRtClientControl.readFloat());
858 if (plugin->isEnabled())
859 plugin->setParameterValue(index, value, false, false, false);
860 break;
863 case kPluginBridgeNonRtClientSetParameterMidiChannel: {
864 const uint32_t index(fShmNonRtClientControl.readUInt());
865 const uint8_t channel(fShmNonRtClientControl.readByte());
867 if (plugin->isEnabled())
868 plugin->setParameterMidiChannel(index, channel, false, false);
869 break;
872 case kPluginBridgeNonRtClientSetParameterMappedControlIndex: {
873 const uint32_t index(fShmNonRtClientControl.readUInt());
874 const int16_t ctrl(fShmNonRtClientControl.readShort());
876 if (plugin->isEnabled())
877 plugin->setParameterMappedControlIndex(index, ctrl, false, false, true);
878 break;
881 case kPluginBridgeNonRtClientSetParameterMappedRange: {
882 const uint32_t index = fShmNonRtClientControl.readUInt();
883 const float minimum = fShmNonRtClientControl.readFloat();
884 const float maximum = fShmNonRtClientControl.readFloat();
886 if (plugin->isEnabled())
887 plugin->setParameterMappedRange(index, minimum, maximum, false, false);
888 break;
891 case kPluginBridgeNonRtClientSetProgram: {
892 const int32_t index(fShmNonRtClientControl.readInt());
894 if (plugin->isEnabled())
895 plugin->setProgram(index, true, false, false);
896 break;
899 case kPluginBridgeNonRtClientSetMidiProgram: {
900 const int32_t index(fShmNonRtClientControl.readInt());
902 if (plugin->isEnabled())
903 plugin->setMidiProgram(index, true, false, false);
904 break;
907 case kPluginBridgeNonRtClientSetCustomData: {
908 const uint32_t maxLocalValueLen = fBridgeVersion >= 10 ? 4096 : 16384;
910 // type
911 const BridgeTextReader type(fShmNonRtClientControl);
913 // key
914 const BridgeTextReader key(fShmNonRtClientControl);
916 // value
917 const uint32_t valueSize = fShmNonRtClientControl.readUInt();
919 if (valueSize > 0)
921 if (valueSize > maxLocalValueLen)
923 const BridgeTextReader bigValueFilePathTry(fShmNonRtClientControl);
925 CARLA_SAFE_ASSERT_BREAK(bigValueFilePathTry.text[0] != '\0');
926 if (! plugin->isEnabled()) break;
928 String bigValueFilePath(bigValueFilePathTry.text);
930 #ifdef CARLA_OS_WIN
931 // check if running under Wine
932 if (bigValueFilePath.startsWith("/"))
933 bigValueFilePath = bigValueFilePath.replaceSection(0, 1, "Z:\\").replace("/", "\\");
934 #endif
936 File bigValueFile(bigValueFilePath.toRawUTF8());
937 CARLA_SAFE_ASSERT_BREAK(bigValueFile.existsAsFile());
939 plugin->setCustomData(type.text, key.text, bigValueFile.loadFileAsString().toRawUTF8(), true);
941 bigValueFile.deleteFile();
943 else
945 const BridgeTextReader value(fShmNonRtClientControl, valueSize);
947 if (plugin->isEnabled())
948 plugin->setCustomData(type.text, key.text, value.text, true);
951 else
953 if (plugin->isEnabled())
954 plugin->setCustomData(type.text, key.text, "", true);
957 break;
960 case kPluginBridgeNonRtClientSetChunkDataFile: {
961 const uint32_t size = fShmNonRtClientControl.readUInt();
962 CARLA_SAFE_ASSERT_BREAK(size > 0);
964 const BridgeTextReader chunkFilePathTry(fShmNonRtClientControl, size);
966 CARLA_SAFE_ASSERT_BREAK(chunkFilePathTry.text[0] != '\0');
967 if (! plugin->isEnabled()) break;
969 String chunkFilePath(chunkFilePathTry.text);
971 #ifdef CARLA_OS_WIN
972 // check if running under Wine
973 if (chunkFilePath.startsWith("/"))
974 chunkFilePath = chunkFilePath.replaceSection(0, 1, "Z:\\").replace("/", "\\");
975 #endif
977 File chunkFile(chunkFilePath.toRawUTF8());
978 CARLA_SAFE_ASSERT_BREAK(chunkFile.existsAsFile());
980 String chunkDataBase64(chunkFile.loadFileAsString());
981 chunkFile.deleteFile();
982 CARLA_SAFE_ASSERT_BREAK(chunkDataBase64.isNotEmpty());
984 std::vector<uint8_t> chunk(carla_getChunkFromBase64String(chunkDataBase64.toRawUTF8()));
986 #ifdef CARLA_PROPER_CPP11_SUPPORT
987 plugin->setChunkData(chunk.data(), chunk.size());
988 #else
989 plugin->setChunkData(&chunk.front(), chunk.size());
990 #endif
991 break;
994 case kPluginBridgeNonRtClientSetCtrlChannel: {
995 const int16_t channel(fShmNonRtClientControl.readShort());
996 CARLA_SAFE_ASSERT_BREAK(channel >= -1 && channel < MAX_MIDI_CHANNELS);
998 if (plugin->isEnabled())
999 plugin->setCtrlChannel(static_cast<int8_t>(channel), false, false);
1000 break;
1003 case kPluginBridgeNonRtClientSetOption: {
1004 const uint32_t option(fShmNonRtClientControl.readUInt());
1005 const bool yesNo(fShmNonRtClientControl.readBool());
1007 if (plugin->isEnabled())
1008 plugin->setOption(option, yesNo, false);
1009 break;
1012 case kPluginBridgeNonRtClientSetOptions: {
1013 const uint32_t options(fShmNonRtClientControl.readUInt());
1015 plugin->pData->options = options;
1016 break;
1019 case kPluginBridgeNonRtClientSetWindowTitle: {
1020 const BridgeTextReader title(fShmNonRtClientControl);
1022 plugin->setCustomUITitle(title.text);
1023 break;
1026 case kPluginBridgeNonRtClientGetParameterText: {
1027 const int32_t index = fShmNonRtClientControl.readInt();
1029 if (index >= 0 && plugin->isEnabled())
1031 char bufStr[STR_MAX+1];
1032 carla_zeroChars(bufStr, STR_MAX+1);
1033 if (! plugin->getParameterText(static_cast<uint32_t>(index), bufStr))
1034 bufStr[0] = '\0';
1036 const uint32_t bufStrLen = static_cast<uint32_t>(std::strlen(bufStr));
1038 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1040 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSetParameterText);
1042 fShmNonRtServerControl.writeInt(index);
1043 fShmNonRtServerControl.writeUInt(bufStrLen);
1044 fShmNonRtServerControl.writeCustomData(bufStr, bufStrLen);
1045 fShmNonRtServerControl.commitWrite();
1047 fShmNonRtServerControl.waitIfDataIsReachingLimit();
1049 else
1051 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1053 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSetParameterText);
1054 fShmNonRtServerControl.writeInt(index);
1055 fShmNonRtServerControl.writeUInt(0);
1056 fShmNonRtServerControl.commitWrite();
1059 break;
1062 case kPluginBridgeNonRtClientPrepareForSave: {
1063 if (! plugin->isEnabled())
1065 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1066 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSaved);
1067 fShmNonRtServerControl.commitWrite();
1068 return;
1071 plugin->prepareForSave(false);
1073 const uint32_t maxLocalValueLen = fBridgeVersion >= 10 ? 4096 : 16384;
1075 for (uint32_t i=0, count=plugin->getCustomDataCount(); i<count; ++i)
1077 const CustomData& cdata(plugin->getCustomData(i));
1079 if (std::strcmp(cdata.type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
1080 continue;
1082 const uint32_t typeLen = static_cast<uint32_t>(std::strlen(cdata.type));
1083 const uint32_t keyLen = static_cast<uint32_t>(std::strlen(cdata.key));
1084 const uint32_t valueLen = static_cast<uint32_t>(std::strlen(cdata.value));
1087 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1089 if (valueLen > maxLocalValueLen)
1090 fShmNonRtServerControl.waitIfDataIsReachingLimit();
1092 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSetCustomData);
1094 fShmNonRtServerControl.writeUInt(typeLen);
1095 fShmNonRtServerControl.writeCustomData(cdata.type, typeLen);
1097 fShmNonRtServerControl.writeUInt(keyLen);
1098 fShmNonRtServerControl.writeCustomData(cdata.key, keyLen);
1100 fShmNonRtServerControl.writeUInt(valueLen);
1102 if (valueLen > 0)
1104 if (valueLen > maxLocalValueLen)
1106 String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
1108 filePath += CARLA_OS_SEP_STR ".CarlaCustomData_";
1109 filePath += fShmAudioPool.getFilenameSuffix();
1111 if (File(filePath.toRawUTF8()).replaceWithText(cdata.value))
1113 const uint32_t ulength(static_cast<uint32_t>(filePath.length()));
1115 fShmNonRtServerControl.writeUInt(ulength);
1116 fShmNonRtServerControl.writeCustomData(filePath.toRawUTF8(), ulength);
1118 else
1120 fShmNonRtServerControl.writeUInt(0);
1123 else
1125 fShmNonRtServerControl.writeCustomData(cdata.value, valueLen);
1129 fShmNonRtServerControl.commitWrite();
1130 fShmNonRtServerControl.waitIfDataIsReachingLimit();
1134 if (plugin->getOptionsEnabled() & PLUGIN_OPTION_USE_CHUNKS)
1136 void* data = nullptr;
1137 if (const std::size_t dataSize = plugin->getChunkData(&data))
1139 CARLA_SAFE_ASSERT_BREAK(data != nullptr);
1141 CarlaString dataBase64 = CarlaString::asBase64(data, dataSize);
1142 CARLA_SAFE_ASSERT_BREAK(dataBase64.length() > 0);
1144 String filePath(File::getSpecialLocation(File::tempDirectory).getFullPathName());
1146 filePath += CARLA_OS_SEP_STR ".CarlaChunk_";
1147 filePath += fShmAudioPool.getFilenameSuffix();
1149 if (File(filePath.toRawUTF8()).replaceWithText(dataBase64.buffer()))
1151 const uint32_t ulength(static_cast<uint32_t>(filePath.length()));
1153 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1155 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSetChunkDataFile);
1156 fShmNonRtServerControl.writeUInt(ulength);
1157 fShmNonRtServerControl.writeCustomData(filePath.toRawUTF8(), ulength);
1158 fShmNonRtServerControl.commitWrite();
1164 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1166 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSaved);
1167 fShmNonRtServerControl.commitWrite();
1169 break;
1172 case kPluginBridgeNonRtClientRestoreLV2State:
1173 if (plugin->isEnabled())
1174 plugin->restoreLV2State(false);
1175 break;
1177 case kPluginBridgeNonRtClientShowUI:
1178 if (plugin->isEnabled())
1179 plugin->showCustomUI(true);
1180 break;
1182 case kPluginBridgeNonRtClientHideUI:
1183 if (plugin->isEnabled())
1184 plugin->showCustomUI(false);
1185 break;
1187 case kPluginBridgeNonRtClientEmbedUI: {
1188 const uint64_t winId = fShmNonRtClientControl.readULong();
1189 uint64_t resp = 0;
1191 if (plugin->isEnabled())
1192 resp = reinterpret_cast<uint64_t>(plugin->embedCustomUI(reinterpret_cast<void*>(winId)));
1194 if (resp == 0)
1195 resp = 1;
1197 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1199 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerRespEmbedUI);
1200 fShmNonRtServerControl.writeULong(resp);
1201 fShmNonRtServerControl.commitWrite();
1202 break;
1205 case kPluginBridgeNonRtClientUiParameterChange: {
1206 const uint32_t index = fShmNonRtClientControl.readUInt();
1207 const float value = fShmNonRtClientControl.readFloat();
1209 if (plugin->isEnabled())
1210 plugin->uiParameterChange(index, value);
1211 break;
1214 case kPluginBridgeNonRtClientUiProgramChange: {
1215 const uint32_t index(fShmNonRtClientControl.readUInt());
1217 if (plugin->isEnabled())
1218 plugin->uiProgramChange(index);
1219 break;
1222 case kPluginBridgeNonRtClientUiMidiProgramChange: {
1223 const uint32_t index(fShmNonRtClientControl.readUInt());
1225 if (plugin->isEnabled())
1226 plugin->uiMidiProgramChange(index);
1227 break;
1230 case kPluginBridgeNonRtClientUiNoteOn: {
1231 const uint8_t chnl(fShmNonRtClientControl.readByte());
1232 const uint8_t note(fShmNonRtClientControl.readByte());
1233 const uint8_t velo(fShmNonRtClientControl.readByte());
1235 if (plugin->isEnabled())
1236 plugin->uiNoteOn(chnl, note, velo);
1237 break;
1240 case kPluginBridgeNonRtClientUiNoteOff: {
1241 const uint8_t chnl(fShmNonRtClientControl.readByte());
1242 const uint8_t note(fShmNonRtClientControl.readByte());
1244 if (plugin->isEnabled())
1245 plugin->uiNoteOff(chnl, note);
1246 break;
1249 case kPluginBridgeNonRtClientQuit:
1250 fClosingDown = true;
1251 signalThreadShouldExit();
1252 callback(true, true, ENGINE_CALLBACK_QUIT, 0, 0, 0, 0, 0.0f, nullptr);
1253 break;
1255 case kPluginBridgeNonRtClientReload:
1256 fFirstIdle = true;
1257 break;
1262 // -------------------------------------------------------------------
1264 protected:
1265 void run() override
1267 #ifdef __SSE2_MATH__
1268 // Set FTZ and DAZ flags
1269 _mm_setcsr(_mm_getcsr() | 0x8040);
1270 #endif
1272 bool quitReceived = false;
1274 for (; ! shouldThreadExit();)
1276 const BridgeRtClientControl::WaitHelper helper(fShmRtClientControl);
1278 if (! helper.ok)
1279 continue;
1281 for (; fShmRtClientControl.isDataAvailableForReading();)
1283 const PluginBridgeRtClientOpcode opcode(fShmRtClientControl.readOpcode());
1284 const CarlaPluginPtr plugin = pData->plugins[0].plugin;
1286 #ifdef DEBUG
1287 if (opcode != kPluginBridgeRtClientProcess && opcode != kPluginBridgeRtClientMidiEvent) {
1288 carla_debug("CarlaEngineBridgeRtThread::run() - got opcode: %s", PluginBridgeRtClientOpcode2str(opcode));
1290 #endif
1292 switch (opcode)
1294 case kPluginBridgeRtClientNull:
1295 break;
1297 case kPluginBridgeRtClientSetAudioPool: {
1298 if (fShmAudioPool.data != nullptr)
1300 jackbridge_shm_unmap(fShmAudioPool.shm, fShmAudioPool.data);
1301 fShmAudioPool.data = nullptr;
1303 const uint64_t poolSize(fShmRtClientControl.readULong());
1304 CARLA_SAFE_ASSERT_BREAK(poolSize > 0);
1305 fShmAudioPool.data = (float*)jackbridge_shm_map(fShmAudioPool.shm, static_cast<size_t>(poolSize));
1306 break;
1309 case kPluginBridgeRtClientSetBufferSize: {
1310 const uint32_t bufferSize(fShmRtClientControl.readUInt());
1311 pData->bufferSize = bufferSize;
1312 bufferSizeChanged(bufferSize);
1313 break;
1316 case kPluginBridgeRtClientSetSampleRate: {
1317 const double sampleRate(fShmRtClientControl.readDouble());
1318 pData->sampleRate = sampleRate;
1319 sampleRateChanged(sampleRate);
1320 break;
1323 case kPluginBridgeRtClientSetOnline:
1324 fIsOffline = fShmRtClientControl.readBool();
1325 offlineModeChanged(fIsOffline);
1326 break;
1328 // NOTE this is never used
1329 case kPluginBridgeRtClientControlEventParameter: {
1330 const uint32_t time(fShmRtClientControl.readUInt());
1331 const uint8_t channel(fShmRtClientControl.readByte());
1332 const uint16_t param(fShmRtClientControl.readUShort());
1333 const float value(fShmRtClientControl.readFloat());
1335 if (EngineEvent* const event = getNextFreeInputEvent())
1337 event->type = kEngineEventTypeControl;
1338 event->time = time;
1339 event->channel = channel;
1340 event->ctrl.type = kEngineControlEventTypeParameter;
1341 event->ctrl.param = param;
1342 event->ctrl.midiValue = -1;
1343 event->ctrl.normalizedValue = value;
1344 event->ctrl.handled = true;
1346 break;
1349 case kPluginBridgeRtClientControlEventMidiBank: {
1350 const uint32_t time(fShmRtClientControl.readUInt());
1351 const uint8_t channel(fShmRtClientControl.readByte());
1352 const uint16_t index(fShmRtClientControl.readUShort());
1354 if (EngineEvent* const event = getNextFreeInputEvent())
1356 event->type = kEngineEventTypeControl;
1357 event->time = time;
1358 event->channel = channel;
1359 event->ctrl.type = kEngineControlEventTypeMidiBank;
1360 event->ctrl.param = index;
1361 event->ctrl.midiValue = -1;
1362 event->ctrl.normalizedValue = 0.0f;
1363 event->ctrl.handled = true;
1365 break;
1368 case kPluginBridgeRtClientControlEventMidiProgram: {
1369 const uint32_t time(fShmRtClientControl.readUInt());
1370 const uint8_t channel(fShmRtClientControl.readByte());
1371 const uint16_t index(fShmRtClientControl.readUShort());
1373 if (EngineEvent* const event = getNextFreeInputEvent())
1375 event->type = kEngineEventTypeControl;
1376 event->time = time;
1377 event->channel = channel;
1378 event->ctrl.type = kEngineControlEventTypeMidiProgram;
1379 event->ctrl.param = index;
1380 event->ctrl.midiValue = -1;
1381 event->ctrl.normalizedValue = 0.0f;
1382 event->ctrl.handled = true;
1384 break;
1387 case kPluginBridgeRtClientControlEventAllSoundOff: {
1388 const uint32_t time(fShmRtClientControl.readUInt());
1389 const uint8_t channel(fShmRtClientControl.readByte());
1391 if (EngineEvent* const event = getNextFreeInputEvent())
1393 event->type = kEngineEventTypeControl;
1394 event->time = time;
1395 event->channel = channel;
1396 event->ctrl.type = kEngineControlEventTypeAllSoundOff;
1397 event->ctrl.param = 0;
1398 event->ctrl.midiValue = -1;
1399 event->ctrl.normalizedValue = 0.0f;
1400 event->ctrl.handled = true;
1402 } break;
1404 case kPluginBridgeRtClientControlEventAllNotesOff: {
1405 const uint32_t time(fShmRtClientControl.readUInt());
1406 const uint8_t channel(fShmRtClientControl.readByte());
1408 if (EngineEvent* const event = getNextFreeInputEvent())
1410 event->type = kEngineEventTypeControl;
1411 event->time = time;
1412 event->channel = channel;
1413 event->ctrl.type = kEngineControlEventTypeAllNotesOff;
1414 event->ctrl.param = 0;
1415 event->ctrl.midiValue = -1;
1416 event->ctrl.normalizedValue = 0.0f;
1417 event->ctrl.handled = true;
1419 } break;
1421 case kPluginBridgeRtClientMidiEvent: {
1422 const uint32_t time(fShmRtClientControl.readUInt());
1423 const uint8_t port(fShmRtClientControl.readByte());
1424 const uint8_t size(fShmRtClientControl.readByte());
1425 CARLA_SAFE_ASSERT_BREAK(size > 0);
1427 // FIXME variable-size stack
1428 uint8_t data[4];
1431 uint8_t i=0;
1432 for (; i<size && i<4; ++i)
1433 data[i] = fShmRtClientControl.readByte();
1434 for (; i<size; ++i)
1435 fShmRtClientControl.readByte();
1438 if (size > 4)
1439 continue;
1441 if (EngineEvent* const event = getNextFreeInputEvent())
1443 event->type = kEngineEventTypeMidi;
1444 event->time = time;
1445 event->channel = MIDI_GET_CHANNEL_FROM_DATA(data);
1447 event->midi.port = port;
1448 event->midi.size = size;
1450 if (size > EngineMidiEvent::kDataSize)
1452 event->midi.dataExt = data;
1453 std::memset(event->midi.data, 0, sizeof(uint8_t)*EngineMidiEvent::kDataSize);
1455 else
1457 event->midi.data[0] = MIDI_GET_STATUS_FROM_DATA(data);
1459 uint8_t i=1;
1460 for (; i < size; ++i)
1461 event->midi.data[i] = data[i];
1462 for (; i < EngineMidiEvent::kDataSize; ++i)
1463 event->midi.data[i] = 0;
1465 event->midi.dataExt = nullptr;
1468 break;
1471 case kPluginBridgeRtClientProcess: {
1472 const uint32_t frames(fShmRtClientControl.readUInt());
1474 CARLA_SAFE_ASSERT_BREAK(fShmAudioPool.data != nullptr);
1476 if (plugin.get() != nullptr && plugin->isEnabled() && plugin->tryLock(fIsOffline))
1478 const BridgeTimeInfo& bridgeTimeInfo(fShmRtClientControl.data->timeInfo);
1480 const uint32_t audioInCount = plugin->getAudioInCount();
1481 const uint32_t audioOutCount = plugin->getAudioOutCount();
1482 const uint32_t cvInCount = plugin->getCVInCount();
1483 const uint32_t cvOutCount = plugin->getCVOutCount();
1485 const float* audioIn[64];
1486 /* */ float* audioOut[64];
1487 const float* cvIn[32];
1488 /* */ float* cvOut[32];
1490 float* fdata = fShmAudioPool.data;
1492 for (uint32_t i=0; i < audioInCount; ++i, fdata += pData->bufferSize)
1493 audioIn[i] = fdata;
1494 for (uint32_t i=0; i < audioOutCount; ++i, fdata += pData->bufferSize)
1495 audioOut[i] = fdata;
1497 for (uint32_t i=0; i < cvInCount; ++i, fdata += pData->bufferSize)
1498 cvIn[i] = fdata;
1499 for (uint32_t i=0; i < cvOutCount; ++i, fdata += pData->bufferSize)
1500 cvOut[i] = fdata;
1502 EngineTimeInfo& timeInfo(pData->timeInfo);
1504 timeInfo.playing = bridgeTimeInfo.playing;
1505 timeInfo.frame = bridgeTimeInfo.frame;
1506 timeInfo.usecs = bridgeTimeInfo.usecs;
1507 timeInfo.bbt.valid = (bridgeTimeInfo.validFlags & kPluginBridgeTimeInfoValidBBT) != 0;
1509 if (timeInfo.bbt.valid)
1511 timeInfo.bbt.bar = bridgeTimeInfo.bar;
1512 timeInfo.bbt.beat = bridgeTimeInfo.beat;
1513 timeInfo.bbt.tick = bridgeTimeInfo.tick;
1515 timeInfo.bbt.beatsPerBar = bridgeTimeInfo.beatsPerBar;
1516 timeInfo.bbt.beatType = bridgeTimeInfo.beatType;
1518 timeInfo.bbt.ticksPerBeat = bridgeTimeInfo.ticksPerBeat;
1519 timeInfo.bbt.beatsPerMinute = bridgeTimeInfo.beatsPerMinute;
1520 timeInfo.bbt.barStartTick = bridgeTimeInfo.barStartTick;
1523 plugin->initBuffers();
1524 plugin->process(audioIn, audioOut, cvIn, cvOut, frames);
1525 plugin->unlock();
1528 uint8_t* midiData(fShmRtClientControl.data->midiOut);
1529 carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize);
1530 std::size_t curMidiDataPos = 0;
1532 if (pData->events.in[0].type != kEngineEventTypeNull)
1533 carla_zeroStructs(pData->events.in, kMaxEngineEventInternalCount);
1535 if (pData->events.out[0].type != kEngineEventTypeNull)
1537 for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
1539 const EngineEvent& event(pData->events.out[i]);
1541 if (event.type == kEngineEventTypeNull)
1542 break;
1544 if (event.type == kEngineEventTypeControl)
1546 uint8_t data[3];
1547 const uint8_t size = event.ctrl.convertToMidiData(event.channel, data);
1548 CARLA_SAFE_ASSERT_CONTINUE(size > 0 && size <= 3);
1550 if (curMidiDataPos + kBridgeBaseMidiOutHeaderSize + size >= kBridgeRtClientDataMidiOutSize)
1551 break;
1553 // set time
1554 *(uint32_t*)midiData = event.time;
1555 midiData = midiData + 4;
1556 curMidiDataPos += 4;
1558 // set port
1559 *midiData++ = 0;
1560 ++curMidiDataPos;
1562 // set size
1563 *midiData++ = size;
1564 ++curMidiDataPos;
1566 // set data
1567 for (uint8_t j=0; j<size; ++j)
1568 *midiData++ = data[j];
1570 curMidiDataPos += size;
1572 else if (event.type == kEngineEventTypeMidi)
1574 const EngineMidiEvent& _midiEvent(event.midi);
1576 if (curMidiDataPos + kBridgeBaseMidiOutHeaderSize + _midiEvent.size >= kBridgeRtClientDataMidiOutSize)
1577 break;
1579 const uint8_t* const _midiData(_midiEvent.dataExt != nullptr ? _midiEvent.dataExt : _midiEvent.data);
1581 // set time
1582 *(uint32_t*)midiData = event.time;
1583 midiData += 4;
1584 curMidiDataPos += 4;
1586 // set port
1587 *midiData++ = _midiEvent.port;
1588 ++curMidiDataPos;
1590 // set size
1591 *midiData++ = _midiEvent.size;
1592 ++curMidiDataPos;
1594 // set data
1595 *midiData++ = uint8_t(_midiData[0] | (event.channel & MIDI_CHANNEL_BIT));
1597 for (uint8_t j=1; j<_midiEvent.size; ++j)
1598 *midiData++ = _midiData[j];
1600 curMidiDataPos += _midiEvent.size;
1604 if (curMidiDataPos != 0 &&
1605 curMidiDataPos + kBridgeBaseMidiOutHeaderSize < kBridgeRtClientDataMidiOutSize)
1606 carla_zeroBytes(midiData, kBridgeBaseMidiOutHeaderSize);
1608 carla_zeroStructs(pData->events.out, kMaxEngineEventInternalCount);
1611 } break;
1613 case kPluginBridgeRtClientQuit: {
1614 quitReceived = true;
1615 fClosingDown = true;
1616 signalThreadShouldExit();
1617 } break;
1622 callback(true, true, ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0, 0.0f, nullptr);
1624 if (! quitReceived)
1626 const char* const message("Plugin bridge error, process thread has stopped");
1627 const std::size_t messageSize(std::strlen(message));
1629 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1630 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerError);
1631 fShmNonRtServerControl.writeUInt(messageSize);
1632 fShmNonRtServerControl.writeCustomData(message, messageSize);
1633 fShmNonRtServerControl.commitWrite();
1637 // called from process thread above
1638 EngineEvent* getNextFreeInputEvent() const noexcept
1640 for (ushort i=0; i < kMaxEngineEventInternalCount; ++i)
1642 EngineEvent* const event(&pData->events.in[i]);
1644 if (event->type == kEngineEventTypeNull)
1645 return event;
1647 return nullptr;
1650 void latencyChanged(const uint32_t samples) noexcept override
1652 const CarlaMutexLocker _cml(fShmNonRtServerControl.mutex);
1654 fShmNonRtServerControl.writeOpcode(kPluginBridgeNonRtServerSetLatency);
1655 fShmNonRtServerControl.writeUInt(samples);
1656 fShmNonRtServerControl.commitWrite();
1659 // -------------------------------------------------------------------
1661 private:
1662 BridgeAudioPool fShmAudioPool;
1663 BridgeRtClientControl fShmRtClientControl;
1664 BridgeNonRtClientControl fShmNonRtClientControl;
1665 BridgeNonRtServerControl fShmNonRtServerControl;
1667 CarlaString fBaseNameAudioPool;
1668 CarlaString fBaseNameRtClientControl;
1669 CarlaString fBaseNameNonRtClientControl;
1670 CarlaString fBaseNameNonRtServerControl;
1672 bool fClosingDown;
1673 bool fIsOffline;
1674 bool fFirstIdle;
1675 uint32_t fBridgeVersion;
1676 uint32_t fLastPingTime;
1678 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaEngineBridge)
1681 // -----------------------------------------------------------------------
1683 namespace EngineInit {
1685 CarlaEngine* newBridge(const char* const audioPoolBaseName,
1686 const char* const rtClientBaseName,
1687 const char* const nonRtClientBaseName,
1688 const char* const nonRtServerBaseName)
1690 return new CarlaEngineBridge(audioPoolBaseName, rtClientBaseName, nonRtClientBaseName, nonRtServerBaseName);
1695 // -----------------------------------------------------------------------
1697 CARLA_BACKEND_END_NAMESPACE
1699 // -----------------------------------------------------------------------
1701 #include "CarlaBridgeUtils.cpp"
1703 // -----------------------------------------------------------------------