1
// SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
5 # error This file should not be compiled if not building bridge
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"
25 # include <xmmintrin.h>
28 #include "water/files/File.h"
29 #include "water/misc/Time.h"
32 #include "jackbridge/JackBridge.hpp"
35 using water::MemoryBlock
;
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
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
) {}
59 CarlaEngineBridgeClient(const CarlaEngine
& engine
, LatencyChangedCallback
* const cb
)
60 : CarlaEngineClientForSubclassing(engine
),
61 fLatencyCallback(cb
) {}
65 void setLatency(const uint32_t samples
) noexcept override
67 if (getLatency() == samples
)
70 fLatencyCallback
->latencyChanged(samples
);
71 CarlaEngineClient::setLatency(samples
);
75 LatencyChangedCallback
* const fLatencyCallback
;
77 CARLA_DECLARE_NON_COPYABLE(CarlaEngineBridgeClient
)
80 // -------------------------------------------------------------------
82 struct BridgeTextReader
{
85 BridgeTextReader(BridgeNonRtClientControl
& nonRtClientCtrl
)
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
);
96 BridgeTextReader(BridgeNonRtClientControl
& nonRtClientCtrl
, const uint32_t size
)
99 text
= new char[size
+ 1];
102 nonRtClientCtrl
.readCustomData(text
, size
);
107 ~BridgeTextReader() noexcept
112 CARLA_DECLARE_NON_COPYABLE(BridgeTextReader
)
115 // -------------------------------------------------------------------
117 class CarlaEngineBridge
: public CarlaEngine
,
119 private LatencyChangedCallback
122 CarlaEngineBridge(const char* const audioPoolBaseName
, const char* const rtClientBaseName
, const char* const nonRtClientBaseName
, const char* const nonRtServerBaseName
)
124 CarlaThread("CarlaEngineBridge"),
126 fShmRtClientControl(),
127 fShmNonRtClientControl(),
128 fShmNonRtServerControl(),
129 fBaseNameAudioPool(audioPoolBaseName
),
130 fBaseNameRtClientControl(rtClientBaseName
),
131 fBaseNameNonRtClientControl(nonRtClientBaseName
),
132 fBaseNameNonRtServerControl(nonRtServerBaseName
),
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()");
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");
162 if (! fShmAudioPool
.attachClient(fBaseNameAudioPool
))
165 setLastError("Failed to attach to audio pool shared memory");
169 if (! fShmRtClientControl
.attachClient(fBaseNameRtClientControl
))
173 setLastError("Failed to attach to rt client control shared memory");
177 if (! fShmRtClientControl
.mapData())
181 setLastError("Failed to map rt client control shared memory");
185 if (! fShmNonRtClientControl
.attachClient(fBaseNameNonRtClientControl
))
189 setLastError("Failed to attach to non-rt client control shared memory");
193 if (! fShmNonRtClientControl
.mapData())
197 setLastError("Failed to map non-rt control client shared memory");
201 if (! fShmNonRtServerControl
.attachClient(fBaseNameNonRtServerControl
))
205 setLastError("Failed to attach to non-rt server control shared memory");
209 if (! fShmNonRtServerControl
.mapData())
213 setLastError("Failed to map non-rt control server shared memory");
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
))
240 setLastError("Shared memory data size mismatch");
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
))
254 setLastError("Shared memory has invalid data");
258 pData
->initTime(nullptr);
260 // tell backend we're live
262 const CarlaMutexLocker
_cml(fShmNonRtServerControl
.mutex
);
264 // kPluginBridgeNonRtServerVersion was added in API 7
267 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerVersion
);
268 fShmNonRtServerControl
.writeUInt(CARLA_PLUGIN_BRIDGE_API_VERSION_CURRENT
);
272 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerPong
);
275 fShmNonRtServerControl
.commitWrite();
282 bool close() override
284 carla_debug("CarlaEngineBridge::close()");
285 fLastPingTime
= UINT32_MAX
;
287 CarlaEngine::close();
295 bool hasIdleOnMainThread() const noexcept override
300 bool isRunning() const noexcept override
305 return isThreadRunning() || ! fFirstIdle
;
308 bool isOffline() const noexcept override
313 EngineType
getType() const noexcept override
315 return kEngineTypeBridge
;
318 const char* getCurrentDriverName() const noexcept override
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);
339 return new CarlaEngineBridgeClient(*this, this);
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);
366 const bool wasFirstIdle
= fFirstIdle
;
371 fLastPingTime
= carla_gettime_ms();
373 char bufStr
[STR_MAX
+1];
374 carla_zeroChars(bufStr
, STR_MAX
+1);
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
))
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
))
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
))
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
))
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())
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
)
509 if ((paramData
.hints
& PARAMETER_IS_ENABLED
) == 0)
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
))
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
))
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())
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
))
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())
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();
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
))
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())
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
)
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();
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();
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();
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();
733 case ENGINE_CALLBACK_UI_STATE_CHANGED
:
736 const CarlaMutexLocker
_cml(fShmNonRtServerControl
.mutex
);
737 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerUiClosed
);
738 fShmNonRtServerControl
.commitWrite();
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();
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
)
767 if ((paramData
.hints
& PARAMETER_IS_ENABLED
) == 0)
770 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerParameterValue
);
771 fShmNonRtServerControl
.writeUInt(i
);
772 fShmNonRtServerControl
.writeFloat(plugin
->getParameterValue(i
));
773 fShmNonRtServerControl
.commitWrite();
775 fShmNonRtServerControl
.waitIfDataIsReachingLimit();
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();
806 if (opcode
!= kPluginBridgeNonRtClientPing
) {
807 carla_debug("CarlaEngineBridge::handleNonRtData() - got opcode: %i:%s",
808 opcode
, PluginBridgeNonRtClientOpcode2str(opcode
));
812 if (opcode
!= kPluginBridgeNonRtClientNull
&&
813 opcode
!= kPluginBridgeNonRtClientPingOnOff
&& fLastPingTime
!= UINT32_MAX
)
814 fLastPingTime
= carla_gettime_ms();
818 case kPluginBridgeNonRtClientNull
:
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
);
827 case kPluginBridgeNonRtClientPing
: {
828 const CarlaMutexLocker
_cml(fShmNonRtServerControl
.mutex
);
830 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerPong
);
831 fShmNonRtServerControl
.commitWrite();
834 case kPluginBridgeNonRtClientPingOnOff
:
835 fLastPingTime
= fShmNonRtClientControl
.readBool() ? carla_gettime_ms() : UINT32_MAX
;
838 case kPluginBridgeNonRtClientActivate
:
839 if (plugin
->isEnabled())
840 plugin
->setActive(true, false, false);
843 case kPluginBridgeNonRtClientDeactivate
:
844 if (plugin
->isEnabled())
845 plugin
->setActive(false, false, false);
848 case kPluginBridgeNonRtClientInitialSetup
:
849 // should never happen!!
850 fShmNonRtServerControl
.readUInt();
851 fShmNonRtServerControl
.readDouble();
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);
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);
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);
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);
891 case kPluginBridgeNonRtClientSetProgram
: {
892 const int32_t index(fShmNonRtClientControl
.readInt());
894 if (plugin
->isEnabled())
895 plugin
->setProgram(index
, true, false, false);
899 case kPluginBridgeNonRtClientSetMidiProgram
: {
900 const int32_t index(fShmNonRtClientControl
.readInt());
902 if (plugin
->isEnabled())
903 plugin
->setMidiProgram(index
, true, false, false);
907 case kPluginBridgeNonRtClientSetCustomData
: {
908 const uint32_t maxLocalValueLen
= fBridgeVersion
>= 10 ? 4096 : 16384;
911 const BridgeTextReader
type(fShmNonRtClientControl
);
914 const BridgeTextReader
key(fShmNonRtClientControl
);
917 const uint32_t valueSize
= fShmNonRtClientControl
.readUInt();
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
);
931 // check if running under Wine
932 if (bigValueFilePath
.startsWith("/"))
933 bigValueFilePath
= bigValueFilePath
.replaceSection(0, 1, "Z:\\").replace("/", "\\");
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();
945 const BridgeTextReader
value(fShmNonRtClientControl
, valueSize
);
947 if (plugin
->isEnabled())
948 plugin
->setCustomData(type
.text
, key
.text
, value
.text
, true);
953 if (plugin
->isEnabled())
954 plugin
->setCustomData(type
.text
, key
.text
, "", true);
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
);
972 // check if running under Wine
973 if (chunkFilePath
.startsWith("/"))
974 chunkFilePath
= chunkFilePath
.replaceSection(0, 1, "Z:\\").replace("/", "\\");
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());
989 plugin
->setChunkData(&chunk
.front(), chunk
.size());
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);
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);
1012 case kPluginBridgeNonRtClientSetOptions
: {
1013 const uint32_t options(fShmNonRtClientControl
.readUInt());
1015 plugin
->pData
->options
= options
;
1019 case kPluginBridgeNonRtClientSetWindowTitle
: {
1020 const BridgeTextReader
title(fShmNonRtClientControl
);
1022 plugin
->setCustomUITitle(title
.text
);
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
))
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();
1051 const CarlaMutexLocker
_cml(fShmNonRtServerControl
.mutex
);
1053 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerSetParameterText
);
1054 fShmNonRtServerControl
.writeInt(index
);
1055 fShmNonRtServerControl
.writeUInt(0);
1056 fShmNonRtServerControl
.commitWrite();
1062 case kPluginBridgeNonRtClientPrepareForSave
: {
1063 if (! plugin
->isEnabled())
1065 const CarlaMutexLocker
_cml(fShmNonRtServerControl
.mutex
);
1066 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerSaved
);
1067 fShmNonRtServerControl
.commitWrite();
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)
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
);
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
);
1120 fShmNonRtServerControl
.writeUInt(0);
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();
1172 case kPluginBridgeNonRtClientRestoreLV2State
:
1173 if (plugin
->isEnabled())
1174 plugin
->restoreLV2State(false);
1177 case kPluginBridgeNonRtClientShowUI
:
1178 if (plugin
->isEnabled())
1179 plugin
->showCustomUI(true);
1182 case kPluginBridgeNonRtClientHideUI
:
1183 if (plugin
->isEnabled())
1184 plugin
->showCustomUI(false);
1187 case kPluginBridgeNonRtClientEmbedUI
: {
1188 const uint64_t winId
= fShmNonRtClientControl
.readULong();
1191 if (plugin
->isEnabled())
1192 resp
= reinterpret_cast<uint64_t>(plugin
->embedCustomUI(reinterpret_cast<void*>(winId
)));
1197 const CarlaMutexLocker
_cml(fShmNonRtServerControl
.mutex
);
1199 fShmNonRtServerControl
.writeOpcode(kPluginBridgeNonRtServerRespEmbedUI
);
1200 fShmNonRtServerControl
.writeULong(resp
);
1201 fShmNonRtServerControl
.commitWrite();
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
);
1214 case kPluginBridgeNonRtClientUiProgramChange
: {
1215 const uint32_t index(fShmNonRtClientControl
.readUInt());
1217 if (plugin
->isEnabled())
1218 plugin
->uiProgramChange(index
);
1222 case kPluginBridgeNonRtClientUiMidiProgramChange
: {
1223 const uint32_t index(fShmNonRtClientControl
.readUInt());
1225 if (plugin
->isEnabled())
1226 plugin
->uiMidiProgramChange(index
);
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
);
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
);
1249 case kPluginBridgeNonRtClientQuit
:
1250 fClosingDown
= true;
1251 signalThreadShouldExit();
1252 callback(true, true, ENGINE_CALLBACK_QUIT
, 0, 0, 0, 0, 0.0f
, nullptr);
1255 case kPluginBridgeNonRtClientReload
:
1262 // -------------------------------------------------------------------
1267 #ifdef __SSE2_MATH__
1268 // Set FTZ and DAZ flags
1269 _mm_setcsr(_mm_getcsr() | 0x8040);
1272 bool quitReceived
= false;
1274 for (; ! shouldThreadExit();)
1276 const BridgeRtClientControl::WaitHelper
helper(fShmRtClientControl
);
1281 for (; fShmRtClientControl
.isDataAvailableForReading();)
1283 const PluginBridgeRtClientOpcode
opcode(fShmRtClientControl
.readOpcode());
1284 const CarlaPluginPtr plugin
= pData
->plugins
[0].plugin
;
1287 if (opcode
!= kPluginBridgeRtClientProcess
&& opcode
!= kPluginBridgeRtClientMidiEvent
) {
1288 carla_debug("CarlaEngineBridgeRtThread::run() - got opcode: %s", PluginBridgeRtClientOpcode2str(opcode
));
1294 case kPluginBridgeRtClientNull
:
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
));
1309 case kPluginBridgeRtClientSetBufferSize
: {
1310 const uint32_t bufferSize(fShmRtClientControl
.readUInt());
1311 pData
->bufferSize
= bufferSize
;
1312 bufferSizeChanged(bufferSize
);
1316 case kPluginBridgeRtClientSetSampleRate
: {
1317 const double sampleRate(fShmRtClientControl
.readDouble());
1318 pData
->sampleRate
= sampleRate
;
1319 sampleRateChanged(sampleRate
);
1323 case kPluginBridgeRtClientSetOnline
:
1324 fIsOffline
= fShmRtClientControl
.readBool();
1325 offlineModeChanged(fIsOffline
);
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
;
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;
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
;
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;
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
;
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;
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
;
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;
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
;
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;
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
1432 for (; i
<size
&& i
<4; ++i
)
1433 data
[i
] = fShmRtClientControl
.readByte();
1435 fShmRtClientControl
.readByte();
1441 if (EngineEvent
* const event
= getNextFreeInputEvent())
1443 event
->type
= kEngineEventTypeMidi
;
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
);
1457 event
->midi
.data
[0] = MIDI_GET_STATUS_FROM_DATA(data
);
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;
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
)
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
)
1499 for (uint32_t i
=0; i
< cvOutCount
; ++i
, fdata
+= pData
->bufferSize
)
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
);
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
)
1544 if (event
.type
== kEngineEventTypeControl
)
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
)
1554 *(uint32_t*)midiData
= event
.time
;
1555 midiData
= midiData
+ 4;
1556 curMidiDataPos
+= 4;
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
)
1579 const uint8_t* const _midiData(_midiEvent
.dataExt
!= nullptr ? _midiEvent
.dataExt
: _midiEvent
.data
);
1582 *(uint32_t*)midiData
= event
.time
;
1584 curMidiDataPos
+= 4;
1587 *midiData
++ = _midiEvent
.port
;
1591 *midiData
++ = _midiEvent
.size
;
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
);
1613 case kPluginBridgeRtClientQuit
: {
1614 quitReceived
= true;
1615 fClosingDown
= true;
1616 signalThreadShouldExit();
1622 callback(true, true, ENGINE_CALLBACK_ENGINE_STOPPED
, 0, 0, 0, 0, 0.0f
, nullptr);
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
)
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 // -------------------------------------------------------------------
1662 BridgeAudioPool fShmAudioPool
;
1663 BridgeRtClientControl fShmRtClientControl
;
1664 BridgeNonRtClientControl fShmNonRtClientControl
;
1665 BridgeNonRtServerControl fShmNonRtServerControl
;
1667 CarlaString fBaseNameAudioPool
;
1668 CarlaString fBaseNameRtClientControl
;
1669 CarlaString fBaseNameNonRtClientControl
;
1670 CarlaString fBaseNameNonRtServerControl
;
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 // -----------------------------------------------------------------------