1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
5 * - complete processRack(): carefully add to input, sorted events
6 * - implement processPatchbay()
7 * - implement oscSend_control_switch_plugins()
8 * - something about the peaks?
11 #include "CarlaEngineClient.hpp"
12 #include "CarlaEngineInit.hpp"
13 #include "CarlaEngineInternal.hpp"
14 #include "CarlaPlugin.hpp"
16 #include "CarlaBackendUtils.hpp"
17 #include "CarlaBinaryUtils.hpp"
18 #include "CarlaEngineUtils.hpp"
19 #include "CarlaMathUtils.hpp"
20 #include "CarlaPipeUtils.hpp"
21 #include "CarlaProcessUtils.hpp"
22 #include "CarlaScopeUtils.hpp"
23 #include "CarlaStateUtils.hpp"
24 #include "CarlaMIDI.h"
26 #include "jackbridge/JackBridge.hpp"
28 #include "water/files/File.h"
29 #include "water/streams/MemoryOutputStream.h"
30 #include "water/xml/XmlDocument.h"
31 #include "water/xml/XmlElement.h"
34 # include "CarlaMacUtils.hpp"
35 # if defined(CARLA_OS_64BIT) && defined(HAVE_LIBMAGIC) && ! defined(BUILD_BRIDGE_ALTERNATIVE_ARCH)
36 # define ADAPT_FOR_APPLE_SILLICON
42 // FIXME Remove on 2.1 release
46 using water::CharPointer_UTF8
;
48 using water::MemoryOutputStream
;
50 using water::StringArray
;
51 using water::XmlDocument
;
52 using water::XmlElement
;
54 // #define SFZ_FILES_USING_SFIZZ
56 CARLA_BACKEND_START_NAMESPACE
58 // -----------------------------------------------------------------------
61 CarlaEngine::CarlaEngine()
62 : pData(new ProtectedData(this))
64 carla_debug("CarlaEngine::CarlaEngine()");
67 CarlaEngine::~CarlaEngine()
69 carla_debug("CarlaEngine::~CarlaEngine()");
74 // -----------------------------------------------------------------------
77 uint
CarlaEngine::getDriverCount()
79 carla_debug("CarlaEngine::getDriverCount()");
80 using namespace EngineInit
;
85 if (jackbridge_is_ok())
90 count
+= getRtAudioApiCount();
100 const char* CarlaEngine::getDriverName(const uint index
)
102 carla_debug("CarlaEngine::getDriverName(%u)", index
);
103 using namespace EngineInit
;
108 if (jackbridge_is_ok())
117 if (const uint count
= getRtAudioApiCount())
120 return getRtAudioApiName(index2
);
131 carla_stderr("CarlaEngine::getDriverName(%u) - invalid index %u", index
, index2
);
135 const char* const* CarlaEngine::getDriverDeviceNames(const uint index
)
137 carla_debug("CarlaEngine::getDriverDeviceNames(%u)", index
);
138 using namespace EngineInit
;
143 if (jackbridge_is_ok())
147 static const char* ret
[3] = { "Auto-Connect ON", "Auto-Connect OFF", nullptr };
155 if (const uint count
= getRtAudioApiCount())
158 return getRtAudioApiDeviceNames(index2
);
165 return getSDLDeviceNames();
169 carla_stderr("CarlaEngine::getDriverDeviceNames(%u) - invalid index %u", index
, index2
);
173 const EngineDriverDeviceInfo
* CarlaEngine::getDriverDeviceInfo(const uint index
, const char* const deviceName
)
175 carla_debug("CarlaEngine::getDriverDeviceInfo(%u, \"%s\")", index
, deviceName
);
176 using namespace EngineInit
;
181 if (jackbridge_is_ok())
185 static EngineDriverDeviceInfo devInfo
;
186 devInfo
.hints
= ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE
;
187 devInfo
.bufferSizes
= nullptr;
188 devInfo
.sampleRates
= nullptr;
196 if (const uint count
= getRtAudioApiCount())
199 return getRtAudioDeviceInfo(index2
, deviceName
);
207 static uint32_t sdlBufferSizes
[] = { 512, 1024, 2048, 4096, 8192, 0 };
208 static double sdlSampleRates
[] = { 44100.0, 48000.0, 88200.0, 96000.0, 0.0 };
209 static EngineDriverDeviceInfo devInfo
;
211 devInfo
.bufferSizes
= sdlBufferSizes
;
212 devInfo
.sampleRates
= sdlSampleRates
;
218 carla_stderr("CarlaEngine::getDriverDeviceInfo(%u, \"%s\") - invalid index %u", index
, deviceName
, index2
);
222 bool CarlaEngine::showDriverDeviceControlPanel(const uint index
, const char* const deviceName
)
224 carla_debug("CarlaEngine::showDriverDeviceControlPanel(%u, \"%s\")", index
, deviceName
);
225 using namespace EngineInit
;
230 if (jackbridge_is_ok())
239 if (const uint count
= getRtAudioApiCount())
253 carla_stderr("CarlaEngine::showDriverDeviceControlPanel(%u, \"%s\") - invalid index %u", index
, deviceName
, index2
);
257 CarlaEngine
* CarlaEngine::newDriverByName(const char* const driverName
)
259 CARLA_SAFE_ASSERT_RETURN(driverName
!= nullptr && driverName
[0] != '\0', nullptr);
260 carla_debug("CarlaEngine::newDriverByName(\"%s\")", driverName
);
261 using namespace EngineInit
;
264 if (std::strcmp(driverName
, "JACK") == 0)
268 #if !(defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) || defined(CARLA_OS_WASM) || defined(CARLA_PLUGIN_BUILD) || defined(STATIC_PLUGIN_TARGET))
269 if (std::strcmp(driverName
, "Dummy") == 0)
274 // -------------------------------------------------------------------
277 if (std::strncmp(driverName
, "JACK ", 5) == 0)
278 return newRtAudio(AUDIO_API_JACK
);
279 if (std::strcmp(driverName
, "OSS") == 0)
280 return newRtAudio(AUDIO_API_OSS
);
282 // -------------------------------------------------------------------
285 if (std::strcmp(driverName
, "ALSA") == 0)
286 return newRtAudio(AUDIO_API_ALSA
);
287 if (std::strcmp(driverName
, "PulseAudio") == 0)
288 return newRtAudio(AUDIO_API_PULSEAUDIO
);
290 // -------------------------------------------------------------------
293 if (std::strcmp(driverName
, "CoreAudio") == 0)
294 return newRtAudio(AUDIO_API_COREAUDIO
);
296 // -------------------------------------------------------------------
299 if (std::strcmp(driverName
, "ASIO") == 0)
300 return newRtAudio(AUDIO_API_ASIO
);
301 if (std::strcmp(driverName
, "DirectSound") == 0)
302 return newRtAudio(AUDIO_API_DIRECTSOUND
);
303 if (std::strcmp(driverName
, "WASAPI") == 0)
304 return newRtAudio(AUDIO_API_WASAPI
);
308 if (std::strcmp(driverName
, "SDL") == 0)
312 carla_stderr("CarlaEngine::newDriverByName(\"%s\") - invalid driver name", driverName
);
316 // -----------------------------------------------------------------------
319 uint
CarlaEngine::getMaxClientNameSize() const noexcept
324 uint
CarlaEngine::getMaxPortNameSize() const noexcept
329 uint
CarlaEngine::getCurrentPluginCount() const noexcept
331 return pData
->curPluginCount
;
334 uint
CarlaEngine::getMaxPluginNumber() const noexcept
336 return pData
->maxPluginNumber
;
339 // -----------------------------------------------------------------------
340 // Virtual, per-engine type calls
342 bool CarlaEngine::close()
344 carla_debug("CarlaEngine::close()");
346 if (pData
->curPluginCount
!= 0)
348 pData
->aboutToClose
= true;
354 callback(true, true, ENGINE_CALLBACK_ENGINE_STOPPED
, 0, 0, 0, 0, 0.0f
, nullptr);
358 bool CarlaEngine::usesConstantBufferSize() const noexcept
363 void CarlaEngine::idle() noexcept
365 CARLA_SAFE_ASSERT_RETURN(pData
->nextAction
.opcode
== kEnginePostActionNull
,);
366 CARLA_SAFE_ASSERT_RETURN(pData
->nextPluginId
== pData
->maxPluginNumber
,);
367 CARLA_SAFE_ASSERT_RETURN(getType() != kEngineTypePlugin
,);
369 const bool engineNotRunning
= !isRunning();
370 const bool engineHasIdleOnMainThread
= hasIdleOnMainThread();
372 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
374 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
376 if (plugin
->isEnabled())
378 const uint hints
= plugin
->getHints();
380 if (engineNotRunning
)
384 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin idle");
386 if (hints
& PLUGIN_HAS_CUSTOM_UI
)
390 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin uiIdle");
395 if (engineHasIdleOnMainThread
&& (hints
& PLUGIN_NEEDS_MAIN_THREAD_IDLE
) != 0)
399 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin idle");
402 if ((hints
& PLUGIN_HAS_CUSTOM_UI
) != 0 && (hints
& PLUGIN_NEEDS_UI_MAIN_THREAD
) != 0)
406 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin uiIdle");
413 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
417 pData
->deletePluginsAsNeeded();
420 CarlaEngineClient
* CarlaEngine::addClient(CarlaPluginPtr plugin
)
422 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
423 return new CarlaEngineClientForStandalone(*this, pData
->graph
, plugin
);
425 return new CarlaEngineClientForBridge(*this);
432 float CarlaEngine::getDSPLoad() const noexcept
434 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
435 return pData
->dspLoad
;
441 uint32_t CarlaEngine::getTotalXruns() const noexcept
443 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
450 void CarlaEngine::clearXruns() const noexcept
452 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
457 bool CarlaEngine::showDeviceControlPanel() const noexcept
462 bool CarlaEngine::setBufferSizeAndSampleRate(const uint
, const double)
467 // -----------------------------------------------------------------------
470 bool CarlaEngine::addPlugin(const BinaryType btype
,
471 const PluginType ptype
,
472 const char* const filename
,
473 const char* const name
,
474 const char* const label
,
475 const int64_t uniqueId
,
476 const void* const extra
,
479 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
480 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
481 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
!= nullptr, "Invalid engine internal data");
482 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextPluginId
<= pData
->maxPluginNumber
, "Invalid engine internal data");
484 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
485 CARLA_SAFE_ASSERT_RETURN_ERR(btype
!= BINARY_NONE
, "Invalid plugin binary mode");
486 CARLA_SAFE_ASSERT_RETURN_ERR(ptype
!= PLUGIN_NONE
, "Invalid plugin type");
487 CARLA_SAFE_ASSERT_RETURN_ERR((filename
!= nullptr && filename
[0] != '\0') || (label
!= nullptr && label
[0] != '\0'), "Invalid plugin filename and label");
488 carla_debug("CarlaEngine::addPlugin(%i:%s, %i:%s, \"%s\", \"%s\", \"%s\", " P_INT64
", %p, %u)",
489 btype
, BinaryType2Str(btype
), ptype
, PluginType2Str(ptype
), filename
, name
, label
, uniqueId
, extra
, options
);
492 if (ptype
!= PLUGIN_JACK
&& ptype
!= PLUGIN_LV2
&& filename
!= nullptr && filename
[0] != '\0') {
493 CARLA_SAFE_ASSERT_RETURN_ERR(filename
[0] == CARLA_OS_SEP
|| filename
[0] == '.' || filename
[0] == '~', "Invalid plugin filename");
499 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
500 CarlaPluginPtr oldPlugin
;
502 if (pData
->nextPluginId
< pData
->curPluginCount
)
504 id
= pData
->nextPluginId
;
505 pData
->nextPluginId
= pData
->maxPluginNumber
;
507 oldPlugin
= pData
->plugins
[id
].plugin
;
509 CARLA_SAFE_ASSERT_RETURN_ERR(oldPlugin
.get() != nullptr, "Invalid replace plugin Id");
514 id
= pData
->curPluginCount
;
516 if (id
== pData
->maxPluginNumber
)
518 setLastError("Maximum number of plugins reached");
522 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
523 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
[id
].plugin
.get() == nullptr, "Invalid engine internal data");
527 CarlaPlugin::Initializer initializer
= {
537 CarlaPluginPtr plugin
;
538 CarlaString
bridgeBinary(pData
->options
.binaryDir
);
540 if (bridgeBinary
.isNotEmpty())
543 if (btype
== BINARY_NATIVE
)
545 bridgeBinary
+= CARLA_OS_SEP_STR
"carla-bridge-native";
553 bridgeBinary
+= CARLA_OS_SEP_STR
"carla-bridge-posix32";
556 bridgeBinary
+= CARLA_OS_SEP_STR
"carla-bridge-posix64";
559 #if defined(CARLA_OS_WIN) && !defined(CARLA_OS_64BIT)
560 bridgeBinary
+= CARLA_OS_SEP_STR
"carla-bridge-native.exe";
562 bridgeBinary
+= CARLA_OS_SEP_STR
"carla-bridge-win32.exe";
566 #if defined(CARLA_OS_WIN) && defined(CARLA_OS_64BIT)
567 bridgeBinary
+= CARLA_OS_SEP_STR
"carla-bridge-native.exe";
569 bridgeBinary
+= CARLA_OS_SEP_STR
"carla-bridge-win64.exe";
573 bridgeBinary
.clear();
578 if (! File(bridgeBinary
.buffer()).existsAsFile())
579 bridgeBinary
.clear();
582 const bool canBeBridged
= ptype
!= PLUGIN_INTERNAL
583 && ptype
!= PLUGIN_DLS
584 && ptype
!= PLUGIN_GIG
585 && ptype
!= PLUGIN_SF2
586 && ptype
!= PLUGIN_SFZ
587 && ptype
!= PLUGIN_JSFX
588 && ptype
!= PLUGIN_JACK
;
590 // Prefer bridges for some specific plugins
591 bool preferBridges
= pData
->options
.preferPluginBridges
;
592 const char* needsArchBridge
= nullptr;
595 // Plugin might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
596 if (canBeBridged
&& ptype
!= PLUGIN_LV2
&& ptype
!= PLUGIN_AU
)
597 removeFileFromQuarantine(filename
);
601 if (canBeBridged
&& ! preferBridges
)
604 if (ptype == PLUGIN_LV2 && label != nullptr)
606 if (std::strncmp(label, "http://calf.sourceforge.net/plugins/", 36) == 0 ||
607 std::strcmp(label, "http://factorial.hu/plugins/lv2/ir") == 0 ||
608 std::strstr(label, "v1.sourceforge.net/lv2") != nullptr)
610 preferBridges = true;
614 #ifdef ADAPT_FOR_APPLE_SILLICON
615 // see if this binary needs bridging
616 if (ptype
== PLUGIN_VST2
|| ptype
== PLUGIN_VST3
)
618 if (const char* const vst2Binary
= findBinaryInBundle(filename
))
620 const CarlaMagic magic
;
621 if (const char* const output
= magic
.getFileDescription(vst2Binary
))
623 carla_stdout("VST binary magic output is '%s'", output
);
625 if (std::strstr(output
, "arm64") == nullptr && std::strstr(output
, "x86_64") != nullptr)
626 needsArchBridge
= "x86_64";
628 if (std::strstr(output
, "x86_64") == nullptr && std::strstr(output
, "arm64") != nullptr)
629 needsArchBridge
= "arm64";
634 carla_stdout("VST binary magic output is null");
639 carla_stdout("Search for binary in VST bundle failed");
642 #endif // ADAPT_FOR_APPLE_SILLICON
644 #endif // ! BUILD_BRIDGE
646 #if defined(CARLA_PLUGIN_ONLY_BRIDGE)
647 if (bridgeBinary
.isNotEmpty())
649 plugin
= CarlaPlugin::newBridge(initializer
, btype
, ptype
, needsArchBridge
, bridgeBinary
);
653 setLastError("Cannot load plugin, the required plugin bridge is not available");
656 #elif !defined(CARLA_OS_WASM)
657 if (canBeBridged
&& (needsArchBridge
|| btype
!= BINARY_NATIVE
|| (preferBridges
&& bridgeBinary
.isNotEmpty())))
659 if (bridgeBinary
.isNotEmpty())
661 plugin
= CarlaPlugin::newBridge(initializer
, btype
, ptype
, needsArchBridge
, bridgeBinary
);
665 setLastError("This Carla build cannot handle this binary");
671 #ifndef CARLA_PLUGIN_ONLY_BRIDGE
673 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
676 setLastError("Invalid or unsupported plugin type");
678 // Some stupid plugins mess up with global signals, err!!
679 const CarlaSignalRestorer csr
;
684 case PLUGIN_TYPE_COUNT
:
688 plugin
= CarlaPlugin::newLADSPA(initializer
, (const LADSPA_RDF_Descriptor
*)extra
);
692 plugin
= CarlaPlugin::newDSSI(initializer
);
696 plugin
= CarlaPlugin::newLV2(initializer
);
700 plugin
= CarlaPlugin::newVST2(initializer
);
704 plugin
= CarlaPlugin::newVST3(initializer
);
708 plugin
= CarlaPlugin::newCLAP(initializer
);
712 plugin
= CarlaPlugin::newAU(initializer
);
715 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
716 case PLUGIN_INTERNAL
:
717 plugin
= CarlaPlugin::newNative(initializer
);
723 use16Outs
= (extra
!= nullptr && std::strcmp((const char*)extra
, "true") == 0);
724 plugin
= CarlaPlugin::newFluidSynth(initializer
, ptype
, use16Outs
);
728 #ifdef SFZ_FILES_USING_SFIZZ
730 CarlaPlugin::Initializer sfizzInitializer
= {
735 "http://sfztools.github.io/sfizz",
740 plugin
= CarlaPlugin::newLV2(sfizzInitializer
);
743 plugin
= CarlaPlugin::newSFZero(initializer
);
748 plugin
= CarlaPlugin::newJSFX(initializer
);
753 plugin
= CarlaPlugin::newJackApp(initializer
);
755 setLastError("JACK plugin target is not available");
759 case PLUGIN_INTERNAL
:
766 setLastError("Plugin bridges cannot handle this binary");
768 #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH
771 #endif // CARLA_PLUGIN_ONLY_BRIDGE
773 if (plugin
.get() == nullptr)
778 #ifdef SFZ_FILES_USING_SFIZZ
779 if (ptype
== PLUGIN_SFZ
&& plugin
->getType() == PLUGIN_LV2
)
781 plugin
->setCustomData(LV2_ATOM__Path
,
782 "http://sfztools.github.io/sfizz:sfzfile",
786 plugin
->restoreLV2State(true);
792 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
794 /**/ if (plugin
->getMidiInCount() > 1 || plugin
->getMidiOutCount() > 1)
796 setLastError("Carla's patchbay mode cannot work with plugins that have multiple MIDI ports, sorry!");
806 EnginePluginData
& pluginData(pData
->plugins
[id
]);
807 pluginData
.plugin
= plugin
;
808 carla_zeroFloats(pluginData
.peaks
, 4);
810 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
811 if (oldPlugin
.get() != nullptr)
813 CARLA_SAFE_ASSERT(! pData
->loadingProject
);
815 const ScopedRunnerStopper
srs(this);
817 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
818 pData
->graph
.replacePlugin(oldPlugin
, plugin
);
820 const bool wasActive
= oldPlugin
->getInternalParameterValue(PARAMETER_ACTIVE
) >= 0.5f
;
821 const float oldDryWet
= oldPlugin
->getInternalParameterValue(PARAMETER_DRYWET
);
822 const float oldVolume
= oldPlugin
->getInternalParameterValue(PARAMETER_VOLUME
);
824 oldPlugin
->prepareForDeletion();
826 const CarlaMutexLocker
cml(pData
->pluginsToDeleteMutex
);
827 pData
->pluginsToDelete
.push_back(oldPlugin
);
830 if (plugin
->getHints() & PLUGIN_CAN_DRYWET
)
831 plugin
->setDryWet(oldDryWet
, true, true);
833 if (plugin
->getHints() & PLUGIN_CAN_VOLUME
)
834 plugin
->setVolume(oldVolume
, true, true);
836 plugin
->setActive(wasActive
, true, true);
837 plugin
->setEnabled(true);
839 callback(true, true, ENGINE_CALLBACK_RELOAD_ALL
, id
, 0, 0, 0, 0.0f
, nullptr);
841 else if (! pData
->loadingProject
)
844 plugin
->setEnabled(true);
846 ++pData
->curPluginCount
;
847 callback(true, true, ENGINE_CALLBACK_PLUGIN_ADDED
, id
, plugin
->getType(), 0, 0, 0.0f
, plugin
->getName());
849 if (getType() != kEngineTypeBridge
)
850 plugin
->setActive(true, true, true);
852 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
853 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
854 pData
->graph
.addPlugin(plugin
);
860 #if defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) || defined(CARLA_PLUGIN_ONLY_BRIDGE)
866 bool CarlaEngine::addPlugin(const PluginType ptype
,
867 const char* const filename
,
868 const char* const name
,
869 const char* const label
,
870 const int64_t uniqueId
,
871 const void* const extra
)
873 return addPlugin(BINARY_NATIVE
, ptype
, filename
, name
, label
, uniqueId
, extra
, PLUGIN_OPTIONS_NULL
);
876 bool CarlaEngine::removePlugin(const uint id
)
878 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
879 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
880 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
!= nullptr, "Invalid engine internal data");
881 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->curPluginCount
!= 0, "Invalid engine internal data");
883 CARLA_SAFE_ASSERT_RETURN_ERR(id
== 0, "Invalid engine internal data");
885 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
886 CARLA_SAFE_ASSERT_RETURN_ERR(id
< pData
->curPluginCount
, "Invalid plugin Id");
887 carla_debug("CarlaEngine::removePlugin(%i)", id
);
889 const CarlaPluginPtr plugin
= pData
->plugins
[id
].plugin
;
891 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
.get() != nullptr, "Could not find plugin to remove");
892 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
->getId() == id
, "Invalid engine internal data");
894 const ScopedRunnerStopper
srs(this);
896 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
897 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
898 pData
->graph
.removePlugin(plugin
);
900 const ScopedActionLock
sal(this, kEnginePostActionRemovePlugin
, id
, 0);
903 for (uint i=id; i < pData->curPluginCount; ++i)
905 CarlaPlugin* const plugin2(pData->plugins[i].plugin);
906 CARLA_SAFE_ASSERT_BREAK(plugin2 != nullptr);
907 plugin2->updateOscURL();
911 pData
->curPluginCount
= 0;
912 pData
->plugins
[0].plugin
.reset();
913 carla_zeroStruct(pData
->plugins
[0].peaks
);
916 plugin
->prepareForDeletion();
918 const CarlaMutexLocker
cml(pData
->pluginsToDeleteMutex
);
919 pData
->pluginsToDelete
.push_back(plugin
);
922 callback(true, true, ENGINE_CALLBACK_PLUGIN_REMOVED
, id
, 0, 0, 0, 0.0f
, nullptr);
926 bool CarlaEngine::removeAllPlugins()
928 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
929 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
930 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
!= nullptr, "Invalid engine internal data");
931 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextPluginId
== pData
->maxPluginNumber
, "Invalid engine internal data");
933 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
934 carla_debug("CarlaEngine::removeAllPlugins()");
936 if (pData
->curPluginCount
== 0)
939 const ScopedRunnerStopper
srs(this);
941 const uint curPluginCount
= pData
->curPluginCount
;
943 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
944 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
945 pData
->graph
.removeAllPlugins(pData
->aboutToClose
);
948 const ScopedActionLock
sal(this, kEnginePostActionZeroCount
, 0, 0);
950 callback(true, false, ENGINE_CALLBACK_IDLE
, 0, 0, 0, 0, 0.0f
, nullptr);
952 for (uint i
=0; i
< curPluginCount
; ++i
)
954 const uint id
= curPluginCount
- i
- 1;
955 EnginePluginData
& pluginData(pData
->plugins
[id
]);
957 pluginData
.plugin
->prepareForDeletion();
959 const CarlaMutexLocker
cml(pData
->pluginsToDeleteMutex
);
960 pData
->pluginsToDelete
.push_back(pluginData
.plugin
);
963 pluginData
.plugin
.reset();
964 carla_zeroStruct(pluginData
.peaks
);
966 callback(true, true, ENGINE_CALLBACK_PLUGIN_REMOVED
, id
, 0, 0, 0, 0.0f
, nullptr);
967 callback(true, false, ENGINE_CALLBACK_IDLE
, 0, 0, 0, 0, 0.0f
, nullptr);
973 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
974 bool CarlaEngine::renamePlugin(const uint id
, const char* const newName
)
976 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
977 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
!= nullptr, "Invalid engine internal data");
978 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->curPluginCount
!= 0, "Invalid engine internal data");
979 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
980 CARLA_SAFE_ASSERT_RETURN_ERR(id
< pData
->curPluginCount
, "Invalid plugin Id");
981 CARLA_SAFE_ASSERT_RETURN_ERR(newName
!= nullptr && newName
[0] != '\0', "Invalid plugin name");
982 carla_debug("CarlaEngine::renamePlugin(%i, \"%s\")", id
, newName
);
984 const CarlaPluginPtr plugin
= pData
->plugins
[id
].plugin
;
985 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
.get() != nullptr, "Could not find plugin to rename");
986 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
->getId() == id
, "Invalid engine internal data");
988 const char* const uniqueName(getUniquePluginName(newName
));
989 CARLA_SAFE_ASSERT_RETURN_ERR(uniqueName
!= nullptr, "Unable to get new unique plugin name");
991 plugin
->setName(uniqueName
);
993 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
994 pData
->graph
.renamePlugin(plugin
, uniqueName
);
996 callback(true, true, ENGINE_CALLBACK_PLUGIN_RENAMED
, id
, 0, 0, 0, 0.0f
, uniqueName
);
1002 bool CarlaEngine::clonePlugin(const uint id
)
1004 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
1005 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
!= nullptr, "Invalid engine internal data");
1006 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->curPluginCount
!= 0, "Invalid engine internal data");
1007 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
1008 CARLA_SAFE_ASSERT_RETURN_ERR(id
< pData
->curPluginCount
, "Invalid plugin Id");
1009 carla_debug("CarlaEngine::clonePlugin(%i)", id
);
1011 const CarlaPluginPtr plugin
= pData
->plugins
[id
].plugin
;
1013 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
.get() != nullptr, "Could not find plugin to clone");
1014 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
->getId() == id
, "Invalid engine internal data");
1016 char label
[STR_MAX
+1];
1017 carla_zeroChars(label
, STR_MAX
+1);
1019 if (! plugin
->getLabel(label
))
1022 const uint
pluginCountBefore(pData
->curPluginCount
);
1024 if (! addPlugin(plugin
->getBinaryType(), plugin
->getType(),
1025 plugin
->getFilename(), plugin
->getName(), label
, plugin
->getUniqueId(),
1026 plugin
->getExtraStuff(), plugin
->getOptionsEnabled()))
1029 CARLA_SAFE_ASSERT_RETURN_ERR(pluginCountBefore
+1 == pData
->curPluginCount
, "No new plugin found");
1031 if (const CarlaPluginPtr newPlugin
= pData
->plugins
[pluginCountBefore
].plugin
)
1033 if (newPlugin
->getType() == PLUGIN_LV2
)
1034 newPlugin
->cloneLV2Files(*plugin
);
1035 newPlugin
->loadStateSave(plugin
->getStateSave(true));
1041 bool CarlaEngine::replacePlugin(const uint id
) noexcept
1043 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
1044 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
!= nullptr, "Invalid engine internal data");
1045 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->curPluginCount
!= 0, "Invalid engine internal data");
1046 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
1047 carla_debug("CarlaEngine::replacePlugin(%i)", id
);
1049 // might use this to reset
1050 if (id
== pData
->maxPluginNumber
)
1052 pData
->nextPluginId
= pData
->maxPluginNumber
;
1056 CARLA_SAFE_ASSERT_RETURN_ERR(id
< pData
->curPluginCount
, "Invalid plugin Id");
1058 const CarlaPluginPtr plugin
= pData
->plugins
[id
].plugin
;
1060 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
.get() != nullptr, "Could not find plugin to replace");
1061 CARLA_SAFE_ASSERT_RETURN_ERR(plugin
->getId() == id
, "Invalid engine internal data");
1063 pData
->nextPluginId
= id
;
1068 bool CarlaEngine::switchPlugins(const uint idA
, const uint idB
) noexcept
1070 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
1071 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->plugins
!= nullptr, "Invalid engine internal data");
1072 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->curPluginCount
>= 2, "Invalid engine internal data");
1073 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
1074 CARLA_SAFE_ASSERT_RETURN_ERR(idA
!= idB
, "Invalid operation, cannot switch plugin with itself");
1075 CARLA_SAFE_ASSERT_RETURN_ERR(idA
< pData
->curPluginCount
, "Invalid plugin Id");
1076 CARLA_SAFE_ASSERT_RETURN_ERR(idB
< pData
->curPluginCount
, "Invalid plugin Id");
1077 carla_debug("CarlaEngine::switchPlugins(%i)", idA
, idB
);
1079 const CarlaPluginPtr pluginA
= pData
->plugins
[idA
].plugin
;
1080 const CarlaPluginPtr pluginB
= pData
->plugins
[idB
].plugin
;
1082 CARLA_SAFE_ASSERT_RETURN_ERR(pluginA
.get() != nullptr, "Could not find plugin to switch");
1083 CARLA_SAFE_ASSERT_RETURN_ERR(pluginB
.get() != nullptr, "Could not find plugin to switch");
1084 CARLA_SAFE_ASSERT_RETURN_ERR(pluginA
->getId() == idA
, "Invalid engine internal data");
1085 CARLA_SAFE_ASSERT_RETURN_ERR(pluginB
->getId() == idB
, "Invalid engine internal data");
1087 const ScopedRunnerStopper
srs(this);
1089 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
1090 pData
->graph
.switchPlugins(pluginA
, pluginB
);
1092 const ScopedActionLock
sal(this, kEnginePostActionSwitchPlugins
, idA
, idB
);
1096 pluginA->updateOscURL();
1097 pluginB->updateOscURL();
1099 if (isOscControlRegistered())
1100 oscSend_control_switch_plugins(idA, idB);
1107 void CarlaEngine::touchPluginParameter(const uint
, const uint32_t, const bool) noexcept
1111 CarlaPluginPtr
CarlaEngine::getPlugin(const uint id
) const noexcept
1113 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1114 CARLA_SAFE_ASSERT_RETURN_ERRN(pData
->plugins
!= nullptr, "Invalid engine internal data");
1115 CARLA_SAFE_ASSERT_RETURN_ERRN(pData
->curPluginCount
!= 0, "Invalid engine internal data");
1117 CARLA_SAFE_ASSERT_RETURN_ERRN(pData
->nextAction
.opcode
== kEnginePostActionNull
, "Invalid engine internal data");
1118 CARLA_SAFE_ASSERT_RETURN_ERRN(id
< pData
->curPluginCount
, "Invalid plugin Id");
1120 return pData
->plugins
[id
].plugin
;
1123 CarlaPluginPtr
CarlaEngine::getPluginUnchecked(const uint id
) const noexcept
1125 return pData
->plugins
[id
].plugin
;
1128 const char* CarlaEngine::getUniquePluginName(const char* const name
) const
1130 CARLA_SAFE_ASSERT_RETURN(pData
->nextAction
.opcode
== kEnginePostActionNull
, nullptr);
1131 CARLA_SAFE_ASSERT_RETURN(name
!= nullptr && name
[0] != '\0', nullptr);
1132 carla_debug("CarlaEngine::getUniquePluginName(\"%s\")", name
);
1137 if (sname
.isEmpty())
1139 sname
= "(No name)";
1143 const std::size_t maxNameSize(carla_minConstrained
<uint
>(getMaxClientNameSize(), 0xff, 6U) - 6); // 6 = strlen(" (10)") + 1
1145 if (maxNameSize
== 0 || ! isRunning())
1148 sname
.truncate(maxNameSize
);
1149 sname
.replace(':', '.'); // ':' is used in JACK1 to split client/port names
1150 sname
.replace('/', '.'); // '/' is used by us for client name prefix
1152 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
1154 const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
;
1155 CARLA_SAFE_ASSERT_BREAK(plugin
.use_count() > 0);
1157 // Check if unique name doesn't exist
1158 if (const char* const pluginName
= plugin
->getName())
1160 if (sname
!= pluginName
)
1164 // Check if string has already been modified
1166 const std::size_t len(sname
.length());
1168 // 1 digit, ex: " (2)"
1169 if (len
> 4 && sname
[len
-4] == ' ' && sname
[len
-3] == '(' && sname
.isDigit(len
-2) && sname
[len
-1] == ')')
1171 const int number
= sname
[len
-2] - '0';
1175 // next number is 10, 2 digits
1176 sname
.truncate(len
-4);
1178 //sname.replace(" (9)", " (10)");
1181 sname
[len
-2] = char('0' + number
+ 1);
1186 // 2 digits, ex: " (11)"
1187 if (len
> 5 && sname
[len
-5] == ' ' && sname
[len
-4] == '(' && sname
.isDigit(len
-3) && sname
.isDigit(len
-2) && sname
[len
-1] == ')')
1189 char n2
= sname
[len
-2];
1190 char n3
= sname
[len
-3];
1195 n3
= static_cast<char>(n3
+ 1);
1198 n2
= static_cast<char>(n2
+ 1);
1207 // Modify string if not
1214 // -----------------------------------------------------------------------
1215 // Project management
1217 bool CarlaEngine::loadFile(const char* const filename
)
1219 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
1220 CARLA_SAFE_ASSERT_RETURN_ERR(filename
!= nullptr && filename
[0] != '\0', "Invalid filename");
1221 carla_debug("CarlaEngine::loadFile(\"%s\")", filename
);
1223 File
file(filename
);
1224 CARLA_SAFE_ASSERT_RETURN_ERR(file
.exists(), "Requested file does not exist or is not a readable");
1226 CarlaString
baseName(file
.getFileNameWithoutExtension().toRawUTF8());
1227 CarlaString
extension(file
.getFileExtension().replace(".","").toLowerCase().toRawUTF8());
1229 const uint
curPluginId(pData
->nextPluginId
< pData
->curPluginCount
? pData
->nextPluginId
: pData
->curPluginCount
);
1231 // -------------------------------------------------------------------
1232 // NOTE: please keep in sync with carla_get_supported_file_extensions!!
1234 if (extension
== "carxp" || extension
== "carxs")
1235 return loadProject(filename
, false);
1237 // -------------------------------------------------------------------
1239 if (extension
== "dls")
1240 return addPlugin(PLUGIN_DLS
, filename
, baseName
, baseName
, 0, nullptr);
1242 if (extension
== "gig")
1243 return addPlugin(PLUGIN_GIG
, filename
, baseName
, baseName
, 0, nullptr);
1245 if (extension
== "sf2" || extension
== "sf3")
1246 return addPlugin(PLUGIN_SF2
, filename
, baseName
, baseName
, 0, nullptr);
1248 if (extension
== "sfz")
1249 return addPlugin(PLUGIN_SFZ
, filename
, baseName
, baseName
, 0, nullptr);
1251 if (extension
== "jsfx")
1252 return addPlugin(PLUGIN_JSFX
, filename
, baseName
, baseName
, 0, nullptr);
1254 // -------------------------------------------------------------------
1257 extension
== "mp3" ||
1259 extension
== "aif" ||
1260 extension
== "aifc" ||
1261 extension
== "aiff" ||
1262 extension
== "au" ||
1263 extension
== "bwf" ||
1264 extension
== "flac" ||
1265 extension
== "htk" ||
1266 extension
== "iff" ||
1267 extension
== "mat4" ||
1268 extension
== "mat5" ||
1269 extension
== "oga" ||
1270 extension
== "ogg" ||
1271 extension
== "opus" ||
1272 extension
== "paf" ||
1273 extension
== "pvf" ||
1274 extension
== "pvf5" ||
1275 extension
== "sd2" ||
1276 extension
== "sf" ||
1277 extension
== "snd" ||
1278 extension
== "svx" ||
1279 extension
== "vcc" ||
1280 extension
== "w64" ||
1281 extension
== "wav" ||
1282 extension
== "xi" ||
1285 extension
== "3g2" ||
1286 extension
== "3gp" ||
1287 extension
== "aac" ||
1288 extension
== "ac3" ||
1289 extension
== "amr" ||
1290 extension
== "ape" ||
1291 extension
== "mp2" ||
1292 extension
== "mpc" ||
1293 extension
== "wma" ||
1294 # ifndef HAVE_SNDFILE
1295 // FFmpeg without sndfile
1296 extension
== "flac" ||
1297 extension
== "oga" ||
1298 extension
== "ogg" ||
1299 extension
== "w64" ||
1300 extension
== "wav" ||
1306 if (addPlugin(PLUGIN_INTERNAL
, nullptr, baseName
, "audiofile", 0, nullptr))
1308 if (const CarlaPluginPtr plugin
= getPlugin(curPluginId
))
1309 plugin
->setCustomData(CUSTOM_DATA_TYPE_STRING
, "file", filename
, true);
1315 // -------------------------------------------------------------------
1317 if (extension
== "mid" || extension
== "midi")
1319 if (addPlugin(PLUGIN_INTERNAL
, nullptr, baseName
, "midifile", 0, nullptr))
1321 if (const CarlaPluginPtr plugin
= getPlugin(curPluginId
))
1322 plugin
->setCustomData(CUSTOM_DATA_TYPE_STRING
, "file", filename
, true);
1328 // -------------------------------------------------------------------
1331 if (extension
== "xmz" || extension
== "xiz")
1333 #ifdef HAVE_ZYN_DEPS
1334 CarlaString
nicerName("Zyn - ");
1336 const std::size_t sep(baseName
.find('-')+1);
1338 if (sep
< baseName
.length())
1339 nicerName
+= baseName
.buffer()+sep
;
1341 nicerName
+= baseName
;
1343 if (addPlugin(PLUGIN_INTERNAL
, nullptr, nicerName
, "zynaddsubfx", 0, nullptr))
1345 callback(true, true, ENGINE_CALLBACK_UI_STATE_CHANGED
, curPluginId
, 0, 0, 0, 0.0f
, nullptr);
1347 if (const CarlaPluginPtr plugin
= getPlugin(curPluginId
))
1349 const char* const ext
= (extension
== "xmz") ? "CarlaAlternateFile1" : "CarlaAlternateFile2";
1350 plugin
->setCustomData(CUSTOM_DATA_TYPE_STRING
, ext
, filename
, true);
1357 setLastError("This Carla build does not have ZynAddSubFX support");
1362 // -------------------------------------------------------------------
1363 // Direct plugin binaries
1366 if (extension
== "component")
1367 return addPlugin(PLUGIN_AU
, filename
, nullptr, nullptr, 0, nullptr);
1369 if (extension
== "vst")
1370 return addPlugin(PLUGIN_VST2
, filename
, nullptr, nullptr, 0, nullptr);
1372 if (extension
== "dll" || extension
== "so")
1373 return addPlugin(getBinaryTypeFromFile(filename
), PLUGIN_VST2
, filename
, nullptr, nullptr, 0, nullptr);
1376 if (extension
== "vst3")
1377 return addPlugin(getBinaryTypeFromFile(filename
), PLUGIN_VST3
, filename
, nullptr, nullptr, 0, nullptr);
1379 if (extension
== "clap")
1380 return addPlugin(getBinaryTypeFromFile(filename
), PLUGIN_CLAP
, filename
, nullptr, nullptr, 0, nullptr);
1382 // -------------------------------------------------------------------
1384 setLastError("Unknown file extension");
1388 bool CarlaEngine::loadProject(const char* const filename
, const bool setAsCurrentProject
)
1390 CARLA_SAFE_ASSERT_RETURN_ERR(pData
->isIdling
== 0, "An operation is still being processed, please wait for it to finish");
1391 CARLA_SAFE_ASSERT_RETURN_ERR(filename
!= nullptr && filename
[0] != '\0', "Invalid filename");
1392 carla_debug("CarlaEngine::loadProject(\"%s\")", filename
);
1394 const File
file(filename
);
1395 CARLA_SAFE_ASSERT_RETURN_ERR(file
.existsAsFile(), "Requested file does not exist or is not a readable file");
1397 if (setAsCurrentProject
)
1399 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1400 if (pData
->currentProjectFilename
!= filename
)
1402 pData
->currentProjectFilename
= filename
;
1405 const size_t r
= pData
->currentProjectFilename
.rfind(CARLA_OS_SEP
, &found
);
1409 pData
->currentProjectFolder
= filename
;
1410 pData
->currentProjectFolder
[r
] = '\0';
1414 pData
->currentProjectFolder
.clear();
1420 XmlDocument
xml(file
);
1421 return loadProjectInternal(xml
, !setAsCurrentProject
);
1424 bool CarlaEngine::saveProject(const char* const filename
, const bool setAsCurrentProject
)
1426 CARLA_SAFE_ASSERT_RETURN_ERR(filename
!= nullptr && filename
[0] != '\0', "Invalid filename");
1427 carla_debug("CarlaEngine::saveProject(\"%s\")", filename
);
1429 if (setAsCurrentProject
)
1431 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1432 if (pData
->currentProjectFilename
!= filename
)
1434 pData
->currentProjectFilename
= filename
;
1437 const size_t r
= pData
->currentProjectFilename
.rfind(CARLA_OS_SEP
, &found
);
1441 pData
->currentProjectFolder
= filename
;
1442 pData
->currentProjectFolder
[r
] = '\0';
1446 pData
->currentProjectFolder
.clear();
1452 MemoryOutputStream out
;
1453 saveProjectInternal(out
);
1455 File
file(filename
);
1457 if (file
.replaceWithData(out
.getData(), out
.getDataSize()))
1460 setLastError("Failed to write file");
1464 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1465 const char* CarlaEngine::getCurrentProjectFolder() const noexcept
1467 return pData
->currentProjectFolder
.isNotEmpty() ? pData
->currentProjectFolder
.buffer()
1471 const char* CarlaEngine::getCurrentProjectFilename() const noexcept
1473 return pData
->currentProjectFilename
;
1476 void CarlaEngine::clearCurrentProjectFilename() noexcept
1478 pData
->currentProjectFilename
.clear();
1479 pData
->currentProjectFolder
.clear();
1483 // -----------------------------------------------------------------------
1484 // Information (base)
1486 uint32_t CarlaEngine::getBufferSize() const noexcept
1488 return pData
->bufferSize
;
1491 double CarlaEngine::getSampleRate() const noexcept
1493 return pData
->sampleRate
;
1496 const char* CarlaEngine::getName() const noexcept
1501 EngineProcessMode
CarlaEngine::getProccessMode() const noexcept
1503 return pData
->options
.processMode
;
1506 const EngineOptions
& CarlaEngine::getOptions() const noexcept
1508 return pData
->options
;
1511 EngineTimeInfo
CarlaEngine::getTimeInfo() const noexcept
1513 return pData
->timeInfo
;
1516 // -----------------------------------------------------------------------
1517 // Information (peaks)
1519 const float* CarlaEngine::getPeaks(const uint pluginId
) const noexcept
1521 static const float kFallback
[4] = { 0.0f
, 0.0f
, 0.0f
, 0.0f
};
1523 if (pluginId
== MAIN_CARLA_PLUGIN_ID
)
1525 // get peak from first plugin, if available
1526 if (const uint count
= pData
->curPluginCount
)
1528 pData
->peaks
[0] = pData
->plugins
[0].peaks
[0];
1529 pData
->peaks
[1] = pData
->plugins
[0].peaks
[1];
1530 pData
->peaks
[2] = pData
->plugins
[count
-1].peaks
[2];
1531 pData
->peaks
[3] = pData
->plugins
[count
-1].peaks
[3];
1535 carla_zeroFloats(pData
->peaks
, 4);
1538 return pData
->peaks
;
1541 CARLA_SAFE_ASSERT_RETURN(pluginId
< pData
->curPluginCount
, kFallback
);
1543 return pData
->plugins
[pluginId
].peaks
;
1546 float CarlaEngine::getInputPeak(const uint pluginId
, const bool isLeft
) const noexcept
1548 if (pluginId
== MAIN_CARLA_PLUGIN_ID
)
1550 // get peak from first plugin, if available
1551 if (pData
->curPluginCount
> 0)
1552 return pData
->plugins
[0].peaks
[isLeft
? 0 : 1];
1556 CARLA_SAFE_ASSERT_RETURN(pluginId
< pData
->curPluginCount
, 0.0f
);
1558 return pData
->plugins
[pluginId
].peaks
[isLeft
? 0 : 1];
1561 float CarlaEngine::getOutputPeak(const uint pluginId
, const bool isLeft
) const noexcept
1563 if (pluginId
== MAIN_CARLA_PLUGIN_ID
)
1565 // get peak from last plugin, if available
1566 if (pData
->curPluginCount
> 0)
1567 return pData
->plugins
[pData
->curPluginCount
-1].peaks
[isLeft
? 2 : 3];
1571 CARLA_SAFE_ASSERT_RETURN(pluginId
< pData
->curPluginCount
, 0.0f
);
1573 return pData
->plugins
[pluginId
].peaks
[isLeft
? 2 : 3];
1576 // -----------------------------------------------------------------------
1579 void CarlaEngine::callback(const bool sendHost
, const bool sendOSC
,
1580 const EngineCallbackOpcode action
, const uint pluginId
,
1581 const int value1
, const int value2
, const int value3
,
1582 const float valuef
, const char* const valueStr
) noexcept
1585 if (pData
->isIdling
)
1586 carla_stdout("CarlaEngine::callback [while idling] (%s, %s, %i:%s, %i, %i, %i, %i, %f, \"%s\")",
1587 bool2str(sendHost
), bool2str(sendOSC
),
1588 action
, EngineCallbackOpcode2Str(action
), pluginId
, value1
, value2
, value3
,
1589 static_cast<double>(valuef
), valueStr
);
1590 else if (action
!= ENGINE_CALLBACK_IDLE
&& action
!= ENGINE_CALLBACK_NOTE_ON
&& action
!= ENGINE_CALLBACK_NOTE_OFF
)
1591 carla_debug("CarlaEngine::callback(%s, %s, %i:%s, %i, %i, %i, %i, %f, \"%s\")",
1592 bool2str(sendHost
), bool2str(sendOSC
),
1593 action
, EngineCallbackOpcode2Str(action
), pluginId
, value1
, value2
, value3
,
1594 static_cast<double>(valuef
), valueStr
);
1597 if (sendHost
&& pData
->callback
!= nullptr)
1599 if (action
== ENGINE_CALLBACK_IDLE
)
1603 pData
->callback(pData
->callbackPtr
, action
, pluginId
, value1
, value2
, value3
, valuef
, valueStr
);
1604 } CARLA_SAFE_EXCEPTION("callback")
1606 if (action
== ENGINE_CALLBACK_IDLE
)
1612 #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
1613 if (pData
->osc
.isControlRegisteredForTCP())
1617 case ENGINE_CALLBACK_RELOAD_INFO
:
1619 CarlaPluginPtr plugin
= pData
->plugins
[pluginId
].plugin
;
1620 CARLA_SAFE_ASSERT_BREAK(plugin
!= nullptr);
1622 pData
->osc
.sendPluginInfo(plugin
);
1626 case ENGINE_CALLBACK_RELOAD_PARAMETERS
:
1628 CarlaPluginPtr plugin
= pData
->plugins
[pluginId
].plugin
;
1629 CARLA_SAFE_ASSERT_BREAK(plugin
!= nullptr);
1631 pData
->osc
.sendPluginPortCount(plugin
);
1633 if (const uint32_t count
= plugin
->getParameterCount())
1635 for (uint32_t i
=0; i
<count
; ++i
)
1636 pData
->osc
.sendPluginParameterInfo(plugin
, i
);
1641 case ENGINE_CALLBACK_RELOAD_PROGRAMS
:
1643 CarlaPluginPtr plugin
= pData
->plugins
[pluginId
].plugin
;
1644 CARLA_SAFE_ASSERT_BREAK(plugin
!= nullptr);
1646 pData
->osc
.sendPluginProgramCount(plugin
);
1648 if (const uint32_t count
= plugin
->getProgramCount())
1650 for (uint32_t i
=0; i
<count
; ++i
)
1651 pData
->osc
.sendPluginProgram(plugin
, i
);
1654 if (const uint32_t count
= plugin
->getMidiProgramCount())
1656 for (uint32_t i
=0; i
<count
; ++i
)
1657 pData
->osc
.sendPluginMidiProgram(plugin
, i
);
1662 case ENGINE_CALLBACK_PLUGIN_ADDED
:
1663 case ENGINE_CALLBACK_RELOAD_ALL
:
1665 CarlaPluginPtr plugin
= pData
->plugins
[pluginId
].plugin
;
1666 CARLA_SAFE_ASSERT_BREAK(plugin
!= nullptr);
1668 pData
->osc
.sendPluginInfo(plugin
);
1669 pData
->osc
.sendPluginPortCount(plugin
);
1670 pData
->osc
.sendPluginDataCount(plugin
);
1672 if (const uint32_t count
= plugin
->getParameterCount())
1674 for (uint32_t i
=0; i
<count
; ++i
)
1675 pData
->osc
.sendPluginParameterInfo(plugin
, i
);
1678 if (const uint32_t count
= plugin
->getProgramCount())
1680 for (uint32_t i
=0; i
<count
; ++i
)
1681 pData
->osc
.sendPluginProgram(plugin
, i
);
1684 if (const uint32_t count
= plugin
->getMidiProgramCount())
1686 for (uint32_t i
=0; i
<count
; ++i
)
1687 pData
->osc
.sendPluginMidiProgram(plugin
, i
);
1690 if (const uint32_t count
= plugin
->getCustomDataCount())
1692 for (uint32_t i
=0; i
<count
; ++i
)
1693 pData
->osc
.sendPluginCustomData(plugin
, i
);
1696 pData
->osc
.sendPluginInternalParameterValues(plugin
);
1700 case ENGINE_CALLBACK_IDLE
:
1707 pData
->osc
.sendCallback(action
, pluginId
, value1
, value2
, value3
, valuef
, valueStr
);
1713 void CarlaEngine::setCallback(const EngineCallbackFunc func
, void* const ptr
) noexcept
1715 carla_debug("CarlaEngine::setCallback(%p, %p)", func
, ptr
);
1717 pData
->callback
= func
;
1718 pData
->callbackPtr
= ptr
;
1721 // -----------------------------------------------------------------------
1724 const char* CarlaEngine::runFileCallback(const FileCallbackOpcode action
, const bool isDir
, const char* const title
, const char* const filter
) noexcept
1726 CARLA_SAFE_ASSERT_RETURN(title
!= nullptr && title
[0] != '\0', nullptr);
1727 CARLA_SAFE_ASSERT_RETURN(filter
!= nullptr, nullptr);
1728 carla_debug("CarlaEngine::runFileCallback(%i:%s, %s, \"%s\", \"%s\")", action
, FileCallbackOpcode2Str(action
), bool2str(isDir
), title
, filter
);
1730 const char* ret
= nullptr;
1732 if (pData
->fileCallback
!= nullptr)
1735 ret
= pData
->fileCallback(pData
->fileCallbackPtr
, action
, isDir
, title
, filter
);
1736 } CARLA_SAFE_EXCEPTION("runFileCallback");
1742 void CarlaEngine::setFileCallback(const FileCallbackFunc func
, void* const ptr
) noexcept
1744 carla_debug("CarlaEngine::setFileCallback(%p, %p)", func
, ptr
);
1746 pData
->fileCallback
= func
;
1747 pData
->fileCallbackPtr
= ptr
;
1750 // -----------------------------------------------------------------------
1753 void CarlaEngine::transportPlay() noexcept
1755 pData
->timeInfo
.playing
= true;
1756 pData
->time
.setNeedsReset();
1759 void CarlaEngine::transportPause() noexcept
1761 if (pData
->timeInfo
.playing
)
1762 pData
->time
.pause();
1764 pData
->time
.setNeedsReset();
1767 void CarlaEngine::transportBPM(const double bpm
) noexcept
1769 CARLA_SAFE_ASSERT_RETURN(bpm
>= 20.0,)
1772 pData
->time
.setBPM(bpm
);
1773 } CARLA_SAFE_EXCEPTION("CarlaEngine::transportBPM");
1776 void CarlaEngine::transportRelocate(const uint64_t frame
) noexcept
1778 pData
->time
.relocate(frame
);
1781 // -----------------------------------------------------------------------
1784 const char* CarlaEngine::getLastError() const noexcept
1786 return pData
->lastError
;
1789 void CarlaEngine::setLastError(const char* const error
) const noexcept
1791 pData
->lastError
= error
;
1794 // -----------------------------------------------------------------------
1797 bool CarlaEngine::isAboutToClose() const noexcept
1799 return pData
->aboutToClose
;
1802 bool CarlaEngine::setAboutToClose() noexcept
1804 carla_debug("CarlaEngine::setAboutToClose()");
1806 pData
->aboutToClose
= true;
1808 return (pData
->isIdling
== 0);
1811 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1812 bool CarlaEngine::isLoadingProject() const noexcept
1814 return pData
->loadingProject
;
1818 void CarlaEngine::setActionCanceled(const bool canceled
) noexcept
1820 pData
->actionCanceled
= canceled
;
1823 bool CarlaEngine::wasActionCanceled() const noexcept
1825 return pData
->actionCanceled
;
1828 // -----------------------------------------------------------------------
1831 void CarlaEngine::setOption(const EngineOption option
, const int value
, const char* const valueStr
) noexcept
1833 carla_debug("CarlaEngine::setOption(%i:%s, %i, \"%s\")", option
, EngineOption2Str(option
), value
, valueStr
);
1839 case ENGINE_OPTION_PROCESS_MODE
:
1840 case ENGINE_OPTION_AUDIO_TRIPLE_BUFFER
:
1841 case ENGINE_OPTION_AUDIO_DRIVER
:
1842 case ENGINE_OPTION_AUDIO_DEVICE
:
1843 return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Cannot set this option while engine is running!",
1844 option
, EngineOption2Str(option
), value
, valueStr
);
1850 // do not un-force stereo for rack mode
1851 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
&& option
== ENGINE_OPTION_FORCE_STEREO
&& value
!= 0)
1856 case ENGINE_OPTION_DEBUG
:
1859 case ENGINE_OPTION_PROCESS_MODE
:
1860 CARLA_SAFE_ASSERT_RETURN(value
>= ENGINE_PROCESS_MODE_SINGLE_CLIENT
&& value
<= ENGINE_PROCESS_MODE_BRIDGE
,);
1861 pData
->options
.processMode
= static_cast<EngineProcessMode
>(value
);
1864 case ENGINE_OPTION_TRANSPORT_MODE
:
1865 CARLA_SAFE_ASSERT_RETURN(value
>= ENGINE_TRANSPORT_MODE_DISABLED
&& value
<= ENGINE_TRANSPORT_MODE_BRIDGE
,);
1866 CARLA_SAFE_ASSERT_RETURN(getType() == kEngineTypeJack
|| value
!= ENGINE_TRANSPORT_MODE_JACK
,);
1867 pData
->options
.transportMode
= static_cast<EngineTransportMode
>(value
);
1868 delete[] pData
->options
.transportExtra
;
1869 if (value
>= ENGINE_TRANSPORT_MODE_DISABLED
&& valueStr
!= nullptr)
1870 pData
->options
.transportExtra
= carla_strdup_safe(valueStr
);
1872 pData
->options
.transportExtra
= nullptr;
1874 pData
->time
.setNeedsReset();
1876 #if defined(HAVE_HYLIA) && !defined(BUILD_BRIDGE)
1877 // enable link now if needed
1879 const bool linkEnabled
= pData
->options
.transportExtra
!= nullptr && std::strstr(pData
->options
.transportExtra
, ":link:") != nullptr;
1880 pData
->time
.enableLink(linkEnabled
);
1885 case ENGINE_OPTION_FORCE_STEREO
:
1886 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
1887 pData
->options
.forceStereo
= (value
!= 0);
1890 case ENGINE_OPTION_PREFER_PLUGIN_BRIDGES
:
1891 #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
1892 CARLA_SAFE_ASSERT_RETURN(value
== 0,);
1894 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
1896 pData
->options
.preferPluginBridges
= (value
!= 0);
1899 case ENGINE_OPTION_PREFER_UI_BRIDGES
:
1900 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
1901 pData
->options
.preferUiBridges
= (value
!= 0);
1904 case ENGINE_OPTION_UIS_ALWAYS_ON_TOP
:
1905 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
1906 pData
->options
.uisAlwaysOnTop
= (value
!= 0);
1909 case ENGINE_OPTION_MAX_PARAMETERS
:
1910 CARLA_SAFE_ASSERT_RETURN(value
>= 0,);
1911 pData
->options
.maxParameters
= static_cast<uint
>(value
);
1914 case ENGINE_OPTION_RESET_XRUNS
:
1915 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
1916 pData
->options
.resetXruns
= (value
!= 0);
1919 case ENGINE_OPTION_UI_BRIDGES_TIMEOUT
:
1920 CARLA_SAFE_ASSERT_RETURN(value
>= 0,);
1921 pData
->options
.uiBridgesTimeout
= static_cast<uint
>(value
);
1924 case ENGINE_OPTION_AUDIO_BUFFER_SIZE
:
1925 CARLA_SAFE_ASSERT_RETURN(value
>= 8,);
1926 pData
->options
.audioBufferSize
= static_cast<uint
>(value
);
1929 case ENGINE_OPTION_AUDIO_SAMPLE_RATE
:
1930 CARLA_SAFE_ASSERT_RETURN(value
>= 22050,);
1931 pData
->options
.audioSampleRate
= static_cast<uint
>(value
);
1934 case ENGINE_OPTION_AUDIO_TRIPLE_BUFFER
:
1935 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
1936 pData
->options
.audioTripleBuffer
= (value
!= 0);
1939 case ENGINE_OPTION_AUDIO_DRIVER
:
1940 CARLA_SAFE_ASSERT_RETURN(valueStr
!= nullptr,);
1942 if (pData
->options
.audioDriver
!= nullptr)
1943 delete[] pData
->options
.audioDriver
;
1945 pData
->options
.audioDriver
= carla_strdup_safe(valueStr
);
1948 case ENGINE_OPTION_AUDIO_DEVICE
:
1949 CARLA_SAFE_ASSERT_RETURN(valueStr
!= nullptr,);
1951 if (pData
->options
.audioDevice
!= nullptr)
1952 delete[] pData
->options
.audioDevice
;
1954 pData
->options
.audioDevice
= carla_strdup_safe(valueStr
);
1957 #ifndef BUILD_BRIDGE
1958 case ENGINE_OPTION_OSC_ENABLED
:
1959 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
1960 pData
->options
.oscEnabled
= (value
!= 0);
1963 case ENGINE_OPTION_OSC_PORT_TCP
:
1964 CARLA_SAFE_ASSERT_RETURN(value
<= 0 || value
>= 1024,);
1965 pData
->options
.oscPortTCP
= value
;
1968 case ENGINE_OPTION_OSC_PORT_UDP
:
1969 CARLA_SAFE_ASSERT_RETURN(value
<= 0 || value
>= 1024,);
1970 pData
->options
.oscPortUDP
= value
;
1974 case ENGINE_OPTION_FILE_PATH
:
1975 CARLA_SAFE_ASSERT_RETURN(value
> FILE_NONE
,);
1976 CARLA_SAFE_ASSERT_RETURN(value
<= FILE_MIDI
,);
1981 if (pData
->options
.pathAudio
!= nullptr)
1982 delete[] pData
->options
.pathAudio
;
1983 if (valueStr
!= nullptr)
1984 pData
->options
.pathAudio
= carla_strdup_safe(valueStr
);
1986 pData
->options
.pathAudio
= nullptr;
1989 if (pData
->options
.pathMIDI
!= nullptr)
1990 delete[] pData
->options
.pathMIDI
;
1991 if (valueStr
!= nullptr)
1992 pData
->options
.pathMIDI
= carla_strdup_safe(valueStr
);
1994 pData
->options
.pathMIDI
= nullptr;
1997 return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Invalid file type",
1998 option
, EngineOption2Str(option
), value
, valueStr
);
2002 case ENGINE_OPTION_PLUGIN_PATH
:
2003 CARLA_SAFE_ASSERT_RETURN(value
> PLUGIN_NONE
,);
2004 CARLA_SAFE_ASSERT_RETURN(value
<= PLUGIN_TYPE_COUNT
,);
2009 if (pData
->options
.pathLADSPA
!= nullptr)
2010 delete[] pData
->options
.pathLADSPA
;
2011 if (valueStr
!= nullptr)
2012 pData
->options
.pathLADSPA
= carla_strdup_safe(valueStr
);
2014 pData
->options
.pathLADSPA
= nullptr;
2017 if (pData
->options
.pathDSSI
!= nullptr)
2018 delete[] pData
->options
.pathDSSI
;
2019 if (valueStr
!= nullptr)
2020 pData
->options
.pathDSSI
= carla_strdup_safe(valueStr
);
2022 pData
->options
.pathDSSI
= nullptr;
2025 if (pData
->options
.pathLV2
!= nullptr)
2026 delete[] pData
->options
.pathLV2
;
2027 if (valueStr
!= nullptr)
2028 pData
->options
.pathLV2
= carla_strdup_safe(valueStr
);
2030 pData
->options
.pathLV2
= nullptr;
2033 if (pData
->options
.pathVST2
!= nullptr)
2034 delete[] pData
->options
.pathVST2
;
2035 if (valueStr
!= nullptr)
2036 pData
->options
.pathVST2
= carla_strdup_safe(valueStr
);
2038 pData
->options
.pathVST2
= nullptr;
2041 if (pData
->options
.pathVST3
!= nullptr)
2042 delete[] pData
->options
.pathVST3
;
2043 if (valueStr
!= nullptr)
2044 pData
->options
.pathVST3
= carla_strdup_safe(valueStr
);
2046 pData
->options
.pathVST3
= nullptr;
2049 if (pData
->options
.pathSF2
!= nullptr)
2050 delete[] pData
->options
.pathSF2
;
2051 if (valueStr
!= nullptr)
2052 pData
->options
.pathSF2
= carla_strdup_safe(valueStr
);
2054 pData
->options
.pathSF2
= nullptr;
2057 if (pData
->options
.pathSFZ
!= nullptr)
2058 delete[] pData
->options
.pathSFZ
;
2059 if (valueStr
!= nullptr)
2060 pData
->options
.pathSFZ
= carla_strdup_safe(valueStr
);
2062 pData
->options
.pathSFZ
= nullptr;
2065 if (pData
->options
.pathJSFX
!= nullptr)
2066 delete[] pData
->options
.pathJSFX
;
2067 if (valueStr
!= nullptr)
2068 pData
->options
.pathJSFX
= carla_strdup_safe(valueStr
);
2070 pData
->options
.pathJSFX
= nullptr;
2073 if (pData
->options
.pathCLAP
!= nullptr)
2074 delete[] pData
->options
.pathCLAP
;
2075 if (valueStr
!= nullptr)
2076 pData
->options
.pathCLAP
= carla_strdup_safe(valueStr
);
2078 pData
->options
.pathCLAP
= nullptr;
2081 return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Invalid plugin type",
2082 option
, EngineOption2Str(option
), value
, valueStr
);
2087 case ENGINE_OPTION_PATH_BINARIES
:
2088 CARLA_SAFE_ASSERT_RETURN(valueStr
!= nullptr && valueStr
[0] != '\0',);
2090 if (pData
->options
.binaryDir
!= nullptr)
2091 delete[] pData
->options
.binaryDir
;
2093 pData
->options
.binaryDir
= carla_strdup_safe(valueStr
);
2096 case ENGINE_OPTION_PATH_RESOURCES
:
2097 CARLA_SAFE_ASSERT_RETURN(valueStr
!= nullptr && valueStr
[0] != '\0',);
2099 if (pData
->options
.resourceDir
!= nullptr)
2100 delete[] pData
->options
.resourceDir
;
2102 pData
->options
.resourceDir
= carla_strdup_safe(valueStr
);
2105 case ENGINE_OPTION_PREVENT_BAD_BEHAVIOUR
: {
2106 CARLA_SAFE_ASSERT_RETURN(pData
->options
.binaryDir
!= nullptr && pData
->options
.binaryDir
[0] != '\0',);
2108 #ifdef CARLA_OS_LINUX
2109 const ScopedEngineEnvironmentLocker
_seel(this);
2113 CarlaString
interposerPath(CarlaString(pData
->options
.binaryDir
) + "/libcarla_interposer-safe.so");
2114 ::setenv("LD_PRELOAD", interposerPath
.buffer(), 1);
2118 ::unsetenv("LD_PRELOAD");
2123 case ENGINE_OPTION_FRONTEND_BACKGROUND_COLOR
:
2124 pData
->options
.bgColor
= static_cast<uint
>(value
);
2127 case ENGINE_OPTION_FRONTEND_FOREGROUND_COLOR
:
2128 pData
->options
.fgColor
= static_cast<uint
>(value
);
2131 case ENGINE_OPTION_FRONTEND_UI_SCALE
:
2132 CARLA_SAFE_ASSERT_RETURN(value
> 0,);
2133 pData
->options
.uiScale
= static_cast<float>(value
) / 1000;
2136 case ENGINE_OPTION_FRONTEND_WIN_ID
: {
2137 CARLA_SAFE_ASSERT_RETURN(valueStr
!= nullptr && valueStr
[0] != '\0',);
2138 const long long winId(std::strtoll(valueStr
, nullptr, 16));
2139 CARLA_SAFE_ASSERT_RETURN(winId
>= 0,);
2140 pData
->options
.frontendWinId
= static_cast<uintptr_t>(winId
);
2143 #if !defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) && !defined(CARLA_OS_WIN)
2144 case ENGINE_OPTION_WINE_EXECUTABLE
:
2145 CARLA_SAFE_ASSERT_RETURN(valueStr
!= nullptr && valueStr
[0] != '\0',);
2147 if (pData
->options
.wine
.executable
!= nullptr)
2148 delete[] pData
->options
.wine
.executable
;
2150 pData
->options
.wine
.executable
= carla_strdup_safe(valueStr
);
2153 case ENGINE_OPTION_WINE_AUTO_PREFIX
:
2154 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
2155 pData
->options
.wine
.autoPrefix
= (value
!= 0);
2158 case ENGINE_OPTION_WINE_FALLBACK_PREFIX
:
2159 CARLA_SAFE_ASSERT_RETURN(valueStr
!= nullptr && valueStr
[0] != '\0',);
2161 if (pData
->options
.wine
.fallbackPrefix
!= nullptr)
2162 delete[] pData
->options
.wine
.fallbackPrefix
;
2164 pData
->options
.wine
.fallbackPrefix
= carla_strdup_safe(valueStr
);
2167 case ENGINE_OPTION_WINE_RT_PRIO_ENABLED
:
2168 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
2169 pData
->options
.wine
.rtPrio
= (value
!= 0);
2172 case ENGINE_OPTION_WINE_BASE_RT_PRIO
:
2173 CARLA_SAFE_ASSERT_RETURN(value
>= 1 && value
<= 89,);
2174 pData
->options
.wine
.baseRtPrio
= value
;
2177 case ENGINE_OPTION_WINE_SERVER_RT_PRIO
:
2178 CARLA_SAFE_ASSERT_RETURN(value
>= 1 && value
<= 99,);
2179 pData
->options
.wine
.serverRtPrio
= value
;
2183 #ifndef BUILD_BRIDGE
2184 case ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT
:
2188 case ENGINE_OPTION_CLIENT_NAME_PREFIX
:
2189 if (pData
->options
.clientNamePrefix
!= nullptr)
2190 delete[] pData
->options
.clientNamePrefix
;
2192 pData
->options
.clientNamePrefix
= valueStr
!= nullptr && valueStr
[0] != '\0'
2193 ? carla_strdup_safe(valueStr
)
2197 case ENGINE_OPTION_PLUGINS_ARE_STANDALONE
:
2198 CARLA_SAFE_ASSERT_RETURN(value
== 0 || value
== 1,);
2199 pData
->options
.pluginsAreStandalone
= (value
!= 0);
2204 #ifndef BUILD_BRIDGE
2205 // -----------------------------------------------------------------------
2208 bool CarlaEngine::isOscControlRegistered() const noexcept
2211 return pData
->osc
.isControlRegisteredForTCP();
2217 const char* CarlaEngine::getOscServerPathTCP() const noexcept
2220 return pData
->osc
.getServerPathTCP();
2226 const char* CarlaEngine::getOscServerPathUDP() const noexcept
2229 return pData
->osc
.getServerPathUDP();
2236 // -----------------------------------------------------------------------
2239 void CarlaEngine::bufferSizeChanged(const uint32_t newBufferSize
)
2241 carla_debug("CarlaEngine::bufferSizeChanged(%i)", newBufferSize
);
2243 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2244 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
||
2245 pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
2247 pData
->graph
.setBufferSize(newBufferSize
);
2251 pData
->time
.updateAudioValues(newBufferSize
, pData
->sampleRate
);
2253 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
2255 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
2257 if (plugin
->isEnabled() && plugin
->tryLock(true))
2259 plugin
->bufferSizeChanged(newBufferSize
);
2265 callback(true, true, ENGINE_CALLBACK_BUFFER_SIZE_CHANGED
, 0, static_cast<int>(newBufferSize
), 0, 0, 0.0f
, nullptr);
2268 void CarlaEngine::sampleRateChanged(const double newSampleRate
)
2270 carla_debug("CarlaEngine::sampleRateChanged(%g)", newSampleRate
);
2272 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2273 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
||
2274 pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
2276 pData
->graph
.setSampleRate(newSampleRate
);
2280 pData
->time
.updateAudioValues(pData
->bufferSize
, newSampleRate
);
2282 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
2284 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
2286 if (plugin
->isEnabled() && plugin
->tryLock(true))
2288 plugin
->sampleRateChanged(newSampleRate
);
2294 callback(true, true, ENGINE_CALLBACK_SAMPLE_RATE_CHANGED
, 0, 0, 0, 0, static_cast<float>(newSampleRate
), nullptr);
2297 void CarlaEngine::offlineModeChanged(const bool isOfflineNow
)
2299 carla_debug("CarlaEngine::offlineModeChanged(%s)", bool2str(isOfflineNow
));
2301 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2302 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
||
2303 pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
2305 pData
->graph
.setOffline(isOfflineNow
);
2309 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
2311 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
2312 if (plugin
->isEnabled())
2313 plugin
->offlineModeChanged(isOfflineNow
);
2317 void CarlaEngine::setPluginPeaksRT(const uint pluginId
, float const inPeaks
[2], float const outPeaks
[2]) noexcept
2319 EnginePluginData
& pluginData(pData
->plugins
[pluginId
]);
2321 pluginData
.peaks
[0] = inPeaks
[0];
2322 pluginData
.peaks
[1] = inPeaks
[1];
2323 pluginData
.peaks
[2] = outPeaks
[0];
2324 pluginData
.peaks
[3] = outPeaks
[1];
2327 void CarlaEngine::saveProjectInternal(water::MemoryOutputStream
& outStream
) const
2329 // send initial prepareForSave first, giving time for bridges to act
2330 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
2332 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
2334 if (plugin
->isEnabled())
2336 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2337 // deactivate bridge client-side ping check, since some plugins block during save
2338 if (plugin
->getHints() & PLUGIN_IS_BRIDGE
)
2339 plugin
->setCustomData(CUSTOM_DATA_TYPE_STRING
, "__CarlaPingOnOff__", "false", false);
2341 plugin
->prepareForSave(false);
2346 outStream
<< "<?xml version='1.0' encoding='UTF-8'?>\n";
2347 outStream
<< "<!DOCTYPE CARLA-PROJECT>\n";
2348 outStream
<< "<CARLA-PROJECT VERSION='" CARLA_VERSION_STRMIN
"'";
2350 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2351 if (pData
->ignoreClientPrefix
)
2352 outStream
<< " IgnoreClientPrefix='true'";
2357 const bool isPlugin(getType() == kEngineTypePlugin
);
2358 const EngineOptions
& options(pData
->options
);
2361 MemoryOutputStream
outSettings(1024);
2363 outSettings
<< " <EngineSettings>\n";
2365 outSettings
<< " <ForceStereo>" << bool2str(options
.forceStereo
) << "</ForceStereo>\n";
2366 outSettings
<< " <PreferPluginBridges>" << bool2str(options
.preferPluginBridges
) << "</PreferPluginBridges>\n";
2367 outSettings
<< " <PreferUiBridges>" << bool2str(options
.preferUiBridges
) << "</PreferUiBridges>\n";
2368 outSettings
<< " <UIsAlwaysOnTop>" << bool2str(options
.uisAlwaysOnTop
) << "</UIsAlwaysOnTop>\n";
2370 outSettings
<< " <MaxParameters>" << String(options
.maxParameters
) << "</MaxParameters>\n";
2371 outSettings
<< " <UIBridgesTimeout>" << String(options
.uiBridgesTimeout
) << "</UIBridgesTimeout>\n";
2375 outSettings
<< " <LADSPA_PATH>" << xmlSafeString(options
.pathLADSPA
, true) << "</LADSPA_PATH>\n";
2376 outSettings
<< " <DSSI_PATH>" << xmlSafeString(options
.pathDSSI
, true) << "</DSSI_PATH>\n";
2377 outSettings
<< " <LV2_PATH>" << xmlSafeString(options
.pathLV2
, true) << "</LV2_PATH>\n";
2378 outSettings
<< " <VST2_PATH>" << xmlSafeString(options
.pathVST2
, true) << "</VST2_PATH>\n";
2379 outSettings
<< " <VST3_PATH>" << xmlSafeString(options
.pathVST3
, true) << "</VST3_PATH>\n";
2380 outSettings
<< " <SF2_PATH>" << xmlSafeString(options
.pathSF2
, true) << "</SF2_PATH>\n";
2381 outSettings
<< " <SFZ_PATH>" << xmlSafeString(options
.pathSFZ
, true) << "</SFZ_PATH>\n";
2382 outSettings
<< " <JSFX_PATH>" << xmlSafeString(options
.pathJSFX
, true) << "</JSFX_PATH>\n";
2383 outSettings
<< " <CLAP_PATH>" << xmlSafeString(options
.pathCLAP
, true) << "</CLAP_PATH>\n";
2386 outSettings
<< " </EngineSettings>\n";
2387 outStream
<< outSettings
;
2390 if (pData
->timeInfo
.bbt
.valid
&& ! isPlugin
)
2392 MemoryOutputStream
outTransport(128);
2394 outTransport
<< "\n <Transport>\n";
2395 // outTransport << " <BeatsPerBar>" << pData->timeInfo.bbt.beatsPerBar << "</BeatsPerBar>\n";
2396 outTransport
<< " <BeatsPerMinute>" << pData
->timeInfo
.bbt
.beatsPerMinute
<< "</BeatsPerMinute>\n";
2397 outTransport
<< " </Transport>\n";
2398 outStream
<< outTransport
;
2401 char strBuf
[STR_MAX
+1];
2402 carla_zeroChars(strBuf
, STR_MAX
+1);
2404 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
2406 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
2408 if (plugin
->isEnabled())
2410 MemoryOutputStream
outPlugin(4096), streamPlugin
;
2411 plugin
->getStateSave(false).dumpToMemoryStream(streamPlugin
);
2415 if (plugin
->getRealName(strBuf
))
2416 outPlugin
<< " <!-- " << xmlSafeString(strBuf
, true) << " -->\n";
2418 outPlugin
<< " <Plugin>\n";
2419 outPlugin
<< streamPlugin
;
2420 outPlugin
<< " </Plugin>\n";
2421 outStream
<< outPlugin
;
2426 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2427 // tell bridges we're done saving
2428 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
2430 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
2431 if (plugin
->isEnabled() && (plugin
->getHints() & PLUGIN_IS_BRIDGE
) != 0)
2432 plugin
->setCustomData(CUSTOM_DATA_TYPE_STRING
, "__CarlaPingOnOff__", "true", false);
2435 // save internal connections
2436 if (pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
)
2439 const char* const* const patchbayConns
= getPatchbayConnections(false);
2440 const PatchbayPosition
* const patchbayPos
= getPatchbayPositions(false, posCount
);
2442 if (patchbayConns
!= nullptr || patchbayPos
!= nullptr)
2444 MemoryOutputStream
outPatchbay(2048);
2446 outPatchbay
<< "\n <Patchbay>\n";
2448 if (patchbayConns
!= nullptr)
2450 for (int i
=0; patchbayConns
[i
] != nullptr && patchbayConns
[i
+1] != nullptr; ++i
, ++i
)
2452 const char* const connSource(patchbayConns
[i
]);
2453 const char* const connTarget(patchbayConns
[i
+1]);
2455 CARLA_SAFE_ASSERT_CONTINUE(connSource
!= nullptr && connSource
[0] != '\0');
2456 CARLA_SAFE_ASSERT_CONTINUE(connTarget
!= nullptr && connTarget
[0] != '\0');
2458 outPatchbay
<< " <Connection>\n";
2459 outPatchbay
<< " <Source>" << xmlSafeString(connSource
, true) << "</Source>\n";
2460 outPatchbay
<< " <Target>" << xmlSafeString(connTarget
, true) << "</Target>\n";
2461 outPatchbay
<< " </Connection>\n";
2465 if (patchbayPos
!= nullptr && posCount
!= 0)
2467 outPatchbay
<< " <Positions>\n";
2469 for (uint i
=0; i
<posCount
; ++i
)
2471 const PatchbayPosition
& ppos(patchbayPos
[i
]);
2473 CARLA_SAFE_ASSERT_CONTINUE(ppos
.name
!= nullptr && ppos
.name
[0] != '\0');
2475 outPatchbay
<< " <Position x1=\"" << ppos
.x1
<< "\" y1=\"" << ppos
.y1
;
2476 if (ppos
.x2
!= 0 || ppos
.y2
!= 0)
2477 outPatchbay
<< "\" x2=\"" << ppos
.x2
<< "\" y2=\"" << ppos
.y2
;
2478 if (ppos
.pluginId
>= 0)
2479 outPatchbay
<< "\" pluginId=\"" << ppos
.pluginId
;
2480 outPatchbay
<< "\">\n";
2481 outPatchbay
<< " <Name>" << xmlSafeString(ppos
.name
, true) << "</Name>\n";
2482 outPatchbay
<< " </Position>\n";
2488 outPatchbay
<< " </Positions>\n";
2491 outPatchbay
<< " </Patchbay>\n";
2492 outStream
<< outPatchbay
;
2494 delete[] patchbayPos
;
2499 // if we're running inside some session-manager (and using JACK), let them handle the connections
2500 bool saveExternalConnections
, saveExternalPositions
= true;
2504 saveExternalConnections
= false;
2505 saveExternalPositions
= false;
2507 else if (std::strcmp(getCurrentDriverName(), "JACK") != 0)
2509 saveExternalConnections
= true;
2511 else if (std::getenv("CARLA_DONT_MANAGE_CONNECTIONS") != nullptr)
2513 saveExternalConnections
= false;
2517 saveExternalConnections
= true;
2520 if (saveExternalConnections
|| saveExternalPositions
)
2523 const char* const* const patchbayConns
= saveExternalConnections
2524 ? getPatchbayConnections(true)
2526 const PatchbayPosition
* const patchbayPos
= saveExternalPositions
2527 ? getPatchbayPositions(true, posCount
)
2530 if (patchbayConns
!= nullptr || patchbayPos
!= nullptr)
2532 MemoryOutputStream
outPatchbay(2048);
2534 outPatchbay
<< "\n <ExternalPatchbay>\n";
2536 if (patchbayConns
!= nullptr)
2538 for (int i
=0; patchbayConns
[i
] != nullptr && patchbayConns
[i
+1] != nullptr; ++i
, ++i
)
2540 const char* const connSource(patchbayConns
[i
]);
2541 const char* const connTarget(patchbayConns
[i
+1]);
2543 CARLA_SAFE_ASSERT_CONTINUE(connSource
!= nullptr && connSource
[0] != '\0');
2544 CARLA_SAFE_ASSERT_CONTINUE(connTarget
!= nullptr && connTarget
[0] != '\0');
2546 outPatchbay
<< " <Connection>\n";
2547 outPatchbay
<< " <Source>" << xmlSafeString(connSource
, true) << "</Source>\n";
2548 outPatchbay
<< " <Target>" << xmlSafeString(connTarget
, true) << "</Target>\n";
2549 outPatchbay
<< " </Connection>\n";
2553 if (patchbayPos
!= nullptr && posCount
!= 0)
2555 outPatchbay
<< " <Positions>\n";
2557 for (uint i
=0; i
<posCount
; ++i
)
2559 const PatchbayPosition
& ppos(patchbayPos
[i
]);
2561 CARLA_SAFE_ASSERT_CONTINUE(ppos
.name
!= nullptr && ppos
.name
[0] != '\0');
2563 outPatchbay
<< " <Position x1=\"" << ppos
.x1
<< "\" y1=\"" << ppos
.y1
;
2564 if (ppos
.x2
!= 0 || ppos
.y2
!= 0)
2565 outPatchbay
<< "\" x2=\"" << ppos
.x2
<< "\" y2=\"" << ppos
.y2
;
2566 if (ppos
.pluginId
>= 0)
2567 outPatchbay
<< "\" pluginId=\"" << ppos
.pluginId
;
2568 outPatchbay
<< "\">\n";
2569 outPatchbay
<< " <Name>" << xmlSafeString(ppos
.name
, true) << "</Name>\n";
2570 outPatchbay
<< " </Position>\n";
2576 outPatchbay
<< " </Positions>\n";
2579 outPatchbay
<< " </ExternalPatchbay>\n";
2580 outStream
<< outPatchbay
;
2585 outStream
<< "</CARLA-PROJECT>\n";
2588 static String
findBinaryInCustomPath(const char* const searchPath
, const char* const binary
)
2590 const StringArray
searchPaths(StringArray::fromTokens(searchPath
, CARLA_OS_SPLIT_STR
, ""));
2592 // try direct filename first
2593 String
jbinary(binary
);
2595 // adjust for current platform
2597 if (jbinary
[0] == '/')
2598 jbinary
= "C:" + jbinary
.replaceCharacter('/', '\\');
2600 if (jbinary
[1] == ':' && (jbinary
[2] == '\\' || jbinary
[2] == '/'))
2601 jbinary
= jbinary
.substring(2).replaceCharacter('\\', '/');
2604 String filename
= File(jbinary
.toRawUTF8()).getFileName();
2606 int searchFlags
= File::findFiles
|File::ignoreHiddenFiles
;
2608 if (filename
.endsWithIgnoreCase(".vst3"))
2609 searchFlags
|= File::findDirectories
;
2611 else if (filename
.endsWithIgnoreCase(".vst"))
2612 searchFlags
|= File::findDirectories
;
2615 std::vector
<File
> results
;
2616 for (const String
*it
=searchPaths
.begin(), *end
=searchPaths
.end(); it
!= end
; ++it
)
2618 const File
path(it
->toRawUTF8());
2621 path
.findChildFiles(results
, searchFlags
, true, filename
.toRawUTF8());
2623 if (!results
.empty())
2624 return results
.front().getFullPathName();
2627 // try changing extension
2628 #if defined(CARLA_OS_MAC)
2629 if (filename
.endsWithIgnoreCase(".dll") || filename
.endsWithIgnoreCase(".so"))
2630 filename
= File(jbinary
.toRawUTF8()).getFileNameWithoutExtension() + ".dylib";
2631 #elif defined(CARLA_OS_WIN)
2632 if (filename
.endsWithIgnoreCase(".dylib") || filename
.endsWithIgnoreCase(".so"))
2633 filename
= File(jbinary
.toRawUTF8()).getFileNameWithoutExtension() + ".dll";
2635 if (filename
.endsWithIgnoreCase(".dll") || filename
.endsWithIgnoreCase(".dylib"))
2636 filename
= File(jbinary
.toRawUTF8()).getFileNameWithoutExtension() + ".so";
2641 for (const String
*it
=searchPaths
.begin(), *end
=searchPaths
.end(); it
!= end
; ++it
)
2643 const File
path(it
->toRawUTF8());
2646 path
.findChildFiles(results
, searchFlags
, true, filename
.toRawUTF8());
2648 if (!results
.empty())
2649 return results
.front().getFullPathName();
2655 bool CarlaEngine::loadProjectInternal(water::XmlDocument
& xmlDoc
, const bool alwaysLoadConnections
)
2657 carla_debug("CarlaEngine::loadProjectInternal(%p, %s) - START", &xmlDoc
, bool2str(alwaysLoadConnections
));
2659 CarlaScopedPointer
<XmlElement
> xmlElement(xmlDoc
.getDocumentElement(true));
2660 CARLA_SAFE_ASSERT_RETURN_ERR(xmlElement
!= nullptr, "Failed to parse project file");
2662 const String
& xmlType(xmlElement
->getTagName());
2663 const bool isPreset(xmlType
.equalsIgnoreCase("carla-preset"));
2665 if (! (xmlType
.equalsIgnoreCase("carla-project") || isPreset
))
2667 callback(true, true, ENGINE_CALLBACK_PROJECT_LOAD_FINISHED
, 0, 0, 0, 0, 0.0f
, nullptr);
2668 setLastError("Not a valid Carla project or preset file");
2672 pData
->actionCanceled
= false;
2673 callback(true, true, ENGINE_CALLBACK_CANCELABLE_ACTION
, 0, 1, 0, 0, 0.0f
, "Loading project");
2675 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2676 if (pData
->options
.clientNamePrefix
!= nullptr)
2678 if (carla_isEqual(xmlElement
->getDoubleAttribute("VERSION", 0.0), 2.0) ||
2679 xmlElement
->getBoolAttribute("IgnoreClientPrefix", false))
2681 carla_stdout("Loading project in compatibility mode, will ignore client name prefix");
2682 pData
->ignoreClientPrefix
= true;
2683 setOption(ENGINE_OPTION_CLIENT_NAME_PREFIX
, 0, "");
2687 const CarlaScopedValueSetter
<bool> csvs(pData
->loadingProject
, true, false);
2690 // completely load file
2691 xmlElement
= xmlDoc
.getDocumentElement(false);
2692 CARLA_SAFE_ASSERT_RETURN_ERR(xmlElement
!= nullptr, "Failed to completely parse project file");
2694 if (pData
->aboutToClose
)
2697 if (pData
->actionCanceled
)
2699 setLastError("Project load canceled");
2703 callback(true, false, ENGINE_CALLBACK_IDLE
, 0, 0, 0, 0, 0.0f
, nullptr);
2705 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2706 const bool isMultiClient
= pData
->options
.processMode
== ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS
;
2707 const bool isPatchbay
= pData
->options
.processMode
== ENGINE_PROCESS_MODE_PATCHBAY
;
2709 const bool isPlugin
= getType() == kEngineTypePlugin
;
2711 // load engine settings first of all
2712 if (XmlElement
* const elem
= isPreset
? nullptr : xmlElement
->getChildByName("EngineSettings"))
2714 for (XmlElement
* settElem
= elem
->getFirstChildElement(); settElem
!= nullptr; settElem
= settElem
->getNextElement())
2716 const String
& tag(settElem
->getTagName());
2717 const String
text(settElem
->getAllSubText().trim());
2719 /** some settings might be incorrect or require extra work,
2720 so we call setOption rather than modifying them direly */
2724 const char* valueStr
= nullptr;
2726 /**/ if (tag
== "ForceStereo")
2728 option
= ENGINE_OPTION_FORCE_STEREO
;
2729 value
= text
== "true" ? 1 : 0;
2731 else if (tag
== "PreferPluginBridges")
2733 option
= ENGINE_OPTION_PREFER_PLUGIN_BRIDGES
;
2734 value
= text
== "true" ? 1 : 0;
2736 else if (tag
== "PreferUiBridges")
2738 option
= ENGINE_OPTION_PREFER_UI_BRIDGES
;
2739 value
= text
== "true" ? 1 : 0;
2741 else if (tag
== "UIsAlwaysOnTop")
2743 option
= ENGINE_OPTION_UIS_ALWAYS_ON_TOP
;
2744 value
= text
== "true" ? 1 : 0;
2746 else if (tag
== "MaxParameters")
2748 option
= ENGINE_OPTION_MAX_PARAMETERS
;
2749 value
= text
.getIntValue();
2751 else if (tag
== "UIBridgesTimeout")
2753 option
= ENGINE_OPTION_UI_BRIDGES_TIMEOUT
;
2754 value
= text
.getIntValue();
2758 /**/ if (tag
== "LADSPA_PATH")
2760 option
= ENGINE_OPTION_PLUGIN_PATH
;
2761 value
= PLUGIN_LADSPA
;
2762 valueStr
= text
.toRawUTF8();
2764 else if (tag
== "DSSI_PATH")
2766 option
= ENGINE_OPTION_PLUGIN_PATH
;
2767 value
= PLUGIN_DSSI
;
2768 valueStr
= text
.toRawUTF8();
2770 else if (tag
== "LV2_PATH")
2772 option
= ENGINE_OPTION_PLUGIN_PATH
;
2774 valueStr
= text
.toRawUTF8();
2776 else if (tag
== "VST2_PATH")
2778 option
= ENGINE_OPTION_PLUGIN_PATH
;
2779 value
= PLUGIN_VST2
;
2780 valueStr
= text
.toRawUTF8();
2782 else if (tag
.equalsIgnoreCase("VST3_PATH"))
2784 option
= ENGINE_OPTION_PLUGIN_PATH
;
2785 value
= PLUGIN_VST3
;
2786 valueStr
= text
.toRawUTF8();
2788 else if (tag
== "SF2_PATH")
2790 option
= ENGINE_OPTION_PLUGIN_PATH
;
2792 valueStr
= text
.toRawUTF8();
2794 else if (tag
== "SFZ_PATH")
2796 option
= ENGINE_OPTION_PLUGIN_PATH
;
2798 valueStr
= text
.toRawUTF8();
2800 else if (tag
== "JSFX_PATH")
2802 option
= ENGINE_OPTION_PLUGIN_PATH
;
2803 value
= PLUGIN_JSFX
;
2804 valueStr
= text
.toRawUTF8();
2806 else if (tag
== "CLAP_PATH")
2808 option
= ENGINE_OPTION_PLUGIN_PATH
;
2809 value
= PLUGIN_CLAP
;
2810 valueStr
= text
.toRawUTF8();
2816 // check old stuff, unhandled now
2817 if (tag
== "GIG_PATH")
2820 if (tag
== "LADSPA_PATH" || tag
== "DSSI_PATH" || tag
== "LV2_PATH" || tag
== "VST2_PATH")
2822 if (tag
== "VST3_PATH" || tag
== "AU_PATH")
2824 if (tag
== "SF2_PATH" || tag
== "SFZ_PATH" || tag
== "JSFX_PATH" || tag
== "CLAP_PATH")
2827 // hmm something is wrong..
2828 carla_stderr2("CarlaEngine::loadProjectInternal() - Unhandled option '%s'", tag
.toRawUTF8());
2832 setOption(static_cast<EngineOption
>(option
), value
, valueStr
);
2835 if (pData
->aboutToClose
)
2838 if (pData
->actionCanceled
)
2840 setLastError("Project load canceled");
2845 // now setup transport
2846 if (XmlElement
* const elem
= (isPreset
|| isPlugin
) ? nullptr : xmlElement
->getChildByName("Transport"))
2848 if (XmlElement
* const bpmElem
= elem
->getChildByName("BeatsPerMinute"))
2850 const String
bpmText(bpmElem
->getAllSubText().trim());
2851 const double bpm
= bpmText
.getDoubleValue();
2854 if (bpm
>= 20.0 && bpm
< 400.0)
2855 pData
->time
.setBPM(bpm
);
2857 if (pData
->aboutToClose
)
2860 if (pData
->actionCanceled
)
2862 setLastError("Project load canceled");
2868 // and we handle plugins
2869 for (XmlElement
* elem
= xmlElement
->getFirstChildElement(); elem
!= nullptr; elem
= elem
->getNextElement())
2871 const String
& tagName(elem
->getTagName());
2873 if (isPreset
|| tagName
== "Plugin")
2875 CarlaStateSave stateSave
;
2876 stateSave
.fillFromXmlElement(isPreset
? xmlElement
.get() : elem
);
2878 if (pData
->aboutToClose
)
2881 if (pData
->actionCanceled
)
2883 setLastError("Project load canceled");
2887 CARLA_SAFE_ASSERT_CONTINUE(stateSave
.type
!= nullptr);
2889 #if !(defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) || defined(CARLA_PLUGIN_ONLY_BRIDGE))
2890 // compatibility code to load projects with GIG files
2891 // FIXME Remove on 2.1 release
2892 if (std::strcmp(stateSave
.type
, "GIG") == 0)
2894 if (addPlugin(PLUGIN_LV2
, "", stateSave
.name
, "http://linuxsampler.org/plugins/linuxsampler", 0, nullptr))
2896 const uint pluginId
= pData
->curPluginCount
;
2898 if (const CarlaPluginPtr plugin
= pData
->plugins
[pluginId
].plugin
)
2900 if (pData
->aboutToClose
)
2903 if (pData
->actionCanceled
)
2905 setLastError("Project load canceled");
2910 lsState
<< "0.35\n";
2911 lsState
<< "18 0 Chromatic\n";
2912 lsState
<< "18 1 Drum Kits\n";
2913 lsState
<< "20 0\n";
2914 lsState
<< "0 1 " << stateSave
.binary
<< "\n";
2915 lsState
<< "0 0 0 0 1 0 GIG\n";
2917 plugin
->setCustomData(LV2_ATOM__String
, "http://linuxsampler.org/schema#state-string", lsState
.toRawUTF8(), true);
2918 plugin
->restoreLV2State(true);
2920 plugin
->setDryWet(stateSave
.dryWet
, true, true);
2921 plugin
->setVolume(stateSave
.volume
, true, true);
2922 plugin
->setBalanceLeft(stateSave
.balanceLeft
, true, true);
2923 plugin
->setBalanceRight(stateSave
.balanceRight
, true, true);
2924 plugin
->setPanning(stateSave
.panning
, true, true);
2925 plugin
->setCtrlChannel(stateSave
.ctrlChannel
, true, true);
2926 plugin
->setActive(stateSave
.active
, true, true);
2927 plugin
->setEnabled(true);
2929 ++pData
->curPluginCount
;
2930 callback(true, true, ENGINE_CALLBACK_PLUGIN_ADDED
, pluginId
, plugin
->getType(),
2935 pData
->graph
.addPlugin(plugin
);
2939 carla_stderr2("Failed to get new plugin, state will not be restored correctly\n");
2944 carla_stderr2("Failed to load a linuxsampler LV2 plugin, GIG file won't be loaded");
2947 callback(true, true, ENGINE_CALLBACK_IDLE
, 0, 0, 0, 0, 0.0f
, nullptr);
2950 #ifdef SFZ_FILES_USING_SFIZZ
2951 if (std::strcmp(stateSave
.type
, "SFZ") == 0)
2953 if (addPlugin(PLUGIN_LV2
, "", stateSave
.name
, "http://sfztools.github.io/sfizz", 0, nullptr))
2955 const uint pluginId
= pData
->curPluginCount
;
2957 if (const CarlaPluginPtr plugin
= pData
->plugins
[pluginId
].plugin
)
2959 if (pData
->aboutToClose
)
2962 if (pData
->actionCanceled
)
2964 setLastError("Project load canceled");
2968 plugin
->setCustomData(LV2_ATOM__Path
,
2969 "http://sfztools.github.io/sfizz:sfzfile",
2973 plugin
->restoreLV2State(true);
2975 plugin
->setDryWet(stateSave
.dryWet
, true, true);
2976 plugin
->setVolume(stateSave
.volume
, true, true);
2977 plugin
->setBalanceLeft(stateSave
.balanceLeft
, true, true);
2978 plugin
->setBalanceRight(stateSave
.balanceRight
, true, true);
2979 plugin
->setPanning(stateSave
.panning
, true, true);
2980 plugin
->setCtrlChannel(stateSave
.ctrlChannel
, true, true);
2981 plugin
->setActive(stateSave
.active
, true, true);
2982 plugin
->setEnabled(true);
2984 ++pData
->curPluginCount
;
2985 callback(true, true, ENGINE_CALLBACK_PLUGIN_ADDED
, pluginId
, plugin
->getType(),
2990 pData
->graph
.addPlugin(plugin
);
2994 carla_stderr2("Failed to get new plugin, state will not be restored correctly\n");
2999 carla_stderr2("Failed to load a sfizz LV2 plugin, SFZ file won't be loaded");
3002 callback(true, true, ENGINE_CALLBACK_IDLE
, 0, 0, 0, 0, 0.0f
, nullptr);
3008 const void* extraStuff
= nullptr;
3009 static const char kTrue
[] = "true";
3011 const PluginType ptype
= getPluginTypeFromString(stateSave
.type
);
3016 if (CarlaString(stateSave
.label
).endsWith(" (16 outs)"))
3026 if (stateSave
.binary
!= nullptr && stateSave
.binary
[0] != '\0' &&
3027 ! (File::isAbsolutePath(stateSave
.binary
) && File(stateSave
.binary
).exists()))
3029 const char* searchPath
;
3033 case PLUGIN_LADSPA
: searchPath
= pData
->options
.pathLADSPA
; break;
3034 case PLUGIN_DSSI
: searchPath
= pData
->options
.pathDSSI
; break;
3035 case PLUGIN_VST2
: searchPath
= pData
->options
.pathVST2
; break;
3036 case PLUGIN_VST3
: searchPath
= pData
->options
.pathVST3
; break;
3037 case PLUGIN_SF2
: searchPath
= pData
->options
.pathSF2
; break;
3038 case PLUGIN_SFZ
: searchPath
= pData
->options
.pathSFZ
; break;
3039 case PLUGIN_JSFX
: searchPath
= pData
->options
.pathJSFX
; break;
3040 case PLUGIN_CLAP
: searchPath
= pData
->options
.pathCLAP
; break;
3041 default: searchPath
= nullptr; break;
3044 if (searchPath
!= nullptr && searchPath
[0] != '\0')
3046 carla_stderr("Plugin binary '%s' doesn't exist on this filesystem, let's look for it...",
3049 String result
= findBinaryInCustomPath(searchPath
, stateSave
.binary
);
3051 if (result
.isEmpty())
3055 case PLUGIN_LADSPA
: searchPath
= std::getenv("LADSPA_PATH"); break;
3056 case PLUGIN_DSSI
: searchPath
= std::getenv("DSSI_PATH"); break;
3057 case PLUGIN_VST2
: searchPath
= std::getenv("VST_PATH"); break;
3058 case PLUGIN_VST3
: searchPath
= std::getenv("VST3_PATH"); break;
3059 case PLUGIN_SF2
: searchPath
= std::getenv("SF2_PATH"); break;
3060 case PLUGIN_SFZ
: searchPath
= std::getenv("SFZ_PATH"); break;
3061 case PLUGIN_JSFX
: searchPath
= std::getenv("JSFX_PATH"); break;
3062 case PLUGIN_CLAP
: searchPath
= std::getenv("CLAP_PATH"); break;
3063 default: searchPath
= nullptr; break;
3066 if (searchPath
!= nullptr && searchPath
[0] != '\0')
3067 result
= findBinaryInCustomPath(searchPath
, stateSave
.binary
);
3070 if (result
.isNotEmpty())
3072 delete[] stateSave
.binary
;
3073 stateSave
.binary
= carla_strdup(result
.toRawUTF8());
3074 carla_stderr("Found it! :)");
3078 carla_stderr("Damn, we failed... :(");
3081 callback(true, true, ENGINE_CALLBACK_IDLE
, 0, 0, 0, 0, 0.0f
, nullptr);
3100 btype
= getBinaryTypeFromFile(stateSave
.binary
);
3103 btype
= BINARY_NATIVE
;
3107 if (addPlugin(btype
, ptype
, stateSave
.binary
,
3108 stateSave
.name
, stateSave
.label
, stateSave
.uniqueId
, extraStuff
, stateSave
.options
))
3110 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
3111 const uint pluginId
= pData
->curPluginCount
;
3113 const uint pluginId
= 0;
3116 if (const CarlaPluginPtr plugin
= pData
->plugins
[pluginId
].plugin
)
3118 if (pData
->aboutToClose
)
3121 if (pData
->actionCanceled
)
3123 setLastError("Project load canceled");
3127 // deactivate bridge client-side ping check, since some plugins block during load
3128 if ((plugin
->getHints() & PLUGIN_IS_BRIDGE
) != 0 && ! isPreset
)
3129 plugin
->setCustomData(CUSTOM_DATA_TYPE_STRING
, "__CarlaPingOnOff__", "false", false);
3131 plugin
->loadStateSave(stateSave
);
3133 /* NOTE: The following code is the same as the end of addPlugin().
3134 * When project is loading we do not enable the plugin right away,
3135 * as we want to load state first.
3137 plugin
->setEnabled(true);
3139 ++pData
->curPluginCount
;
3140 callback(true, true, ENGINE_CALLBACK_PLUGIN_ADDED
, pluginId
, plugin
->getType(),
3144 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
3146 pData
->graph
.addPlugin(plugin
);
3151 carla_stderr2("Failed to get new plugin, state will not be restored correctly\n");
3156 carla_stderr2("Failed to load a plugin '%s', error was:\n%s", stateSave
.name
, getLastError());
3160 callback(true, true, ENGINE_CALLBACK_IDLE
, 0, 0, 0, 0, 0.0f
, nullptr);
3165 callback(true, true, ENGINE_CALLBACK_PROJECT_LOAD_FINISHED
, 0, 0, 0, 0, 0.0f
, nullptr);
3166 callback(true, true, ENGINE_CALLBACK_CANCELABLE_ACTION
, 0, 0, 0, 0, 0.0f
, "Loading project");
3171 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
3172 // tell bridges we're done loading
3173 for (uint i
=0; i
< pData
->curPluginCount
; ++i
)
3175 if (const CarlaPluginPtr plugin
= pData
->plugins
[i
].plugin
)
3176 if (plugin
->isEnabled() && (plugin
->getHints() & PLUGIN_IS_BRIDGE
) != 0)
3177 plugin
->setCustomData(CUSTOM_DATA_TYPE_STRING
, "__CarlaPingOnOff__", "true", false);
3180 if (pData
->aboutToClose
)
3183 if (pData
->actionCanceled
)
3185 setLastError("Project load canceled");
3189 // now we handle positions
3190 bool loadingAsExternal
;
3191 std::map
<water::String
, water::String
> mapGroupNamesInternal
, mapGroupNamesExternal
;
3193 bool hasInternalPositions
= false;
3195 if (XmlElement
* const elemPatchbay
= xmlElement
->getChildByName("Patchbay"))
3197 hasInternalPositions
= true;
3199 if (XmlElement
* const elemPositions
= elemPatchbay
->getChildByName("Positions"))
3202 PatchbayPosition ppos
= { nullptr, -1, 0, 0, 0, 0, false };
3204 for (XmlElement
* patchElem
= elemPositions
->getFirstChildElement(); patchElem
!= nullptr; patchElem
= patchElem
->getNextElement())
3206 const String
& patchTag(patchElem
->getTagName());
3208 if (patchTag
!= "Position")
3211 XmlElement
* const patchName
= patchElem
->getChildByName("Name");
3212 CARLA_SAFE_ASSERT_CONTINUE(patchName
!= nullptr);
3214 const String
nameText(patchName
->getAllSubText().trim());
3215 name
= xmlSafeString(nameText
, false);
3217 ppos
.name
= name
.toRawUTF8();
3218 ppos
.x1
= patchElem
->getIntAttribute("x1");
3219 ppos
.y1
= patchElem
->getIntAttribute("y1");
3220 ppos
.x2
= patchElem
->getIntAttribute("x2");
3221 ppos
.y2
= patchElem
->getIntAttribute("y2");
3222 ppos
.pluginId
= patchElem
->getIntAttribute("pluginId", -1);
3223 ppos
.dealloc
= false;
3225 loadingAsExternal
= ppos
.pluginId
>= 0 && isMultiClient
;
3227 if (name
.isNotEmpty() && restorePatchbayGroupPosition(loadingAsExternal
, ppos
))
3229 if (name
!= ppos
.name
)
3231 carla_stdout("Converted client name '%s' to '%s' for this session",
3232 name
.toRawUTF8(), ppos
.name
);
3233 if (loadingAsExternal
)
3234 mapGroupNamesExternal
[name
] = ppos
.name
;
3236 mapGroupNamesInternal
[name
] = ppos
.name
;
3240 std::free(const_cast<char*>(ppos
.name
));
3244 if (pData
->aboutToClose
)
3247 if (pData
->actionCanceled
)
3249 setLastError("Project load canceled");
3255 if (XmlElement
* const elemPatchbay
= xmlElement
->getChildByName("ExternalPatchbay"))
3257 if (XmlElement
* const elemPositions
= elemPatchbay
->getChildByName("Positions"))
3260 PatchbayPosition ppos
= { nullptr, -1, 0, 0, 0, 0, false };
3262 for (XmlElement
* patchElem
= elemPositions
->getFirstChildElement(); patchElem
!= nullptr; patchElem
= patchElem
->getNextElement())
3264 const String
& patchTag(patchElem
->getTagName());
3266 if (patchTag
!= "Position")
3269 XmlElement
* const patchName
= patchElem
->getChildByName("Name");
3270 CARLA_SAFE_ASSERT_CONTINUE(patchName
!= nullptr);
3272 const String
nameText(patchName
->getAllSubText().trim());
3273 name
= xmlSafeString(nameText
, false);
3275 ppos
.name
= name
.toRawUTF8();
3276 ppos
.x1
= patchElem
->getIntAttribute("x1");
3277 ppos
.y1
= patchElem
->getIntAttribute("y1");
3278 ppos
.x2
= patchElem
->getIntAttribute("x2");
3279 ppos
.y2
= patchElem
->getIntAttribute("y2");
3280 ppos
.pluginId
= patchElem
->getIntAttribute("pluginId", -1);
3281 ppos
.dealloc
= false;
3283 loadingAsExternal
= ppos
.pluginId
< 0 || hasInternalPositions
|| !isPatchbay
;
3285 carla_debug("loadingAsExternal: %i because %i %i %i",
3286 loadingAsExternal
, ppos
.pluginId
< 0, hasInternalPositions
, !isPatchbay
);
3288 if (name
.isNotEmpty() && restorePatchbayGroupPosition(loadingAsExternal
, ppos
))
3290 if (name
!= ppos
.name
)
3292 carla_stdout("Converted client name '%s' to '%s' for this session",
3293 name
.toRawUTF8(), ppos
.name
);
3295 if (loadingAsExternal
)
3296 mapGroupNamesExternal
[name
] = ppos
.name
;
3298 mapGroupNamesInternal
[name
] = ppos
.name
;
3302 std::free(const_cast<char*>(ppos
.name
));
3306 if (pData
->aboutToClose
)
3309 if (pData
->actionCanceled
)
3311 setLastError("Project load canceled");
3317 bool hasInternalConnections
= false;
3319 // and now we handle connections (internal)
3320 if (XmlElement
* const elem
= xmlElement
->getChildByName("Patchbay"))
3322 hasInternalConnections
= true;
3326 water::String sourcePort
, targetPort
;
3328 for (XmlElement
* patchElem
= elem
->getFirstChildElement(); patchElem
!= nullptr; patchElem
= patchElem
->getNextElement())
3330 const String
& patchTag(patchElem
->getTagName());
3332 if (patchTag
!= "Connection")
3338 for (XmlElement
* connElem
= patchElem
->getFirstChildElement(); connElem
!= nullptr; connElem
= connElem
->getNextElement())
3340 const String
& tag(connElem
->getTagName());
3341 const String
text(connElem
->getAllSubText().trim());
3343 /**/ if (tag
== "Source")
3344 sourcePort
= xmlSafeString(text
, false);
3345 else if (tag
== "Target")
3346 targetPort
= xmlSafeString(text
, false);
3349 if (sourcePort
.isNotEmpty() && targetPort
.isNotEmpty())
3351 std::map
<water::String
, water::String
>& map(mapGroupNamesInternal
);
3352 std::map
<water::String
, water::String
>::iterator it
;
3354 if ((it
= map
.find(sourcePort
.upToFirstOccurrenceOf(":", false, false))) != map
.end())
3355 sourcePort
= it
->second
+ sourcePort
.fromFirstOccurrenceOf(":", true, false);
3356 if ((it
= map
.find(targetPort
.upToFirstOccurrenceOf(":", false, false))) != map
.end())
3357 targetPort
= it
->second
+ targetPort
.fromFirstOccurrenceOf(":", true, false);
3359 restorePatchbayConnection(false, sourcePort
.toRawUTF8(), targetPort
.toRawUTF8());
3363 if (pData
->aboutToClose
)
3366 if (pData
->actionCanceled
)
3368 setLastError("Project load canceled");
3374 // if we're running inside some session-manager (and using JACK), let them handle the external connections
3375 bool loadExternalConnections
;
3377 if (alwaysLoadConnections
)
3379 loadExternalConnections
= true;
3383 /**/ if (std::strcmp(getCurrentDriverName(), "JACK") != 0)
3384 loadExternalConnections
= true;
3385 else if (std::getenv("CARLA_DONT_MANAGE_CONNECTIONS") != nullptr)
3386 loadExternalConnections
= false;
3387 else if (std::getenv("LADISH_APP_NAME") != nullptr)
3388 loadExternalConnections
= false;
3389 else if (std::getenv("NSM_URL") != nullptr)
3390 loadExternalConnections
= false;
3392 loadExternalConnections
= true;
3395 // plus external connections too
3396 if (loadExternalConnections
)
3399 loadingAsExternal
= hasInternalConnections
&&
3400 (pData
->options
.processMode
== ENGINE_PROCESS_MODE_CONTINUOUS_RACK
|| isPatchbay
);
3402 for (XmlElement
* elem
= xmlElement
->getFirstChildElement(); elem
!= nullptr; elem
= elem
->getNextElement())
3404 const String
& tagName(elem
->getTagName());
3406 // check if we want to load patchbay-mode connections into an external (multi-client) graph
3407 if (tagName
== "Patchbay")
3412 loadingAsExternal
= true;
3414 // or load external patchbay connections
3415 else if (tagName
== "ExternalPatchbay")
3418 loadingAsExternal
= true;
3426 water::String sourcePort
, targetPort
;
3428 for (XmlElement
* patchElem
= elem
->getFirstChildElement(); patchElem
!= nullptr; patchElem
= patchElem
->getNextElement())
3430 const String
& patchTag(patchElem
->getTagName());
3432 if (patchTag
!= "Connection")
3438 for (XmlElement
* connElem
= patchElem
->getFirstChildElement(); connElem
!= nullptr; connElem
= connElem
->getNextElement())
3440 const String
& tag(connElem
->getTagName());
3441 const String
text(connElem
->getAllSubText().trim());
3443 /**/ if (tag
== "Source")
3444 sourcePort
= xmlSafeString(text
, false);
3445 else if (tag
== "Target")
3446 targetPort
= xmlSafeString(text
, false);
3449 if (sourcePort
.isNotEmpty() && targetPort
.isNotEmpty())
3451 std::map
<water::String
, water::String
>& map(loadingAsExternal
? mapGroupNamesExternal
3452 : mapGroupNamesInternal
);
3453 std::map
<water::String
, water::String
>::iterator it
;
3455 if (isExternal
&& isPatchbay
&& !loadingAsExternal
&& sourcePort
.startsWith("system:capture_"))
3457 water::String internalPort
= sourcePort
.trimCharactersAtStart("system:capture_");
3459 if (pData
->graph
.getNumAudioOuts() < 3)
3461 /**/ if (internalPort
== "1")
3462 internalPort
= "Audio Input:Left";
3463 else if (internalPort
== "2")
3464 internalPort
= "Audio Input:Right";
3465 else if (internalPort
== "3")
3466 internalPort
= "Audio Input:Sidechain";
3472 internalPort
= "Audio Input:Capture " + internalPort
;
3475 carla_stdout("Converted port name '%s' to '%s' for this session",
3476 sourcePort
.toRawUTF8(), internalPort
.toRawUTF8());
3477 sourcePort
= internalPort
;
3479 else if (!isExternal
&& isMultiClient
&& sourcePort
.startsWith("Audio Input:"))
3481 water::String externalPort
= sourcePort
.trimCharactersAtStart("Audio Input:");
3483 /**/ if (externalPort
== "Left")
3484 externalPort
= "system:capture_1";
3485 else if (externalPort
== "Right")
3486 externalPort
= "system:capture_2";
3487 else if (externalPort
== "Sidechain")
3488 externalPort
= "system:capture_3";
3490 externalPort
= "system:capture_ " + externalPort
.trimCharactersAtStart("Capture ");
3492 carla_stdout("Converted port name '%s' to '%s' for this session",
3493 sourcePort
.toRawUTF8(), externalPort
.toRawUTF8());
3494 sourcePort
= externalPort
;
3496 else if ((it
= map
.find(sourcePort
.upToFirstOccurrenceOf(":", false, false))) != map
.end())
3498 sourcePort
= it
->second
+ sourcePort
.fromFirstOccurrenceOf(":", true, false);
3501 if (isExternal
&& isPatchbay
&& !loadingAsExternal
&& targetPort
.startsWith("system:playback_"))
3503 water::String internalPort
= targetPort
.trimCharactersAtStart("system:playback_");
3505 if (pData
->graph
.getNumAudioOuts() < 3)
3507 /**/ if (internalPort
== "1")
3508 internalPort
= "Audio Output:Left";
3509 else if (internalPort
== "2")
3510 internalPort
= "Audio Output:Right";
3516 internalPort
= "Audio Input:Playback " + internalPort
;
3519 carla_stdout("Converted port name '%s' to '%s' for this session",
3520 targetPort
.toRawUTF8(), internalPort
.toRawUTF8());
3521 targetPort
= internalPort
;
3523 else if (!isExternal
&& isMultiClient
&& targetPort
.startsWith("Audio Output:"))
3525 water::String externalPort
= targetPort
.trimCharactersAtStart("Audio Output:");
3527 /**/ if (externalPort
== "Left")
3528 externalPort
= "system:playback_1";
3529 else if (externalPort
== "Right")
3530 externalPort
= "system:playback_2";
3532 externalPort
= "system:playback_ " + externalPort
.trimCharactersAtStart("Playback ");
3534 carla_stdout("Converted port name '%s' to '%s' for this session",
3535 targetPort
.toRawUTF8(), externalPort
.toRawUTF8());
3536 targetPort
= externalPort
;
3538 else if ((it
= map
.find(targetPort
.upToFirstOccurrenceOf(":", false, false))) != map
.end())
3540 targetPort
= it
->second
+ targetPort
.fromFirstOccurrenceOf(":", true, false);
3543 restorePatchbayConnection(loadingAsExternal
, sourcePort
.toRawUTF8(), targetPort
.toRawUTF8());
3551 if (pData
->options
.resetXruns
)
3554 callback(true, true, ENGINE_CALLBACK_PROJECT_LOAD_FINISHED
, 0, 0, 0, 0, 0.0f
, nullptr);
3555 callback(true, true, ENGINE_CALLBACK_CANCELABLE_ACTION
, 0, 0, 0, 0, 0.0f
, "Loading project");
3557 carla_debug("CarlaEngine::loadProjectInternal(%p, %s) - END", &xmlDoc
, bool2str(alwaysLoadConnections
));
3560 #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
3562 (void)alwaysLoadConnections
;
3566 // -----------------------------------------------------------------------
3568 CARLA_BACKEND_END_NAMESPACE