Cleanup
[carla.git] / source / backend / engine / CarlaEngine.cpp
blob100599b953d562dd9629a60be46fe19ee3ee4d7c
1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
4 /* TODO:
5 * - complete processRack(): carefully add to input, sorted events
6 * - implement processPatchbay()
7 * - implement oscSend_control_switch_plugins()
8 * - something about the peaks?
9 */
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"
33 #ifdef CARLA_OS_MAC
34 # include "CarlaMacUtils.hpp"
35 # if defined(CARLA_OS_64BIT) && defined(HAVE_LIBMAGIC) && ! defined(BUILD_BRIDGE_ALTERNATIVE_ARCH)
36 # define ADAPT_FOR_APPLE_SILLICON
37 # endif
38 #endif
40 #include <map>
42 // FIXME Remove on 2.1 release
43 #include "lv2/atom.h"
45 using water::Array;
46 using water::CharPointer_UTF8;
47 using water::File;
48 using water::MemoryOutputStream;
49 using water::String;
50 using water::StringArray;
51 using water::XmlDocument;
52 using water::XmlElement;
54 // #define SFZ_FILES_USING_SFIZZ
56 CARLA_BACKEND_START_NAMESPACE
58 // -----------------------------------------------------------------------
59 // Carla Engine
61 CarlaEngine::CarlaEngine()
62 : pData(new ProtectedData(this))
64 carla_debug("CarlaEngine::CarlaEngine()");
67 CarlaEngine::~CarlaEngine()
69 carla_debug("CarlaEngine::~CarlaEngine()");
71 delete pData;
74 // -----------------------------------------------------------------------
75 // Static calls
77 uint CarlaEngine::getDriverCount()
79 carla_debug("CarlaEngine::getDriverCount()");
80 using namespace EngineInit;
82 uint count = 0;
84 #ifdef HAVE_JACK
85 if (jackbridge_is_ok())
86 ++count;
87 #endif
89 #ifdef USING_RTAUDIO
90 count += getRtAudioApiCount();
91 #endif
93 #ifdef HAVE_SDL
94 ++count;
95 #endif
97 return count;
100 const char* CarlaEngine::getDriverName(const uint index)
102 carla_debug("CarlaEngine::getDriverName(%u)", index);
103 using namespace EngineInit;
105 uint index2 = index;
107 #ifdef HAVE_JACK
108 if (jackbridge_is_ok())
110 if (index2 == 0)
111 return "JACK";
112 --index2;
114 #endif
116 #ifdef USING_RTAUDIO
117 if (const uint count = getRtAudioApiCount())
119 if (index2 < count)
120 return getRtAudioApiName(index2);
121 index2 -= count;
123 #endif
125 #ifdef HAVE_SDL
126 if (index2 == 0)
127 return "SDL";
128 --index2;
129 #endif
131 carla_stderr("CarlaEngine::getDriverName(%u) - invalid index %u", index, index2);
132 return nullptr;
135 const char* const* CarlaEngine::getDriverDeviceNames(const uint index)
137 carla_debug("CarlaEngine::getDriverDeviceNames(%u)", index);
138 using namespace EngineInit;
140 uint index2 = index;
142 #ifdef HAVE_JACK
143 if (jackbridge_is_ok())
145 if (index2 == 0)
147 static const char* ret[3] = { "Auto-Connect ON", "Auto-Connect OFF", nullptr };
148 return ret;
150 --index2;
152 #endif
154 #ifdef USING_RTAUDIO
155 if (const uint count = getRtAudioApiCount())
157 if (index2 < count)
158 return getRtAudioApiDeviceNames(index2);
159 index2 -= count;
161 #endif
163 #ifdef HAVE_SDL
164 if (index2 == 0)
165 return getSDLDeviceNames();
166 --index2;
167 #endif
169 carla_stderr("CarlaEngine::getDriverDeviceNames(%u) - invalid index %u", index, index2);
170 return nullptr;
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;
178 uint index2 = index;
180 #ifdef HAVE_JACK
181 if (jackbridge_is_ok())
183 if (index2 == 0)
185 static EngineDriverDeviceInfo devInfo;
186 devInfo.hints = ENGINE_DRIVER_DEVICE_VARIABLE_BUFFER_SIZE;
187 devInfo.bufferSizes = nullptr;
188 devInfo.sampleRates = nullptr;
189 return &devInfo;
191 --index2;
193 #endif
195 #ifdef USING_RTAUDIO
196 if (const uint count = getRtAudioApiCount())
198 if (index2 < count)
199 return getRtAudioDeviceInfo(index2, deviceName);
200 index2 -= count;
202 #endif
204 #ifdef HAVE_SDL
205 if (index2 == 0)
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;
210 devInfo.hints = 0x0;
211 devInfo.bufferSizes = sdlBufferSizes;
212 devInfo.sampleRates = sdlSampleRates;
213 return &devInfo;
215 --index2;
216 #endif
218 carla_stderr("CarlaEngine::getDriverDeviceInfo(%u, \"%s\") - invalid index %u", index, deviceName, index2);
219 return nullptr;
222 bool CarlaEngine::showDriverDeviceControlPanel(const uint index, const char* const deviceName)
224 carla_debug("CarlaEngine::showDriverDeviceControlPanel(%u, \"%s\")", index, deviceName);
225 using namespace EngineInit;
227 uint index2 = index;
229 #ifdef HAVE_JACK
230 if (jackbridge_is_ok())
232 if (index2 == 0)
233 return false;
234 --index2;
236 #endif
238 #ifdef USING_RTAUDIO
239 if (const uint count = getRtAudioApiCount())
241 if (index2 < count)
242 return false;
243 index2 -= count;
245 #endif
247 #ifdef HAVE_SDL
248 if (index2 == 0)
249 return false;
250 --index2;
251 #endif
253 carla_stderr("CarlaEngine::showDriverDeviceControlPanel(%u, \"%s\") - invalid index %u", index, deviceName, index2);
254 return false;
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;
263 #ifdef HAVE_JACK
264 if (std::strcmp(driverName, "JACK") == 0)
265 return newJack();
266 #endif
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)
270 return newDummy();
271 #endif
273 #ifdef USING_RTAUDIO
274 // -------------------------------------------------------------------
275 // common
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 // -------------------------------------------------------------------
283 // linux
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 // -------------------------------------------------------------------
291 // macos
293 if (std::strcmp(driverName, "CoreAudio") == 0)
294 return newRtAudio(AUDIO_API_COREAUDIO);
296 // -------------------------------------------------------------------
297 // windows
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);
305 #endif
307 #ifdef HAVE_SDL
308 if (std::strcmp(driverName, "SDL") == 0)
309 return newSDL();
310 #endif
312 carla_stderr("CarlaEngine::newDriverByName(\"%s\") - invalid driver name", driverName);
313 return nullptr;
316 // -----------------------------------------------------------------------
317 // Constant values
319 uint CarlaEngine::getMaxClientNameSize() const noexcept
321 return STR_MAX/2;
324 uint CarlaEngine::getMaxPortNameSize() const noexcept
326 return STR_MAX;
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;
349 removeAllPlugins();
352 pData->close();
354 callback(true, true, ENGINE_CALLBACK_ENGINE_STOPPED, 0, 0, 0, 0, 0.0f, nullptr);
355 return true;
358 bool CarlaEngine::usesConstantBufferSize() const noexcept
360 return true;
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)
382 try {
383 plugin->idle();
384 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin idle");
386 if (hints & PLUGIN_HAS_CUSTOM_UI)
388 try {
389 plugin->uiIdle();
390 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin uiIdle");
393 else
395 if (engineHasIdleOnMainThread && (hints & PLUGIN_NEEDS_MAIN_THREAD_IDLE) != 0)
397 try {
398 plugin->idle();
399 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin idle");
402 if ((hints & PLUGIN_HAS_CUSTOM_UI) != 0 && (hints & PLUGIN_NEEDS_UI_MAIN_THREAD) != 0)
404 try {
405 plugin->uiIdle();
406 } CARLA_SAFE_EXCEPTION_CONTINUE("Plugin uiIdle");
413 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
414 pData->osc.idle();
415 #endif
417 pData->deletePluginsAsNeeded();
420 CarlaEngineClient* CarlaEngine::addClient(CarlaPluginPtr plugin)
422 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
423 return new CarlaEngineClientForStandalone(*this, pData->graph, plugin);
424 #else
425 return new CarlaEngineClientForBridge(*this);
427 // unused
428 (void)plugin;
429 #endif
432 float CarlaEngine::getDSPLoad() const noexcept
434 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
435 return pData->dspLoad;
436 #else
437 return 0.0f;
438 #endif
441 uint32_t CarlaEngine::getTotalXruns() const noexcept
443 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
444 return pData->xruns;
445 #else
446 return 0;
447 #endif
450 void CarlaEngine::clearXruns() const noexcept
452 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
453 pData->xruns = 0;
454 #endif
457 bool CarlaEngine::showDeviceControlPanel() const noexcept
459 return false;
462 bool CarlaEngine::setBufferSizeAndSampleRate(const uint, const double)
464 return false;
467 // -----------------------------------------------------------------------
468 // Plugin management
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,
477 const uint options)
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");
483 #endif
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);
491 #ifndef CARLA_OS_WIN
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");
495 #endif
497 uint id;
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");
511 else
512 #endif
514 id = pData->curPluginCount;
516 if (id == pData->maxPluginNumber)
518 setLastError("Maximum number of plugins reached");
519 return false;
522 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
523 CARLA_SAFE_ASSERT_RETURN_ERR(pData->plugins[id].plugin.get() == nullptr, "Invalid engine internal data");
524 #endif
527 CarlaPlugin::Initializer initializer = {
528 this,
530 filename,
531 name,
532 label,
533 uniqueId,
534 options
537 CarlaPluginPtr plugin;
538 CarlaString bridgeBinary(pData->options.binaryDir);
540 if (bridgeBinary.isNotEmpty())
542 #ifndef CARLA_OS_WIN
543 if (btype == BINARY_NATIVE)
545 bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-native";
547 else
548 #endif
550 switch (btype)
552 case BINARY_POSIX32:
553 bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-posix32";
554 break;
555 case BINARY_POSIX64:
556 bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-posix64";
557 break;
558 case BINARY_WIN32:
559 #if defined(CARLA_OS_WIN) && !defined(CARLA_OS_64BIT)
560 bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-native.exe";
561 #else
562 bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-win32.exe";
563 #endif
564 break;
565 case BINARY_WIN64:
566 #if defined(CARLA_OS_WIN) && defined(CARLA_OS_64BIT)
567 bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-native.exe";
568 #else
569 bridgeBinary += CARLA_OS_SEP_STR "carla-bridge-win64.exe";
570 #endif
571 break;
572 default:
573 bridgeBinary.clear();
574 break;
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;
594 #ifdef CARLA_OS_MAC
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);
598 #endif
600 #ifndef BUILD_BRIDGE
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);
624 #ifdef __aarch64__
625 if (std::strstr(output, "arm64") == nullptr && std::strstr(output, "x86_64") != nullptr)
626 needsArchBridge = "x86_64";
627 #else
628 if (std::strstr(output, "x86_64") == nullptr && std::strstr(output, "arm64") != nullptr)
629 needsArchBridge = "arm64";
630 #endif
632 else
634 carla_stdout("VST binary magic output is null");
637 else
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);
651 else
653 setLastError("Cannot load plugin, the required plugin bridge is not available");
654 return false;
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);
663 else
665 setLastError("This Carla build cannot handle this binary");
666 return false;
669 else
670 #endif
671 #ifndef CARLA_PLUGIN_ONLY_BRIDGE
673 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
674 bool use16Outs;
675 #endif
676 setLastError("Invalid or unsupported plugin type");
678 // Some stupid plugins mess up with global signals, err!!
679 const CarlaSignalRestorer csr;
681 switch (ptype)
683 case PLUGIN_NONE:
684 case PLUGIN_TYPE_COUNT:
685 break;
687 case PLUGIN_LADSPA:
688 plugin = CarlaPlugin::newLADSPA(initializer, (const LADSPA_RDF_Descriptor*)extra);
689 break;
691 case PLUGIN_DSSI:
692 plugin = CarlaPlugin::newDSSI(initializer);
693 break;
695 case PLUGIN_LV2:
696 plugin = CarlaPlugin::newLV2(initializer);
697 break;
699 case PLUGIN_VST2:
700 plugin = CarlaPlugin::newVST2(initializer);
701 break;
703 case PLUGIN_VST3:
704 plugin = CarlaPlugin::newVST3(initializer);
705 break;
707 case PLUGIN_CLAP:
708 plugin = CarlaPlugin::newCLAP(initializer);
709 break;
711 case PLUGIN_AU:
712 plugin = CarlaPlugin::newAU(initializer);
713 break;
715 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
716 case PLUGIN_INTERNAL:
717 plugin = CarlaPlugin::newNative(initializer);
718 break;
720 case PLUGIN_DLS:
721 case PLUGIN_GIG:
722 case PLUGIN_SF2:
723 use16Outs = (extra != nullptr && std::strcmp((const char*)extra, "true") == 0);
724 plugin = CarlaPlugin::newFluidSynth(initializer, ptype, use16Outs);
725 break;
727 case PLUGIN_SFZ:
728 #ifdef SFZ_FILES_USING_SFIZZ
730 CarlaPlugin::Initializer sfizzInitializer = {
731 this,
733 name,
735 "http://sfztools.github.io/sfizz",
737 options
740 plugin = CarlaPlugin::newLV2(sfizzInitializer);
742 #else
743 plugin = CarlaPlugin::newSFZero(initializer);
744 #endif
745 break;
747 case PLUGIN_JSFX:
748 plugin = CarlaPlugin::newJSFX(initializer);
749 break;
751 case PLUGIN_JACK:
752 #ifdef HAVE_JACK
753 plugin = CarlaPlugin::newJackApp(initializer);
754 #else
755 setLastError("JACK plugin target is not available");
756 #endif
757 break;
758 #else
759 case PLUGIN_INTERNAL:
760 case PLUGIN_DLS:
761 case PLUGIN_GIG:
762 case PLUGIN_SF2:
763 case PLUGIN_SFZ:
764 case PLUGIN_JACK:
765 case PLUGIN_JSFX:
766 setLastError("Plugin bridges cannot handle this binary");
767 break;
768 #endif // BUILD_BRIDGE_ALTERNATIVE_ARCH
771 #endif // CARLA_PLUGIN_ONLY_BRIDGE
773 if (plugin.get() == nullptr)
774 return false;
776 plugin->reload();
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",
783 filename,
784 false);
786 plugin->restoreLV2State(true);
788 #endif
790 bool canRun = 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!");
797 canRun = false;
801 if (! canRun)
803 return false;
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)
842 #endif
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);
855 #endif
858 return true;
860 #if defined(BUILD_BRIDGE_ALTERNATIVE_ARCH) || defined(CARLA_PLUGIN_ONLY_BRIDGE)
861 // unused
862 (void)extra;
863 #endif
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");
882 #else
883 CARLA_SAFE_ASSERT_RETURN_ERR(id == 0, "Invalid engine internal data");
884 #endif
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();
910 #else
911 pData->curPluginCount = 0;
912 pData->plugins[0].plugin.reset();
913 carla_zeroStruct(pData->plugins[0].peaks);
914 #endif
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);
923 return true;
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");
932 #endif
933 CARLA_SAFE_ASSERT_RETURN_ERR(pData->nextAction.opcode == kEnginePostActionNull, "Invalid engine internal data");
934 carla_debug("CarlaEngine::removeAllPlugins()");
936 if (pData->curPluginCount == 0)
937 return true;
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);
946 #endif
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);
970 return true;
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);
998 delete[] uniqueName;
999 return true;
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))
1020 label[0] = '\0';
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()))
1027 return false;
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));
1038 return 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;
1053 return true;
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;
1065 return true;
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);
1094 // TODO
1096 pluginA->updateOscURL();
1097 pluginB->updateOscURL();
1099 if (isOscControlRegistered())
1100 oscSend_control_switch_plugins(idA, idB);
1103 return true;
1105 #endif
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");
1116 #endif
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);
1134 CarlaString sname;
1135 sname = name;
1137 if (sname.isEmpty())
1139 sname = "(No name)";
1140 return sname.dup();
1143 const std::size_t maxNameSize(carla_minConstrained<uint>(getMaxClientNameSize(), 0xff, 6U) - 6); // 6 = strlen(" (10)") + 1
1145 if (maxNameSize == 0 || ! isRunning())
1146 return sname.dup();
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)
1161 continue;
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';
1173 if (number == 9)
1175 // next number is 10, 2 digits
1176 sname.truncate(len-4);
1177 sname += " (10)";
1178 //sname.replace(" (9)", " (10)");
1180 else
1181 sname[len-2] = char('0' + number + 1);
1183 continue;
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];
1192 if (n2 == '9')
1194 n2 = '0';
1195 n3 = static_cast<char>(n3 + 1);
1197 else
1198 n2 = static_cast<char>(n2 + 1);
1200 sname[len-2] = n2;
1201 sname[len-3] = n3;
1203 continue;
1207 // Modify string if not
1208 sname += " (2)";
1211 return sname.dup();
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 // -------------------------------------------------------------------
1256 if (
1257 extension == "mp3" ||
1258 #ifdef HAVE_SNDFILE
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" ||
1283 #endif
1284 #ifdef HAVE_FFMPEG
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" ||
1301 # endif
1302 #endif
1303 false
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);
1310 return true;
1312 return false;
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);
1323 return true;
1325 return false;
1328 // -------------------------------------------------------------------
1329 // ZynAddSubFX
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;
1340 else
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);
1353 return true;
1355 return false;
1356 #else
1357 setLastError("This Carla build does not have ZynAddSubFX support");
1358 return false;
1359 #endif
1362 // -------------------------------------------------------------------
1363 // Direct plugin binaries
1365 #ifdef CARLA_OS_MAC
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);
1371 #else
1372 if (extension == "dll" || extension == "so")
1373 return addPlugin(getBinaryTypeFromFile(filename), PLUGIN_VST2, filename, nullptr, nullptr, 0, nullptr);
1374 #endif
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");
1385 return false;
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;
1404 bool found;
1405 const size_t r = pData->currentProjectFilename.rfind(CARLA_OS_SEP, &found);
1407 if (found)
1409 pData->currentProjectFolder = filename;
1410 pData->currentProjectFolder[r] = '\0';
1412 else
1414 pData->currentProjectFolder.clear();
1417 #endif
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;
1436 bool found;
1437 const size_t r = pData->currentProjectFilename.rfind(CARLA_OS_SEP, &found);
1439 if (found)
1441 pData->currentProjectFolder = filename;
1442 pData->currentProjectFolder[r] = '\0';
1444 else
1446 pData->currentProjectFolder.clear();
1449 #endif
1452 MemoryOutputStream out;
1453 saveProjectInternal(out);
1455 File file(filename);
1457 if (file.replaceWithData(out.getData(), out.getDataSize()))
1458 return true;
1460 setLastError("Failed to write file");
1461 return false;
1464 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1465 const char* CarlaEngine::getCurrentProjectFolder() const noexcept
1467 return pData->currentProjectFolder.isNotEmpty() ? pData->currentProjectFolder.buffer()
1468 : nullptr;
1471 const char* CarlaEngine::getCurrentProjectFilename() const noexcept
1473 return pData->currentProjectFilename;
1476 void CarlaEngine::clearCurrentProjectFilename() noexcept
1478 pData->currentProjectFilename.clear();
1479 pData->currentProjectFolder.clear();
1481 #endif
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
1498 return pData->name;
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];
1533 else
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];
1553 return 0.0f;
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];
1568 return 0.0f;
1571 CARLA_SAFE_ASSERT_RETURN(pluginId < pData->curPluginCount, 0.0f);
1573 return pData->plugins[pluginId].peaks[isLeft ? 2 : 3];
1576 // -----------------------------------------------------------------------
1577 // Callback
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
1584 #ifdef DEBUG
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);
1595 #endif
1597 if (sendHost && pData->callback != nullptr)
1599 if (action == ENGINE_CALLBACK_IDLE)
1600 ++pData->isIdling;
1602 try {
1603 pData->callback(pData->callbackPtr, action, pluginId, value1, value2, value3, valuef, valueStr);
1604 } CARLA_SAFE_EXCEPTION("callback")
1606 if (action == ENGINE_CALLBACK_IDLE)
1607 --pData->isIdling;
1610 if (sendOSC)
1612 #if defined(HAVE_LIBLO) && ! defined(BUILD_BRIDGE)
1613 if (pData->osc.isControlRegisteredForTCP())
1615 switch (action)
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);
1623 break;
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);
1638 break;
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);
1659 break;
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);
1697 break;
1700 case ENGINE_CALLBACK_IDLE:
1701 return;
1703 default:
1704 break;
1707 pData->osc.sendCallback(action, pluginId, value1, value2, value3, valuef, valueStr);
1709 #endif
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 // -----------------------------------------------------------------------
1722 // File Callback
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)
1734 try {
1735 ret = pData->fileCallback(pData->fileCallbackPtr, action, isDir, title, filter);
1736 } CARLA_SAFE_EXCEPTION("runFileCallback");
1739 return ret;
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 // -----------------------------------------------------------------------
1751 // Transport
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();
1763 else
1764 pData->time.setNeedsReset();
1767 void CarlaEngine::transportBPM(const double bpm) noexcept
1769 CARLA_SAFE_ASSERT_RETURN(bpm >= 20.0,)
1771 try {
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 // -----------------------------------------------------------------------
1782 // Error handling
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 // -----------------------------------------------------------------------
1795 // Misc
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;
1816 #endif
1818 void CarlaEngine::setActionCanceled(const bool canceled) noexcept
1820 pData->actionCanceled = canceled;
1823 bool CarlaEngine::wasActionCanceled() const noexcept
1825 return pData->actionCanceled;
1828 // -----------------------------------------------------------------------
1829 // Global options
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);
1835 if (isRunning())
1837 switch (option)
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);
1845 default:
1846 break;
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)
1852 return;
1854 switch (option)
1856 case ENGINE_OPTION_DEBUG:
1857 break;
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);
1862 break;
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);
1871 else
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);
1882 #endif
1883 break;
1885 case ENGINE_OPTION_FORCE_STEREO:
1886 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
1887 pData->options.forceStereo = (value != 0);
1888 break;
1890 case ENGINE_OPTION_PREFER_PLUGIN_BRIDGES:
1891 #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
1892 CARLA_SAFE_ASSERT_RETURN(value == 0,);
1893 #else
1894 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
1895 #endif
1896 pData->options.preferPluginBridges = (value != 0);
1897 break;
1899 case ENGINE_OPTION_PREFER_UI_BRIDGES:
1900 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
1901 pData->options.preferUiBridges = (value != 0);
1902 break;
1904 case ENGINE_OPTION_UIS_ALWAYS_ON_TOP:
1905 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
1906 pData->options.uisAlwaysOnTop = (value != 0);
1907 break;
1909 case ENGINE_OPTION_MAX_PARAMETERS:
1910 CARLA_SAFE_ASSERT_RETURN(value >= 0,);
1911 pData->options.maxParameters = static_cast<uint>(value);
1912 break;
1914 case ENGINE_OPTION_RESET_XRUNS:
1915 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
1916 pData->options.resetXruns = (value != 0);
1917 break;
1919 case ENGINE_OPTION_UI_BRIDGES_TIMEOUT:
1920 CARLA_SAFE_ASSERT_RETURN(value >= 0,);
1921 pData->options.uiBridgesTimeout = static_cast<uint>(value);
1922 break;
1924 case ENGINE_OPTION_AUDIO_BUFFER_SIZE:
1925 CARLA_SAFE_ASSERT_RETURN(value >= 8,);
1926 pData->options.audioBufferSize = static_cast<uint>(value);
1927 break;
1929 case ENGINE_OPTION_AUDIO_SAMPLE_RATE:
1930 CARLA_SAFE_ASSERT_RETURN(value >= 22050,);
1931 pData->options.audioSampleRate = static_cast<uint>(value);
1932 break;
1934 case ENGINE_OPTION_AUDIO_TRIPLE_BUFFER:
1935 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
1936 pData->options.audioTripleBuffer = (value != 0);
1937 break;
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);
1946 break;
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);
1955 break;
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);
1961 break;
1963 case ENGINE_OPTION_OSC_PORT_TCP:
1964 CARLA_SAFE_ASSERT_RETURN(value <= 0 || value >= 1024,);
1965 pData->options.oscPortTCP = value;
1966 break;
1968 case ENGINE_OPTION_OSC_PORT_UDP:
1969 CARLA_SAFE_ASSERT_RETURN(value <= 0 || value >= 1024,);
1970 pData->options.oscPortUDP = value;
1971 break;
1972 #endif
1974 case ENGINE_OPTION_FILE_PATH:
1975 CARLA_SAFE_ASSERT_RETURN(value > FILE_NONE,);
1976 CARLA_SAFE_ASSERT_RETURN(value <= FILE_MIDI,);
1978 switch (value)
1980 case FILE_AUDIO:
1981 if (pData->options.pathAudio != nullptr)
1982 delete[] pData->options.pathAudio;
1983 if (valueStr != nullptr)
1984 pData->options.pathAudio = carla_strdup_safe(valueStr);
1985 else
1986 pData->options.pathAudio = nullptr;
1987 break;
1988 case FILE_MIDI:
1989 if (pData->options.pathMIDI != nullptr)
1990 delete[] pData->options.pathMIDI;
1991 if (valueStr != nullptr)
1992 pData->options.pathMIDI = carla_strdup_safe(valueStr);
1993 else
1994 pData->options.pathMIDI = nullptr;
1995 break;
1996 default:
1997 return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Invalid file type",
1998 option, EngineOption2Str(option), value, valueStr);
1999 break;
2001 break;
2002 case ENGINE_OPTION_PLUGIN_PATH:
2003 CARLA_SAFE_ASSERT_RETURN(value > PLUGIN_NONE,);
2004 CARLA_SAFE_ASSERT_RETURN(value <= PLUGIN_TYPE_COUNT,);
2006 switch (value)
2008 case PLUGIN_LADSPA:
2009 if (pData->options.pathLADSPA != nullptr)
2010 delete[] pData->options.pathLADSPA;
2011 if (valueStr != nullptr)
2012 pData->options.pathLADSPA = carla_strdup_safe(valueStr);
2013 else
2014 pData->options.pathLADSPA = nullptr;
2015 break;
2016 case PLUGIN_DSSI:
2017 if (pData->options.pathDSSI != nullptr)
2018 delete[] pData->options.pathDSSI;
2019 if (valueStr != nullptr)
2020 pData->options.pathDSSI = carla_strdup_safe(valueStr);
2021 else
2022 pData->options.pathDSSI = nullptr;
2023 break;
2024 case PLUGIN_LV2:
2025 if (pData->options.pathLV2 != nullptr)
2026 delete[] pData->options.pathLV2;
2027 if (valueStr != nullptr)
2028 pData->options.pathLV2 = carla_strdup_safe(valueStr);
2029 else
2030 pData->options.pathLV2 = nullptr;
2031 break;
2032 case PLUGIN_VST2:
2033 if (pData->options.pathVST2 != nullptr)
2034 delete[] pData->options.pathVST2;
2035 if (valueStr != nullptr)
2036 pData->options.pathVST2 = carla_strdup_safe(valueStr);
2037 else
2038 pData->options.pathVST2 = nullptr;
2039 break;
2040 case PLUGIN_VST3:
2041 if (pData->options.pathVST3 != nullptr)
2042 delete[] pData->options.pathVST3;
2043 if (valueStr != nullptr)
2044 pData->options.pathVST3 = carla_strdup_safe(valueStr);
2045 else
2046 pData->options.pathVST3 = nullptr;
2047 break;
2048 case PLUGIN_SF2:
2049 if (pData->options.pathSF2 != nullptr)
2050 delete[] pData->options.pathSF2;
2051 if (valueStr != nullptr)
2052 pData->options.pathSF2 = carla_strdup_safe(valueStr);
2053 else
2054 pData->options.pathSF2 = nullptr;
2055 break;
2056 case PLUGIN_SFZ:
2057 if (pData->options.pathSFZ != nullptr)
2058 delete[] pData->options.pathSFZ;
2059 if (valueStr != nullptr)
2060 pData->options.pathSFZ = carla_strdup_safe(valueStr);
2061 else
2062 pData->options.pathSFZ = nullptr;
2063 break;
2064 case PLUGIN_JSFX:
2065 if (pData->options.pathJSFX != nullptr)
2066 delete[] pData->options.pathJSFX;
2067 if (valueStr != nullptr)
2068 pData->options.pathJSFX = carla_strdup_safe(valueStr);
2069 else
2070 pData->options.pathJSFX = nullptr;
2071 break;
2072 case PLUGIN_CLAP:
2073 if (pData->options.pathCLAP != nullptr)
2074 delete[] pData->options.pathCLAP;
2075 if (valueStr != nullptr)
2076 pData->options.pathCLAP = carla_strdup_safe(valueStr);
2077 else
2078 pData->options.pathCLAP = nullptr;
2079 break;
2080 default:
2081 return carla_stderr("CarlaEngine::setOption(%i:%s, %i, \"%s\") - Invalid plugin type",
2082 option, EngineOption2Str(option), value, valueStr);
2083 break;
2085 break;
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);
2094 break;
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);
2103 break;
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);
2111 if (value != 0)
2113 CarlaString interposerPath(CarlaString(pData->options.binaryDir) + "/libcarla_interposer-safe.so");
2114 ::setenv("LD_PRELOAD", interposerPath.buffer(), 1);
2116 else
2118 ::unsetenv("LD_PRELOAD");
2120 #endif
2121 } break;
2123 case ENGINE_OPTION_FRONTEND_BACKGROUND_COLOR:
2124 pData->options.bgColor = static_cast<uint>(value);
2125 break;
2127 case ENGINE_OPTION_FRONTEND_FOREGROUND_COLOR:
2128 pData->options.fgColor = static_cast<uint>(value);
2129 break;
2131 case ENGINE_OPTION_FRONTEND_UI_SCALE:
2132 CARLA_SAFE_ASSERT_RETURN(value > 0,);
2133 pData->options.uiScale = static_cast<float>(value) / 1000;
2134 break;
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);
2141 } break;
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);
2151 break;
2153 case ENGINE_OPTION_WINE_AUTO_PREFIX:
2154 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
2155 pData->options.wine.autoPrefix = (value != 0);
2156 break;
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);
2165 break;
2167 case ENGINE_OPTION_WINE_RT_PRIO_ENABLED:
2168 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
2169 pData->options.wine.rtPrio = (value != 0);
2170 break;
2172 case ENGINE_OPTION_WINE_BASE_RT_PRIO:
2173 CARLA_SAFE_ASSERT_RETURN(value >= 1 && value <= 89,);
2174 pData->options.wine.baseRtPrio = value;
2175 break;
2177 case ENGINE_OPTION_WINE_SERVER_RT_PRIO:
2178 CARLA_SAFE_ASSERT_RETURN(value >= 1 && value <= 99,);
2179 pData->options.wine.serverRtPrio = value;
2180 break;
2181 #endif
2183 #ifndef BUILD_BRIDGE
2184 case ENGINE_OPTION_DEBUG_CONSOLE_OUTPUT:
2185 break;
2186 #endif
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)
2194 : nullptr;
2195 break;
2197 case ENGINE_OPTION_PLUGINS_ARE_STANDALONE:
2198 CARLA_SAFE_ASSERT_RETURN(value == 0 || value == 1,);
2199 pData->options.pluginsAreStandalone = (value != 0);
2200 break;
2204 #ifndef BUILD_BRIDGE
2205 // -----------------------------------------------------------------------
2206 // OSC Stuff
2208 bool CarlaEngine::isOscControlRegistered() const noexcept
2210 # ifdef HAVE_LIBLO
2211 return pData->osc.isControlRegisteredForTCP();
2212 # else
2213 return false;
2214 # endif
2217 const char* CarlaEngine::getOscServerPathTCP() const noexcept
2219 # ifdef HAVE_LIBLO
2220 return pData->osc.getServerPathTCP();
2221 # else
2222 return nullptr;
2223 # endif
2226 const char* CarlaEngine::getOscServerPathUDP() const noexcept
2228 # ifdef HAVE_LIBLO
2229 return pData->osc.getServerPathUDP();
2230 # else
2231 return nullptr;
2232 # endif
2234 #endif
2236 // -----------------------------------------------------------------------
2237 // Internal stuff
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);
2249 #endif
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);
2260 plugin->unlock();
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);
2278 #endif
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);
2289 plugin->unlock();
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);
2307 #endif
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);
2340 #endif
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'";
2353 #endif
2355 outStream << ">\n";
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";
2373 if (isPlugin)
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);
2413 outPlugin << "\n";
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)
2438 uint posCount = 0;
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";
2484 if (ppos.dealloc)
2485 delete[] ppos.name;
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;
2502 /**/ if (isPlugin)
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;
2515 else
2517 saveExternalConnections = true;
2520 if (saveExternalConnections || saveExternalPositions)
2522 uint posCount = 0;
2523 const char* const* const patchbayConns = saveExternalConnections
2524 ? getPatchbayConnections(true)
2525 : nullptr;
2526 const PatchbayPosition* const patchbayPos = saveExternalPositions
2527 ? getPatchbayPositions(true, posCount)
2528 : nullptr;
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";
2572 if (ppos.dealloc)
2573 delete[] ppos.name;
2576 outPatchbay << " </Positions>\n";
2579 outPatchbay << " </ExternalPatchbay>\n";
2580 outStream << outPatchbay;
2583 #endif
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
2596 #ifdef CARLA_OS_WIN
2597 if (jbinary[0] == '/')
2598 jbinary = "C:" + jbinary.replaceCharacter('/', '\\');
2599 #else
2600 if (jbinary[1] == ':' && (jbinary[2] == '\\' || jbinary[2] == '/'))
2601 jbinary = jbinary.substring(2).replaceCharacter('\\', '/');
2602 #endif
2604 String filename = File(jbinary.toRawUTF8()).getFileName();
2606 int searchFlags = File::findFiles|File::ignoreHiddenFiles;
2608 if (filename.endsWithIgnoreCase(".vst3"))
2609 searchFlags |= File::findDirectories;
2610 #ifdef CARLA_OS_MAC
2611 else if (filename.endsWithIgnoreCase(".vst"))
2612 searchFlags |= File::findDirectories;
2613 #endif
2615 std::vector<File> results;
2616 for (const String *it=searchPaths.begin(), *end=searchPaths.end(); it != end; ++it)
2618 const File path(it->toRawUTF8());
2620 results.clear();
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";
2634 #else
2635 if (filename.endsWithIgnoreCase(".dll") || filename.endsWithIgnoreCase(".dylib"))
2636 filename = File(jbinary.toRawUTF8()).getFileNameWithoutExtension() + ".so";
2637 #endif
2638 else
2639 return String();
2641 for (const String *it=searchPaths.begin(), *end=searchPaths.end(); it != end; ++it)
2643 const File path(it->toRawUTF8());
2645 results.clear();
2646 path.findChildFiles(results, searchFlags, true, filename.toRawUTF8());
2648 if (!results.empty())
2649 return results.front().getFullPathName();
2652 return String();
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");
2669 return false;
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);
2688 #endif
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)
2695 return true;
2697 if (pData->actionCanceled)
2699 setLastError("Project load canceled");
2700 return false;
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;
2708 #endif
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 */
2722 int option = -1;
2723 int value = 0;
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();
2756 else if (isPlugin)
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;
2773 value = PLUGIN_LV2;
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;
2791 value = PLUGIN_SF2;
2792 valueStr = text.toRawUTF8();
2794 else if (tag == "SFZ_PATH")
2796 option = ENGINE_OPTION_PLUGIN_PATH;
2797 value = PLUGIN_SFZ;
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();
2814 if (option == -1)
2816 // check old stuff, unhandled now
2817 if (tag == "GIG_PATH")
2818 continue;
2819 // ignored tags
2820 if (tag == "LADSPA_PATH" || tag == "DSSI_PATH" || tag == "LV2_PATH" || tag == "VST2_PATH")
2821 continue;
2822 if (tag == "VST3_PATH" || tag == "AU_PATH")
2823 continue;
2824 if (tag == "SF2_PATH" || tag == "SFZ_PATH" || tag == "JSFX_PATH" || tag == "CLAP_PATH")
2825 continue;
2827 // hmm something is wrong..
2828 carla_stderr2("CarlaEngine::loadProjectInternal() - Unhandled option '%s'", tag.toRawUTF8());
2829 continue;
2832 setOption(static_cast<EngineOption>(option), value, valueStr);
2835 if (pData->aboutToClose)
2836 return true;
2838 if (pData->actionCanceled)
2840 setLastError("Project load canceled");
2841 return false;
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();
2853 // some sane limits
2854 if (bpm >= 20.0 && bpm < 400.0)
2855 pData->time.setBPM(bpm);
2857 if (pData->aboutToClose)
2858 return true;
2860 if (pData->actionCanceled)
2862 setLastError("Project load canceled");
2863 return false;
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)
2879 return true;
2881 if (pData->actionCanceled)
2883 setLastError("Project load canceled");
2884 return false;
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)
2901 return true;
2903 if (pData->actionCanceled)
2905 setLastError("Project load canceled");
2906 return false;
2909 String lsState;
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(),
2931 0, 0, 0.0f,
2932 plugin->getName());
2934 if (isPatchbay)
2935 pData->graph.addPlugin(plugin);
2937 else
2939 carla_stderr2("Failed to get new plugin, state will not be restored correctly\n");
2942 else
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);
2948 continue;
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)
2960 return true;
2962 if (pData->actionCanceled)
2964 setLastError("Project load canceled");
2965 return false;
2968 plugin->setCustomData(LV2_ATOM__Path,
2969 "http://sfztools.github.io/sfizz:sfzfile",
2970 stateSave.binary,
2971 false);
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(),
2986 0, 0, 0.0f,
2987 plugin->getName());
2989 if (isPatchbay)
2990 pData->graph.addPlugin(plugin);
2992 else
2994 carla_stderr2("Failed to get new plugin, state will not be restored correctly\n");
2997 else
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);
3003 continue;
3005 #endif
3006 #endif
3008 const void* extraStuff = nullptr;
3009 static const char kTrue[] = "true";
3011 const PluginType ptype = getPluginTypeFromString(stateSave.type);
3013 switch (ptype)
3015 case PLUGIN_SF2:
3016 if (CarlaString(stateSave.label).endsWith(" (16 outs)"))
3017 extraStuff = kTrue;
3018 // fall through
3019 case PLUGIN_LADSPA:
3020 case PLUGIN_DSSI:
3021 case PLUGIN_VST2:
3022 case PLUGIN_VST3:
3023 case PLUGIN_SFZ:
3024 case PLUGIN_JSFX:
3025 case PLUGIN_CLAP:
3026 if (stateSave.binary != nullptr && stateSave.binary[0] != '\0' &&
3027 ! (File::isAbsolutePath(stateSave.binary) && File(stateSave.binary).exists()))
3029 const char* searchPath;
3031 switch (ptype)
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...",
3047 stateSave.binary);
3049 String result = findBinaryInCustomPath(searchPath, stateSave.binary);
3051 if (result.isEmpty())
3053 switch (ptype)
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! :)");
3076 else
3078 carla_stderr("Damn, we failed... :(");
3081 callback(true, true, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);
3084 break;
3085 default:
3086 break;
3089 BinaryType btype;
3091 switch (ptype)
3093 case PLUGIN_LADSPA:
3094 case PLUGIN_DSSI:
3095 case PLUGIN_LV2:
3096 case PLUGIN_VST2:
3097 case PLUGIN_VST3:
3098 case PLUGIN_CLAP:
3099 case PLUGIN_AU:
3100 btype = getBinaryTypeFromFile(stateSave.binary);
3101 break;
3102 default:
3103 btype = BINARY_NATIVE;
3104 break;
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;
3112 #else
3113 const uint pluginId = 0;
3114 #endif
3116 if (const CarlaPluginPtr plugin = pData->plugins[pluginId].plugin)
3118 if (pData->aboutToClose)
3119 return true;
3121 if (pData->actionCanceled)
3123 setLastError("Project load canceled");
3124 return false;
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(),
3141 0, 0, 0.0f,
3142 plugin->getName());
3144 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
3145 if (isPatchbay)
3146 pData->graph.addPlugin(plugin);
3147 #endif
3149 else
3151 carla_stderr2("Failed to get new plugin, state will not be restored correctly\n");
3154 else
3156 carla_stderr2("Failed to load a plugin '%s', error was:\n%s", stateSave.name, getLastError());
3159 if (! isPreset)
3160 callback(true, true, ENGINE_CALLBACK_IDLE, 0, 0, 0, 0, 0.0f, nullptr);
3163 if (isPreset)
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");
3167 return true;
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)
3181 return true;
3183 if (pData->actionCanceled)
3185 setLastError("Project load canceled");
3186 return false;
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"))
3201 String name;
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")
3209 continue;
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;
3235 else
3236 mapGroupNamesInternal[name] = ppos.name;
3239 if (ppos.dealloc)
3240 std::free(const_cast<char*>(ppos.name));
3244 if (pData->aboutToClose)
3245 return true;
3247 if (pData->actionCanceled)
3249 setLastError("Project load canceled");
3250 return false;
3255 if (XmlElement* const elemPatchbay = xmlElement->getChildByName("ExternalPatchbay"))
3257 if (XmlElement* const elemPositions = elemPatchbay->getChildByName("Positions"))
3259 String name;
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")
3267 continue;
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;
3297 else
3298 mapGroupNamesInternal[name] = ppos.name;
3301 if (ppos.dealloc)
3302 std::free(const_cast<char*>(ppos.name));
3306 if (pData->aboutToClose)
3307 return true;
3309 if (pData->actionCanceled)
3311 setLastError("Project load canceled");
3312 return false;
3317 bool hasInternalConnections = false;
3319 // and now we handle connections (internal)
3320 if (XmlElement* const elem = xmlElement->getChildByName("Patchbay"))
3322 hasInternalConnections = true;
3324 if (isPatchbay)
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")
3333 continue;
3335 sourcePort.clear();
3336 targetPort.clear();
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)
3364 return true;
3366 if (pData->actionCanceled)
3368 setLastError("Project load canceled");
3369 return false;
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;
3381 else
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;
3391 else
3392 loadExternalConnections = true;
3395 // plus external connections too
3396 if (loadExternalConnections)
3398 bool isExternal;
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")
3409 if (isPatchbay)
3410 continue;
3411 isExternal = false;
3412 loadingAsExternal = true;
3414 // or load external patchbay connections
3415 else if (tagName == "ExternalPatchbay")
3417 if (! isPatchbay)
3418 loadingAsExternal = true;
3419 isExternal = true;
3421 else
3423 continue;
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")
3433 continue;
3435 sourcePort.clear();
3436 targetPort.clear();
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";
3467 else
3468 continue;
3470 else
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";
3489 else
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";
3511 else
3512 continue;
3514 else
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";
3531 else
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());
3546 break;
3549 #endif
3551 if (pData->options.resetXruns)
3552 clearXruns();
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));
3558 return true;
3560 #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
3561 // unused
3562 (void)alwaysLoadConnections;
3563 #endif
3566 // -----------------------------------------------------------------------
3568 CARLA_BACKEND_END_NAMESPACE