Cleanup
[carla.git] / source / backend / plugin / CarlaPlugin.cpp
blob6854395b5bd6e0ffc59b1479ccae9478f1871e54
1 // SPDX-FileCopyrightText: 2011-2024 Filipe Coelho <falktx@falktx.com>
2 // SPDX-License-Identifier: GPL-2.0-or-later
4 #include "CarlaPluginInternal.hpp"
5 #include "CarlaEngine.hpp"
7 #include "CarlaBackendUtils.hpp"
8 #include "CarlaBase64Utils.hpp"
9 #include "CarlaMathUtils.hpp"
10 #include "CarlaMIDI.h"
11 #include "CarlaPluginUI.hpp"
12 #include "CarlaScopeUtils.hpp"
13 #include "CarlaStringList.hpp"
15 #include <ctime>
17 #include "water/files/File.h"
18 #include "water/streams/MemoryOutputStream.h"
19 #include "water/xml/XmlDocument.h"
20 #include "water/xml/XmlElement.h"
22 using water::CharPointer_UTF8;
23 using water::File;
24 using water::MemoryOutputStream;
25 using water::Result;
26 using water::String;
27 using water::XmlDocument;
28 using water::XmlElement;
30 CARLA_BACKEND_START_NAMESPACE
32 // -------------------------------------------------------------------------------------------------------------------
33 // Fallback data
35 static const ParameterData kParameterDataNull = { PARAMETER_UNKNOWN, 0x0, PARAMETER_NULL, -1, 0, CONTROL_INDEX_NONE, 0.0f, 1.0f, 0x0 };
36 static const ParameterRanges kParameterRangesNull = { 0.0f, 0.0f, 1.0f, 0.01f, 0.0001f, 0.1f };
37 static const MidiProgramData kMidiProgramDataNull = { 0, 0, nullptr };
39 static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr };
40 static /* */ CustomData kCustomDataFallbackNC = { nullptr, nullptr, nullptr };
41 static const PluginPostRtEvent kPluginPostRtEventFallback = { kPluginPostRtEventNull, false, {} };
43 // -------------------------------------------------------------------------------------------------------------------
44 // ParamSymbol struct, needed for CarlaPlugin::loadStateSave()
46 struct ParamSymbol {
47 int32_t index;
48 const char* symbol;
50 ParamSymbol(const uint32_t i, const char* const s)
51 : index(static_cast<int32_t>(i)),
52 symbol(carla_strdup(s)) {}
54 ~ParamSymbol() noexcept
56 CARLA_SAFE_ASSERT_RETURN(symbol != nullptr,)
58 delete[] symbol;
59 symbol = nullptr;
62 #ifdef CARLA_PROPER_CPP11_SUPPORT
63 ParamSymbol() = delete;
64 CARLA_DECLARE_NON_COPYABLE(ParamSymbol)
65 #endif
68 // -------------------------------------------------------------------------------------------------------------------
69 // Constructor and destructor
71 CarlaPlugin::CarlaPlugin(CarlaEngine* const engine, const uint id)
72 : pData(new ProtectedData(engine, id))
74 CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
75 CARLA_SAFE_ASSERT(id < engine->getMaxPluginNumber());
76 carla_debug("CarlaPlugin::CarlaPlugin(%p, %i)", engine, id);
78 switch (engine->getProccessMode())
80 case ENGINE_PROCESS_MODE_SINGLE_CLIENT:
81 case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
82 CARLA_SAFE_ASSERT(id < MAX_DEFAULT_PLUGINS);
83 break;
85 case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
86 CARLA_SAFE_ASSERT(id < MAX_RACK_PLUGINS);
87 break;
89 case ENGINE_PROCESS_MODE_PATCHBAY:
90 CARLA_SAFE_ASSERT(id < MAX_PATCHBAY_PLUGINS);
91 break;
93 case ENGINE_PROCESS_MODE_BRIDGE:
94 CARLA_SAFE_ASSERT(id == 0);
95 break;
99 CarlaPlugin::~CarlaPlugin()
101 carla_debug("CarlaPlugin::~CarlaPlugin()");
103 delete pData;
106 // -------------------------------------------------------------------
107 // Information (base)
109 uint CarlaPlugin::getId() const noexcept
111 return pData->id;
114 uint CarlaPlugin::getHints() const noexcept
116 return pData->hints;
119 uint CarlaPlugin::getOptionsEnabled() const noexcept
121 return pData->options;
124 bool CarlaPlugin::isEnabled() const noexcept
126 return pData->enabled;
129 const char* CarlaPlugin::getName() const noexcept
131 return pData->name;
134 const char* CarlaPlugin::getFilename() const noexcept
136 return pData->filename;
139 const char* CarlaPlugin::getIconName() const noexcept
141 return pData->iconName;
144 PluginCategory CarlaPlugin::getCategory() const noexcept
146 return getPluginCategoryFromName(pData->name);
149 int64_t CarlaPlugin::getUniqueId() const noexcept
151 return 0;
154 uint32_t CarlaPlugin::getLatencyInFrames() const noexcept
156 return 0;
159 // -------------------------------------------------------------------
160 // Information (count)
162 uint32_t CarlaPlugin::getAudioInCount() const noexcept
164 return pData->audioIn.count;
167 uint32_t CarlaPlugin::getAudioOutCount() const noexcept
169 return pData->audioOut.count;
172 uint32_t CarlaPlugin::getCVInCount() const noexcept
174 return pData->cvIn.count;
177 uint32_t CarlaPlugin::getCVOutCount() const noexcept
179 return pData->cvOut.count;
182 uint32_t CarlaPlugin::getMidiInCount() const noexcept
184 return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_IN) ? 1 : 0;
187 uint32_t CarlaPlugin::getMidiOutCount() const noexcept
189 return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_OUT) ? 1 : 0;
192 uint32_t CarlaPlugin::getParameterCount() const noexcept
194 return pData->param.count;
197 uint32_t CarlaPlugin::getParameterScalePointCount(const uint32_t parameterId) const noexcept
199 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0);
200 return 0;
203 uint32_t CarlaPlugin::getProgramCount() const noexcept
205 return pData->prog.count;
208 uint32_t CarlaPlugin::getMidiProgramCount() const noexcept
210 return pData->midiprog.count;
213 uint32_t CarlaPlugin::getCustomDataCount() const noexcept
215 return static_cast<uint32_t>(pData->custom.count());
218 // -------------------------------------------------------------------
219 // Information (current data)
221 int32_t CarlaPlugin::getCurrentProgram() const noexcept
223 return pData->prog.current;
226 int32_t CarlaPlugin::getCurrentMidiProgram() const noexcept
228 return pData->midiprog.current;
231 uint CarlaPlugin::getAudioPortHints(bool, uint32_t) const noexcept
233 return 0x0;
236 const ParameterData& CarlaPlugin::getParameterData(const uint32_t parameterId) const noexcept
238 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterDataNull);
239 return pData->param.data[parameterId];
242 const ParameterRanges& CarlaPlugin::getParameterRanges(const uint32_t parameterId) const noexcept
244 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterRangesNull);
245 return pData->param.ranges[parameterId];
248 bool CarlaPlugin::isParameterOutput(const uint32_t parameterId) const noexcept
250 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
251 return (pData->param.data[parameterId].type == PARAMETER_OUTPUT);
254 const MidiProgramData& CarlaPlugin::getMidiProgramData(const uint32_t index) const noexcept
256 CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, kMidiProgramDataNull);
257 return pData->midiprog.data[index];
260 const CustomData& CarlaPlugin::getCustomData(const uint32_t index) const noexcept
262 return pData->custom.getAt(index, kCustomDataFallback);
265 std::size_t CarlaPlugin::getChunkData(void** const dataPtr) noexcept
267 CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0);
268 CARLA_SAFE_ASSERT(false); // this should never happen
269 return 0;
272 // -------------------------------------------------------------------
273 // Information (per-plugin data)
275 uint CarlaPlugin::getOptionsAvailable() const noexcept
277 CARLA_SAFE_ASSERT(false); // this should never happen
278 return 0x0;
281 float CarlaPlugin::getParameterValue(const uint32_t parameterId) const noexcept
283 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
284 CARLA_SAFE_ASSERT(false); // this should never happen
285 return 0.0f;
288 float CarlaPlugin::getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) const noexcept
290 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
291 CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), 0.0f);
292 CARLA_SAFE_ASSERT(false); // this should never happen
293 return 0.0f;
296 bool CarlaPlugin::getLabel(char* const strBuf) const noexcept
298 strBuf[0] = '\0';
299 return false;
302 bool CarlaPlugin::getMaker(char* const strBuf) const noexcept
304 strBuf[0] = '\0';
305 return false;
308 bool CarlaPlugin::getCopyright(char* const strBuf) const noexcept
310 strBuf[0] = '\0';
311 return false;
314 bool CarlaPlugin::getRealName(char* const strBuf) const noexcept
316 strBuf[0] = '\0';
317 return false;
320 bool CarlaPlugin::getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept
322 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
323 CARLA_SAFE_ASSERT(false); // this should never happen
324 strBuf[0] = '\0';
325 return false;
328 bool CarlaPlugin::getParameterSymbol(const uint32_t parameterId, char* const strBuf) const noexcept
330 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
331 strBuf[0] = '\0';
332 return false;
335 bool CarlaPlugin::getParameterText(const uint32_t parameterId, char* const strBuf) noexcept
337 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
338 CARLA_SAFE_ASSERT(false); // this should never happen
339 strBuf[0] = '\0';
340 return false;
343 bool CarlaPlugin::getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept
345 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
346 strBuf[0] = '\0';
347 return false;
350 bool CarlaPlugin::getParameterComment(const uint32_t parameterId, char* const strBuf) const noexcept
352 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
353 strBuf[0] = '\0';
354 return false;
357 bool CarlaPlugin::getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept
359 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
360 strBuf[0] = '\0';
361 return false;
364 bool CarlaPlugin::getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) const noexcept
366 CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
367 CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), false);
368 CARLA_SAFE_ASSERT(false); // this should never happen
369 strBuf[0] = '\0';
370 return false;
373 float CarlaPlugin::getInternalParameterValue(const int32_t parameterId) const noexcept
375 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
376 CARLA_SAFE_ASSERT_RETURN(parameterId != PARAMETER_NULL && parameterId > PARAMETER_MAX, 0.0f);
378 switch (parameterId)
380 case PARAMETER_ACTIVE:
381 return pData->active;
382 case PARAMETER_CTRL_CHANNEL:
383 return pData->ctrlChannel;
384 case PARAMETER_DRYWET:
385 return pData->postProc.dryWet;
386 case PARAMETER_VOLUME:
387 return pData->postProc.volume;
388 case PARAMETER_BALANCE_LEFT:
389 return pData->postProc.balanceLeft;
390 case PARAMETER_BALANCE_RIGHT:
391 return pData->postProc.balanceRight;
392 case PARAMETER_PANNING:
393 return pData->postProc.panning;
395 #endif
396 CARLA_SAFE_ASSERT_RETURN(parameterId >= 0, 0.0f);
398 return getParameterValue(static_cast<uint32_t>(parameterId));
401 bool CarlaPlugin::getProgramName(const uint32_t index, char* const strBuf) const noexcept
403 CARLA_SAFE_ASSERT_RETURN(index < pData->prog.count, false);
404 CARLA_SAFE_ASSERT_RETURN(pData->prog.names[index] != nullptr, false);
405 std::strncpy(strBuf, pData->prog.names[index], STR_MAX);
406 return true;
409 bool CarlaPlugin::getMidiProgramName(const uint32_t index, char* const strBuf) const noexcept
411 CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, false);
412 CARLA_SAFE_ASSERT_RETURN(pData->midiprog.data[index].name != nullptr, false);
413 std::strncpy(strBuf, pData->midiprog.data[index].name, STR_MAX);
414 return true;
417 void CarlaPlugin::getParameterCountInfo(uint32_t& ins, uint32_t& outs) const noexcept
419 ins = 0;
420 outs = 0;
422 for (uint32_t i=0; i < pData->param.count; ++i)
424 if (pData->param.data[i].type == PARAMETER_INPUT)
425 ++ins;
426 else if (pData->param.data[i].type == PARAMETER_OUTPUT)
427 ++outs;
431 // -------------------------------------------------------------------
432 // Set data (state)
434 void CarlaPlugin::prepareForSave(bool)
438 void CarlaPlugin::resetParameters() noexcept
440 for (uint i=0; i < pData->param.count; ++i)
442 const ParameterData& paramData(pData->param.data[i]);
443 const ParameterRanges& paramRanges(pData->param.ranges[i]);
445 if (paramData.type != PARAMETER_INPUT)
446 continue;
447 if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
448 continue;
450 setParameterValue(i, paramRanges.def, true, true, true);
454 void CarlaPlugin::randomizeParameters() noexcept
456 float value, random;
458 char strBuf[STR_MAX+1];
459 strBuf[STR_MAX] = '\0';
461 std::srand(static_cast<uint>(std::time(nullptr)));
463 for (uint i=0; i < pData->param.count; ++i)
465 const ParameterData& paramData(pData->param.data[i]);
467 if (paramData.type != PARAMETER_INPUT)
468 continue;
469 if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
470 continue;
472 if (! getParameterName(i, strBuf))
473 strBuf[0] = '\0';
475 if (std::strstr(strBuf, "olume") != nullptr)
476 continue;
477 if (std::strstr(strBuf, "Master") != nullptr)
478 continue;
480 const ParameterRanges& paramRanges(pData->param.ranges[i]);
482 if (paramData.hints & PARAMETER_IS_BOOLEAN)
484 random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
485 value = random > 0.5f ? paramRanges.max : paramRanges.min;
487 else
489 random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
490 value = random * (paramRanges.max - paramRanges.min) + paramRanges.min;
492 if (paramData.hints & PARAMETER_IS_INTEGER)
493 value = std::rint(value);
496 setParameterValue(i, value, true, true, true);
500 const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave)
502 pData->stateSave.clear();
504 if (callPrepareForSave)
506 pData->stateSave.temporary = true;
507 prepareForSave(true);
510 const PluginType pluginType = getType();
512 char strBuf[STR_MAX+1];
513 carla_zeroChars(strBuf, STR_MAX+1);
515 // ---------------------------------------------------------------
516 // Basic info
518 if (! getLabel(strBuf))
519 strBuf[0] = '\0';
521 pData->stateSave.type = carla_strdup(getPluginTypeAsString(pluginType));
522 pData->stateSave.name = carla_strdup(pData->name);
523 pData->stateSave.label = carla_strdup(strBuf);
524 pData->stateSave.uniqueId = getUniqueId();
525 // #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
526 pData->stateSave.options = pData->options;
527 // #endif
529 if (pData->filename != nullptr)
530 pData->stateSave.binary = carla_strdup(pData->filename);
532 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
533 // ---------------------------------------------------------------
534 // Internals
536 pData->stateSave.active = pData->active;
537 pData->stateSave.dryWet = pData->postProc.dryWet;
538 pData->stateSave.volume = pData->postProc.volume;
539 pData->stateSave.balanceLeft = pData->postProc.balanceLeft;
540 pData->stateSave.balanceRight = pData->postProc.balanceRight;
541 pData->stateSave.panning = pData->postProc.panning;
542 pData->stateSave.ctrlChannel = pData->ctrlChannel;
543 #endif
545 if (pData->hints & PLUGIN_IS_BRIDGE)
546 waitForBridgeSaveSignal();
548 // ---------------------------------------------------------------
549 // Chunk
551 bool usingChunk = false;
553 if (pData->options & PLUGIN_OPTION_USE_CHUNKS)
555 void* data = nullptr;
556 const std::size_t dataSize = getChunkData(&data);
558 if (data != nullptr && dataSize > 0)
560 pData->stateSave.chunk = CarlaString::asBase64(data, dataSize).dup();
562 if (pluginType != PLUGIN_INTERNAL && pluginType != PLUGIN_JSFX)
563 usingChunk = true;
567 // ---------------------------------------------------------------
568 // Current Program
570 if (pData->prog.current >= 0 && pluginType != PLUGIN_LV2)
572 pData->stateSave.currentProgramIndex = pData->prog.current;
573 pData->stateSave.currentProgramName = carla_strdup(pData->prog.names[pData->prog.current]);
576 // ---------------------------------------------------------------
577 // Current MIDI Program
579 if (pData->midiprog.current >= 0 && pluginType != PLUGIN_LV2 && pluginType != PLUGIN_SF2)
581 const MidiProgramData& mpData(pData->midiprog.getCurrent());
583 pData->stateSave.currentMidiBank = static_cast<int32_t>(mpData.bank);
584 pData->stateSave.currentMidiProgram = static_cast<int32_t>(mpData.program);
587 // ---------------------------------------------------------------
588 // Parameters
590 const float sampleRate = static_cast<float>(pData->engine->getSampleRate());
592 for (uint32_t i=0; i < pData->param.count; ++i)
594 const ParameterData& paramData(pData->param.data[i]);
596 if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
597 continue;
598 if (paramData.hints & PARAMETER_IS_NOT_SAVED)
599 continue;
601 const bool dummy = paramData.type != PARAMETER_INPUT || usingChunk;
603 if (dummy && paramData.mappedControlIndex <= CONTROL_INDEX_NONE)
604 continue;
606 CarlaStateSave::Parameter* const stateParameter(new CarlaStateSave::Parameter());
608 stateParameter->dummy = dummy;
609 stateParameter->index = paramData.index;
610 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
611 if (paramData.mappedControlIndex != CONTROL_INDEX_MIDI_LEARN)
613 stateParameter->mappedControlIndex = paramData.mappedControlIndex;
614 stateParameter->midiChannel = paramData.midiChannel;
616 if (paramData.hints & PARAMETER_MAPPED_RANGES_SET)
618 stateParameter->mappedMinimum = paramData.mappedMinimum;
619 stateParameter->mappedMaximum = paramData.mappedMaximum;
620 stateParameter->mappedRangeValid = true;
622 if (paramData.hints & PARAMETER_USES_SAMPLERATE)
624 stateParameter->mappedMinimum /= sampleRate;
625 stateParameter->mappedMaximum /= sampleRate;
629 #endif
631 if (! getParameterName(i, strBuf))
632 strBuf[0] = '\0';
633 stateParameter->name = carla_strdup(strBuf);
635 if (! getParameterSymbol(i, strBuf))
636 strBuf[0] = '\0';
637 stateParameter->symbol = carla_strdup(strBuf);;
639 if (! dummy)
641 stateParameter->value = getParameterValue(i);
643 if (paramData.hints & PARAMETER_USES_SAMPLERATE)
644 stateParameter->value /= sampleRate;
647 pData->stateSave.parameters.append(stateParameter);
650 // ---------------------------------------------------------------
651 // Custom Data
653 for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
655 const CustomData& cData(it.getValue(kCustomDataFallback));
656 CARLA_SAFE_ASSERT_CONTINUE(cData.isValid());
658 CarlaStateSave::CustomData* stateCustomData(new CarlaStateSave::CustomData());
660 stateCustomData->type = carla_strdup(cData.type);
661 stateCustomData->key = carla_strdup(cData.key);
662 stateCustomData->value = carla_strdup(cData.value);
664 pData->stateSave.customData.append(stateCustomData);
667 return pData->stateSave;
670 void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave)
672 const bool usesMultiProgs = pData->hints & PLUGIN_USES_MULTI_PROGS;
673 const PluginType pluginType = getType();
675 char strBuf[STR_MAX+1];
676 carla_zeroChars(strBuf, STR_MAX+1);
678 // ---------------------------------------------------------------
679 // Part 1 - PRE-set custom data (only those which reload programs)
681 for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
683 const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
684 CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
685 CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
687 const char* const key(stateCustomData->key);
689 /**/ if (pluginType == PLUGIN_DSSI && (std::strcmp (key, "reloadprograms") == 0 ||
690 std::strcmp (key, "load" ) == 0 ||
691 std::strncmp(key, "patches", 7) == 0 ))
692 pass();
693 else if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0)
694 pass();
695 else
696 continue;
698 setCustomData(stateCustomData->type, key, stateCustomData->value, true);
701 // ---------------------------------------------------------------
702 // Part 2 - set program
704 if (stateSave.currentProgramIndex >= 0 && stateSave.currentProgramName != nullptr)
706 int32_t programId = -1;
708 // index < count
709 if (stateSave.currentProgramIndex < static_cast<int32_t>(pData->prog.count))
711 programId = stateSave.currentProgramIndex;
713 // index not valid, try to find by name
714 else
716 for (uint32_t i=0; i < pData->prog.count; ++i)
718 if (getProgramName(i, strBuf) && std::strcmp(stateSave.currentProgramName, strBuf) == 0)
720 programId = static_cast<int32_t>(i);
721 break;
726 // set program now, if valid
727 if (programId >= 0)
728 setProgram(programId, true, true, true);
731 // ---------------------------------------------------------------
732 // Part 3 - set midi program
734 if (stateSave.currentMidiBank >= 0 && stateSave.currentMidiProgram >= 0 && ! usesMultiProgs)
735 setMidiProgramById(static_cast<uint32_t>(stateSave.currentMidiBank), static_cast<uint32_t>(stateSave.currentMidiProgram), true, true, true);
737 // ---------------------------------------------------------------
738 // Part 4a - get plugin parameter symbols
740 LinkedList<ParamSymbol*> paramSymbols;
742 if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2 || pluginType == PLUGIN_CLAP)
744 for (uint32_t i=0; i < pData->param.count; ++i)
746 if (pData->param.data[i].hints & PARAMETER_IS_NOT_SAVED)
747 continue;
749 if (getParameterSymbol(i, strBuf))
751 ParamSymbol* const paramSymbol(new ParamSymbol(i, strBuf));
752 paramSymbols.append(paramSymbol);
757 // ---------------------------------------------------------------
758 // Part 4b - set parameter values (carefully)
760 const float sampleRate = static_cast<float>(pData->engine->getSampleRate());
762 for (CarlaStateSave::ParameterItenerator it = stateSave.parameters.begin2(); it.valid(); it.next())
764 CarlaStateSave::Parameter* const stateParameter(it.getValue(nullptr));
765 CARLA_SAFE_ASSERT_CONTINUE(stateParameter != nullptr);
767 int32_t index = -1;
769 if (pluginType == PLUGIN_LADSPA)
771 // Try to set by symbol, otherwise use index
772 if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
774 for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
776 ParamSymbol* const paramSymbol(it2.getValue(nullptr));
777 CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
778 CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
780 if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
782 index = paramSymbol->index;
783 break;
786 if (index == -1)
787 index = stateParameter->index;
789 else
791 index = stateParameter->index;
794 else if (pluginType == PLUGIN_LV2 || pluginType == PLUGIN_CLAP)
796 // Symbol only
797 if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
799 for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
801 ParamSymbol* const paramSymbol(it2.getValue(nullptr));
802 CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
803 CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
805 if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
807 index = paramSymbol->index;
808 break;
811 if (index == -1)
813 if (pluginType == PLUGIN_LV2)
814 carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'",
815 stateParameter->symbol, pData->name);
816 else
817 carla_stderr("Failed to find CLAP parameter id '%s' for '%s'",
818 stateParameter->symbol, pData->name);
821 else
823 if (pluginType == PLUGIN_LV2)
824 carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name);
825 else
826 carla_stderr("CLAP Plugin parameter '%s' has no id", stateParameter->name);
829 else
831 // Index only
832 index = stateParameter->index;
835 // Now set parameter
836 if (index >= 0 && index < static_cast<int32_t>(pData->param.count))
838 //CARLA_SAFE_ASSERT(stateParameter->isInput == (pData
840 if (! stateParameter->dummy)
842 if (pData->param.data[index].hints & PARAMETER_USES_SAMPLERATE)
843 stateParameter->value *= sampleRate;
845 setParameterValue(static_cast<uint32_t>(index), stateParameter->value, true, true, true);
848 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
849 if (stateParameter->mappedRangeValid)
851 if (pData->param.data[index].hints & PARAMETER_USES_SAMPLERATE)
853 stateParameter->mappedMinimum *= sampleRate;
854 stateParameter->mappedMaximum *= sampleRate;
857 setParameterMappedRange(static_cast<uint32_t>(index),
858 stateParameter->mappedMinimum,
859 stateParameter->mappedMaximum, true, true);
862 setParameterMappedControlIndex(static_cast<uint32_t>(index),
863 stateParameter->mappedControlIndex, true, true, false);
864 setParameterMidiChannel(static_cast<uint32_t>(index), stateParameter->midiChannel, true, true);
865 #endif
867 else
868 carla_stderr("Could not set parameter '%s' value for '%s'",
869 stateParameter->name, pData->name);
872 // ---------------------------------------------------------------
873 // Part 4c - clear
875 for (LinkedList<ParamSymbol*>::Itenerator it = paramSymbols.begin2(); it.valid(); it.next())
877 ParamSymbol* const paramSymbol(it.getValue(nullptr));
878 delete paramSymbol;
881 paramSymbols.clear();
883 // ---------------------------------------------------------------
884 // Part 5 - set custom data
886 for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
888 const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
889 CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
890 CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
892 const char* const key(stateCustomData->key);
894 if (pluginType == PLUGIN_DSSI && (std::strcmp (key, "reloadprograms") == 0 ||
895 std::strcmp (key, "load" ) == 0 ||
896 std::strncmp(key, "patches", 7) == 0 ))
897 continue;
898 if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0)
899 continue;
901 setCustomData(stateCustomData->type, key, stateCustomData->value, true);
904 // ---------------------------------------------------------------
905 // Part 5x - set lv2 state
907 if (pluginType == PLUGIN_LV2)
909 for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
911 const CustomData& customData(it.getValue(kCustomDataFallback));
912 CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
914 if (std::strcmp(customData.type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
915 continue;
917 restoreLV2State(stateSave.temporary);
918 break;
922 // ---------------------------------------------------------------
923 // Part 6 - set chunk
925 if (stateSave.chunk != nullptr && (pData->options & PLUGIN_OPTION_USE_CHUNKS) != 0)
927 std::vector<uint8_t> chunk(carla_getChunkFromBase64String(stateSave.chunk));
928 #ifdef CARLA_PROPER_CPP11_SUPPORT
929 setChunkData(chunk.data(), chunk.size());
930 #else
931 setChunkData(&chunk.front(), chunk.size());
932 #endif
935 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
936 // ---------------------------------------------------------------
937 // Part 6 - set internal stuff
939 const uint availOptions = getOptionsAvailable();
941 for (uint i=0; i<10; ++i) // FIXME - get this value somehow...
943 const uint option(1u << i);
945 if (availOptions & option)
946 setOption(option, (stateSave.options & option) != 0, true);
949 setDryWet(stateSave.dryWet, true, true);
950 setVolume(stateSave.volume, true, true);
951 setBalanceLeft(stateSave.balanceLeft, true, true);
952 setBalanceRight(stateSave.balanceRight, true, true);
953 setPanning(stateSave.panning, true, true);
954 setCtrlChannel(stateSave.ctrlChannel, true, true);
955 setActive(stateSave.active, true, true);
957 if (! pData->engine->isLoadingProject())
958 pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0, 0.0f, nullptr);
959 #endif
962 bool CarlaPlugin::saveStateToFile(const char* const filename)
964 CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
965 carla_debug("CarlaPlugin::saveStateToFile(\"%s\")", filename);
967 MemoryOutputStream out, streamState;
968 getStateSave().dumpToMemoryStream(streamState);
970 out << "<?xml version='1.0' encoding='UTF-8'?>\n";
971 out << "<!DOCTYPE CARLA-PRESET>\n";
972 out << "<CARLA-PRESET VERSION='2.0'>\n";
973 out << streamState;
974 out << "</CARLA-PRESET>\n";
976 File file(filename);
978 if (file.replaceWithData(out.getData(), out.getDataSize()))
979 return true;
981 pData->engine->setLastError("Failed to write file");
982 return false;
985 bool CarlaPlugin::loadStateFromFile(const char* const filename)
987 // TODO set errors
989 CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
990 carla_debug("CarlaPlugin::loadStateFromFile(\"%s\")", filename);
992 File file(filename);
993 CARLA_SAFE_ASSERT_RETURN(file.existsAsFile(), false);
995 XmlDocument xml(file);
996 CarlaScopedPointer<XmlElement> xmlElement(xml.getDocumentElement(true));
997 CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
998 CARLA_SAFE_ASSERT_RETURN(xmlElement->getTagName().equalsIgnoreCase("carla-preset"), false);
1000 // completely load file
1001 xmlElement = xml.getDocumentElement(false);
1002 CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
1004 if (pData->stateSave.fillFromXmlElement(xmlElement))
1006 loadStateSave(pData->stateSave);
1007 return true;
1010 return false;
1013 #ifndef CARLA_PLUGIN_ONLY_BRIDGE
1014 bool CarlaPlugin::exportAsLV2(const char* const lv2path)
1016 CARLA_SAFE_ASSERT_RETURN(lv2path != nullptr && lv2path[0] != '\0', false);
1017 carla_debug("CarlaPlugin::exportAsLV2(\"%s\")", lv2path);
1019 CarlaString bundlepath(lv2path);
1021 if (! bundlepath.endsWith(".lv2"))
1022 bundlepath += ".lv2";
1024 const File bundlefolder(bundlepath.buffer());
1026 if (bundlefolder.existsAsFile())
1028 pData->engine->setLastError("Requested filename already exists as file, use a folder instead");
1029 return false;
1032 if (! bundlefolder.exists())
1034 const Result res(bundlefolder.createDirectory());
1036 if (res.failed())
1038 pData->engine->setLastError(res.getErrorMessage().c_str());
1039 return false;
1043 CarlaString symbol(pData->name);
1044 symbol.toBasic();
1047 const CarlaString pluginFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".xml");
1049 if (! saveStateToFile(pluginFilename))
1050 return false;
1054 MemoryOutputStream manifestStream;
1056 manifestStream << "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
1057 manifestStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
1058 manifestStream << "@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n";
1059 manifestStream << "\n";
1060 manifestStream << "<" << symbol.buffer() << ".ttl>\n";
1061 manifestStream << " a lv2:Plugin ;\n";
1062 manifestStream << " lv2:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
1063 manifestStream << " rdfs:seeAlso <" << symbol.buffer() << ".ttl> .\n";
1064 manifestStream << "\n";
1065 manifestStream << "<ext-ui>\n";
1066 manifestStream << " a <http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget> ;\n";
1067 manifestStream << " ui:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
1068 manifestStream << " lv2:extensionData <http://lv2plug.in/ns/extensions/ui#idleInterface> ,\n";
1069 manifestStream << " <http://lv2plug.in/ns/extensions/ui#showInterface> ;\n";
1070 manifestStream << " lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> .\n";
1071 manifestStream << "\n";
1073 const CarlaString manifestFilename(bundlepath + CARLA_OS_SEP_STR "manifest.ttl");
1074 const File manifestFile(manifestFilename.buffer());
1076 if (! manifestFile.replaceWithData(manifestStream.getData(), manifestStream.getDataSize()))
1078 pData->engine->setLastError("Failed to write manifest.ttl file");
1079 return false;
1084 MemoryOutputStream mainStream;
1086 mainStream << "@prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n";
1087 mainStream << "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
1088 mainStream << "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
1089 mainStream << "@prefix lv2: <http://lv2plug.in/ns/lv2core#> .\n";
1090 mainStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
1091 mainStream << "@prefix ui: <http://lv2plug.in/ns/extensions/ui#> .\n";
1092 mainStream << "\n";
1093 mainStream << "<>\n";
1094 mainStream << " a lv2:Plugin ;\n";
1095 mainStream << "\n";
1096 mainStream << " lv2:requiredFeature <http://lv2plug.in/ns/ext/buf-size#boundedBlockLength> ,\n";
1097 mainStream << " <http://lv2plug.in/ns/ext/options#options> ,\n";
1098 mainStream << " <http://lv2plug.in/ns/ext/urid#map> ;\n";
1099 mainStream << "\n";
1101 if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
1103 mainStream << " ui:ui <ext-ui> ;\n";
1104 mainStream << "\n";
1107 const uint32_t midiIns = getMidiInCount();
1108 const uint32_t midiOuts = getMidiOutCount();
1110 int portIndex = 0;
1112 if (midiIns > 0)
1114 mainStream << " lv2:port [\n";
1115 mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
1116 mainStream << " lv2:index 0 ;\n";
1117 mainStream << " lv2:symbol \"clv2_events_in\" ;\n";
1118 mainStream << " lv2:name \"Events Input\" ;\n";
1119 mainStream << " atom:bufferType atom:Sequence ;\n";
1120 mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ,\n";
1121 mainStream << " <http://lv2plug.in/ns/ext/time#Position> ;\n";
1122 mainStream << " ] ;\n";
1123 ++portIndex;
1125 for (uint32_t i=1; i<midiIns; ++i)
1127 const String portIndexNum(portIndex++);
1128 const String portIndexLabel(portIndex);
1130 mainStream << " lv2:port [\n";
1131 mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
1132 mainStream << " lv2:index " << portIndexNum << " ;\n";
1133 mainStream << " lv2:symbol \"clv2_midi_in_" << portIndexLabel << "\" ;\n";
1134 mainStream << " lv2:name \"MIDI Input " << portIndexLabel << "\" ;\n";
1135 mainStream << " ] ;\n";
1138 else
1140 mainStream << " lv2:port [\n";
1141 mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
1142 mainStream << " lv2:index 0 ;\n";
1143 mainStream << " lv2:symbol \"clv2_time_info\" ;\n";
1144 mainStream << " lv2:name \"Time Info\" ;\n";
1145 mainStream << " atom:bufferType atom:Sequence ;\n";
1146 mainStream << " atom:supports <http://lv2plug.in/ns/ext/time#Position> ;\n";
1147 mainStream << " ] ;\n";
1148 ++portIndex;
1151 for (uint32_t i=0; i<midiOuts; ++i)
1153 const String portIndexNum(portIndex++);
1154 const String portIndexLabel(portIndex);
1156 mainStream << " lv2:port [\n";
1157 mainStream << " a lv2:InputPort, atom:AtomPort ;\n";
1158 mainStream << " lv2:index " << portIndexNum << " ;\n";
1159 mainStream << " lv2:symbol \"clv2_midi_out_" << portIndexLabel << "\" ;\n";
1160 mainStream << " lv2:name \"MIDI Output " << portIndexLabel << "\" ;\n";
1161 mainStream << " atom:bufferType atom:Sequence ;\n";
1162 mainStream << " atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n";
1163 mainStream << " ] ;\n";
1166 mainStream << " lv2:port [\n";
1167 mainStream << " a lv2:InputPort, lv2:ControlPort ;\n";
1168 mainStream << " lv2:index " << String(portIndex++) << " ;\n";
1169 mainStream << " lv2:name \"freewheel\" ;\n";
1170 mainStream << " lv2:symbol \"clv2_freewheel\" ;\n";
1171 mainStream << " lv2:default 0 ;\n";
1172 mainStream << " lv2:minimum 0 ;\n";
1173 mainStream << " lv2:maximum 1 ;\n";
1174 mainStream << " lv2:designation lv2:freeWheeling ;\n";
1175 mainStream << " lv2:portProperty lv2:toggled , lv2:integer ;\n";
1176 mainStream << " lv2:portProperty <http://lv2plug.in/ns/ext/port-props#notOnGUI> ;\n";
1177 mainStream << " ] ;\n";
1179 for (uint32_t i=0; i<pData->audioIn.count; ++i)
1181 const String portIndexNum(portIndex++);
1182 const String portIndexLabel(i+1);
1184 mainStream << " lv2:port [\n";
1185 mainStream << " a lv2:InputPort, lv2:AudioPort ;\n";
1186 mainStream << " lv2:index " << portIndexNum << " ;\n";
1187 mainStream << " lv2:symbol \"clv2_audio_in_" << portIndexLabel << "\" ;\n";
1188 mainStream << " lv2:name \"Audio Input " << portIndexLabel << "\" ;\n";
1189 mainStream << " ] ;\n";
1192 for (uint32_t i=0; i<pData->audioOut.count; ++i)
1194 const String portIndexNum(portIndex++);
1195 const String portIndexLabel(i+1);
1197 mainStream << " lv2:port [\n";
1198 mainStream << " a lv2:OutputPort, lv2:AudioPort ;\n";
1199 mainStream << " lv2:index " << portIndexNum << " ;\n";
1200 mainStream << " lv2:symbol \"clv2_audio_out_" << portIndexLabel << "\" ;\n";
1201 mainStream << " lv2:name \"Audio Output " << portIndexLabel << "\" ;\n";
1202 mainStream << " ] ;\n";
1205 CarlaStringList uniqueSymbolNames;
1207 char strBufName[STR_MAX+1];
1208 char strBufSymbol[STR_MAX+1];
1209 carla_zeroChars(strBufName, STR_MAX+1);
1210 carla_zeroChars(strBufSymbol, STR_MAX+1);
1212 for (uint32_t i=0; i<pData->param.count; ++i)
1214 const ParameterData& paramData(pData->param.data[i]);
1215 const ParameterRanges& paramRanges(pData->param.ranges[i]);
1217 const String portIndexNum(portIndex++);
1219 mainStream << " lv2:port [\n";
1221 if (paramData.type == PARAMETER_INPUT)
1222 mainStream << " a lv2:InputPort, lv2:ControlPort ;\n";
1223 else
1224 mainStream << " a lv2:OutputPort, lv2:ControlPort ;\n";
1226 if (paramData.hints & PARAMETER_IS_BOOLEAN)
1227 mainStream << " lv2:portProperty lv2:toggled ;\n";
1229 if (paramData.hints & PARAMETER_IS_INTEGER)
1230 mainStream << " lv2:portProperty lv2:integer ;\n";
1232 // TODO logarithmic, enabled (not on gui), automatable, samplerate, scalepoints
1234 if (! getParameterName(i, strBufName))
1235 strBufName[0] = '\0';
1236 if (! getParameterSymbol(i, strBufSymbol))
1237 strBufSymbol[0] = '\0';
1239 if (strBufSymbol[0] == '\0')
1241 CarlaString s(strBufName);
1242 s.toBasic();
1243 std::memcpy(strBufSymbol, s.buffer(), s.length()+1);
1245 if (strBufSymbol[0] >= '0' && strBufSymbol[0] <= '9')
1247 const size_t len(std::strlen(strBufSymbol));
1248 std::memmove(strBufSymbol+1, strBufSymbol, len);
1249 strBufSymbol[0] = '_';
1250 strBufSymbol[len+1] = '\0';
1254 if (uniqueSymbolNames.contains(strBufSymbol))
1255 std::snprintf(strBufSymbol, STR_MAX, "clv2_param_%d", i+1);
1257 mainStream << " lv2:index " << portIndexNum << " ;\n";
1258 mainStream << " lv2:symbol \"" << strBufSymbol << "\" ;\n";
1259 mainStream << " lv2:name \"\"\"" << strBufName << "\"\"\" ;\n";
1260 mainStream << " lv2:default " << String(paramRanges.def) << " ;\n";
1261 mainStream << " lv2:minimum " << String(paramRanges.min) << " ;\n";
1262 mainStream << " lv2:maximum " << String(paramRanges.max) << " ;\n";
1264 // TODO midiCC, midiChannel
1266 mainStream << " ] ;\n";
1269 char strBuf[STR_MAX+1];
1270 carla_zeroChars(strBuf, STR_MAX+1);
1272 if (! getMaker(strBuf))
1273 strBuf[0] = '\0';
1275 mainStream << " rdfs:comment \"Plugin generated using Carla LV2 export.\" ;\n";
1276 mainStream << " doap:name \"\"\"" << getName() << "\"\"\" ;\n";
1277 mainStream << " doap:maintainer [ foaf:name \"\"\"" << strBuf << "\"\"\" ] .\n";
1278 mainStream << "\n";
1280 const CarlaString mainFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".ttl");
1281 const File mainFile(mainFilename.buffer());
1283 if (! mainFile.replaceWithData(mainStream.getData(), mainStream.getDataSize()))
1285 pData->engine->setLastError("Failed to write main plugin ttl file");
1286 return false;
1290 const CarlaString binaryFilename(bundlepath + CARLA_OS_SEP_STR + symbol + CARLA_LIB_EXT);
1292 const File binaryFileSource(File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("carla-bridge-lv2" CARLA_LIB_EXT));
1293 const File binaryFileTarget(binaryFilename.buffer());
1295 const EngineOptions& opts(pData->engine->getOptions());
1297 const CarlaString binFolderTarget(bundlepath + CARLA_OS_SEP_STR + "bin");
1298 const CarlaString resFolderTarget(bundlepath + CARLA_OS_SEP_STR + "res");
1300 if (! binaryFileSource.copyFileTo(binaryFileTarget))
1302 pData->engine->setLastError("Failed to copy plugin binary");
1303 return false;
1306 #ifdef CARLA_OS_WIN
1307 File(opts.resourceDir).copyDirectoryTo(File(resFolderTarget.buffer()));
1309 // Copying all the binaries is pointless, just go through the expected needed bits
1310 const File binFolder1(opts.binaryDir);
1311 const File binFolder2(binFolderTarget.buffer());
1312 binFolder2.createDirectory();
1314 static const char* files[] = {
1315 "carla-bridge-native.exe",
1316 "carla-bridge-win32.exe",
1317 "carla-discovery-win32.exe",
1318 "carla-discovery-win64.exe",
1319 "libcarla_utils.dll"
1322 for (int i=0; i<5; ++i)
1323 binFolder1.getChildFile(files[i]).copyFileTo(binFolder2.getChildFile(files[i]));;
1324 #else
1325 File(opts.binaryDir).createSymbolicLink(File(binFolderTarget.buffer()), true);
1326 File(opts.resourceDir).createSymbolicLink(File(resFolderTarget.buffer()), true);
1327 #endif
1329 return true;
1331 #endif
1333 // -------------------------------------------------------------------
1334 // Set data (internal stuff)
1336 void CarlaPlugin::setId(const uint newId) noexcept
1338 pData->id = newId;
1341 void CarlaPlugin::setName(const char* const newName)
1343 CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0',);
1345 if (pData->name != nullptr)
1346 delete[] pData->name;
1348 pData->name = carla_strdup(newName);
1351 void CarlaPlugin::setOption(const uint option, const bool yesNo, const bool sendCallback)
1353 CARLA_SAFE_ASSERT_UINT2_RETURN(getOptionsAvailable() & option, getOptionsAvailable(), option,);
1355 if (yesNo)
1356 pData->options |= option;
1357 else
1358 pData->options &= ~option;
1360 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1361 if (sendCallback)
1362 pData->engine->callback(true, true,
1363 ENGINE_CALLBACK_OPTION_CHANGED,
1364 pData->id,
1365 static_cast<int>(option),
1366 yesNo ? 1 : 0,
1367 0, 0.0f, nullptr);
1368 #else
1369 // unused
1370 return; (void)sendCallback;
1371 #endif
1374 void CarlaPlugin::setEnabled(const bool yesNo) noexcept
1376 if (pData->enabled == yesNo)
1377 return;
1379 pData->masterMutex.lock();
1380 pData->enabled = yesNo;
1382 if (yesNo && ! pData->client->isActive())
1383 pData->client->activate();
1385 pData->masterMutex.unlock();
1388 void CarlaPlugin::setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept
1390 if (pData->engineBridged) {
1391 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1392 } else if (pData->enginePlugin) {
1393 // nothing here
1394 } else {
1395 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1398 if (pData->active == active)
1399 return;
1402 const ScopedSingleProcessLocker spl(this, true);
1404 if (active)
1405 activate();
1406 else
1407 deactivate();
1410 pData->active = active;
1412 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1413 const float value = active ? 1.0f : 0.0f;
1415 pData->engine->callback(sendCallback, sendOsc,
1416 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1417 pData->id,
1418 PARAMETER_ACTIVE,
1419 0, 0,
1420 value,
1421 nullptr);
1422 #endif
1425 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1426 void CarlaPlugin::setDryWet(const float value, const bool sendOsc, const bool sendCallback) noexcept
1428 if (pData->engineBridged) {
1429 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1430 } else {
1431 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1433 CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
1435 const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
1437 if (carla_isEqual(pData->postProc.dryWet, fixedValue))
1438 return;
1440 pData->postProc.dryWet = fixedValue;
1442 pData->engine->callback(sendCallback, sendOsc,
1443 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1444 pData->id,
1445 PARAMETER_DRYWET,
1446 0, 0,
1447 fixedValue,
1448 nullptr);
1451 void CarlaPlugin::setVolume(const float value, const bool sendOsc, const bool sendCallback) noexcept
1453 if (pData->engineBridged) {
1454 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1455 } else {
1456 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1458 CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
1460 const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
1462 if (carla_isEqual(pData->postProc.volume, fixedValue))
1463 return;
1465 pData->postProc.volume = fixedValue;
1467 pData->engine->callback(sendCallback, sendOsc,
1468 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1469 pData->id,
1470 PARAMETER_VOLUME,
1471 0, 0,
1472 fixedValue,
1473 nullptr);
1476 void CarlaPlugin::setBalanceLeft(const float value, const bool sendOsc, const bool sendCallback) noexcept
1478 if (pData->engineBridged) {
1479 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1480 } else {
1481 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1483 CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1485 const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1487 if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
1488 return;
1490 pData->postProc.balanceLeft = fixedValue;
1492 pData->engine->callback(sendCallback, sendOsc,
1493 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1494 pData->id,
1495 PARAMETER_BALANCE_LEFT,
1496 0, 0,
1497 fixedValue,
1498 nullptr);
1501 void CarlaPlugin::setBalanceRight(const float value, const bool sendOsc, const bool sendCallback) noexcept
1503 if (pData->engineBridged) {
1504 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1505 } else {
1506 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1508 CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1510 const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1512 if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
1513 return;
1515 pData->postProc.balanceRight = fixedValue;
1517 pData->engine->callback(sendCallback, sendOsc,
1518 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1519 pData->id,
1520 PARAMETER_BALANCE_RIGHT,
1521 0, 0,
1522 fixedValue,
1523 nullptr);
1526 void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool sendCallback) noexcept
1528 if (pData->engineBridged) {
1529 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1530 } else {
1531 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1533 CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1535 const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1537 if (carla_isEqual(pData->postProc.panning, fixedValue))
1538 return;
1540 pData->postProc.panning = fixedValue;
1542 pData->engine->callback(sendCallback, sendOsc,
1543 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1544 pData->id,
1545 PARAMETER_PANNING,
1546 0, 0,
1547 fixedValue,
1548 nullptr);
1551 void CarlaPlugin::setDryWetRT(const float value, const bool sendCallbackLater) noexcept
1553 CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
1555 const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
1557 if (carla_isEqual(pData->postProc.dryWet, fixedValue))
1558 return;
1560 pData->postProc.dryWet = fixedValue;
1561 pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_DRYWET, fixedValue);
1564 void CarlaPlugin::setVolumeRT(const float value, const bool sendCallbackLater) noexcept
1566 CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
1568 const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
1570 if (carla_isEqual(pData->postProc.volume, fixedValue))
1571 return;
1573 pData->postProc.volume = fixedValue;
1574 pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_VOLUME, fixedValue);
1577 void CarlaPlugin::setBalanceLeftRT(const float value, const bool sendCallbackLater) noexcept
1579 CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1581 const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1583 if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
1584 return;
1586 pData->postProc.balanceLeft = fixedValue;
1587 pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_BALANCE_LEFT, fixedValue);
1590 void CarlaPlugin::setBalanceRightRT(const float value, const bool sendCallbackLater) noexcept
1592 CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1594 const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1596 if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
1597 return;
1599 pData->postProc.balanceRight = fixedValue;
1600 pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_BALANCE_RIGHT, fixedValue);
1603 void CarlaPlugin::setPanningRT(const float value, const bool sendCallbackLater) noexcept
1605 CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1607 const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1609 if (carla_isEqual(pData->postProc.panning, fixedValue))
1610 return;
1612 pData->postProc.panning = fixedValue;
1613 pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_PANNING, fixedValue);
1615 #endif // ! BUILD_BRIDGE_ALTERNATIVE_ARCH
1617 void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept
1619 if (pData->engineBridged) {
1620 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1621 } else {
1622 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1624 CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,);
1626 if (pData->ctrlChannel == channel)
1627 return;
1629 pData->ctrlChannel = channel;
1631 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1632 const float channelf = static_cast<float>(channel);
1634 pData->engine->callback(sendCallback, sendOsc,
1635 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1636 pData->id,
1637 PARAMETER_CTRL_CHANNEL,
1638 0, 0,
1639 channelf, nullptr);
1640 #endif
1643 // -------------------------------------------------------------------
1644 // Set data (plugin-specific stuff)
1646 void CarlaPlugin::setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
1648 if (pData->engineBridged) {
1649 // NOTE: some LV2 plugins feedback messages to UI on purpose
1650 CARLA_SAFE_ASSERT_RETURN(getType() == PLUGIN_LV2 || !sendGui,);
1651 } else if (pData->enginePlugin) {
1652 // nothing here
1653 } else {
1654 CARLA_SAFE_ASSERT_RETURN(sendGui || sendOsc || sendCallback,); // never call this from RT
1656 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1658 if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
1659 uiParameterChange(parameterId, value);
1661 pData->engine->callback(sendCallback, sendOsc,
1662 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1663 pData->id,
1664 static_cast<int>(parameterId),
1665 0, 0,
1666 value,
1667 nullptr);
1670 void CarlaPlugin::setParameterValueRT(const uint32_t parameterId, const float value, uint32_t, const bool sendCallbackLater) noexcept
1672 pData->postponeParameterChangeRtEvent(sendCallbackLater, static_cast<int32_t>(parameterId), value);
1675 void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
1677 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1678 CARLA_SAFE_ASSERT_RETURN(rindex > PARAMETER_MAX && rindex != PARAMETER_NULL,);
1680 switch (rindex)
1682 case PARAMETER_ACTIVE:
1683 return setActive((value > 0.0f), sendOsc, sendCallback);
1684 case PARAMETER_CTRL_CHANNEL:
1685 return setCtrlChannel(int8_t(value), sendOsc, sendCallback);
1686 case PARAMETER_DRYWET:
1687 return setDryWet(value, sendOsc, sendCallback);
1688 case PARAMETER_VOLUME:
1689 return setVolume(value, sendOsc, sendCallback);
1690 case PARAMETER_BALANCE_LEFT:
1691 return setBalanceLeft(value, sendOsc, sendCallback);
1692 case PARAMETER_BALANCE_RIGHT:
1693 return setBalanceRight(value, sendOsc, sendCallback);
1694 case PARAMETER_PANNING:
1695 return setPanning(value, sendOsc, sendCallback);
1697 #endif
1698 CARLA_SAFE_ASSERT_RETURN(rindex >= 0,);
1700 for (uint32_t i=0; i < pData->param.count; ++i)
1702 if (pData->param.data[i].rindex == rindex)
1704 //if (carla_isNotEqual(getParameterValue(i), value))
1705 setParameterValue(i, value, sendGui, sendOsc, sendCallback);
1706 break;
1711 void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint8_t channel, const bool sendOsc, const bool sendCallback) noexcept
1713 if (pData->engineBridged) {
1714 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1715 } else {
1716 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1718 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1719 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
1721 if (pData->param.data[parameterId].midiChannel == channel)
1722 return;
1724 pData->param.data[parameterId].midiChannel = channel;
1726 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1727 pData->engine->callback(sendCallback, sendOsc,
1728 ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED,
1729 pData->id,
1730 static_cast<int>(parameterId),
1731 channel,
1732 0, 0.0f, nullptr);
1733 #endif
1736 void CarlaPlugin::setParameterMappedControlIndex(const uint32_t parameterId, const int16_t index,
1737 const bool sendOsc, const bool sendCallback,
1738 const bool reconfigureNow) noexcept
1740 if (pData->engineBridged) {
1741 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1742 } else {
1743 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1745 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1746 CARLA_SAFE_ASSERT_RETURN(index >= CONTROL_INDEX_NONE && index <= CONTROL_INDEX_MAX_ALLOWED,);
1748 ParameterData& paramData(pData->param.data[parameterId]);
1750 if (paramData.mappedControlIndex == index)
1751 return;
1753 const ParameterRanges& paramRanges(pData->param.ranges[parameterId]);
1755 if ((paramData.hints & PARAMETER_MAPPED_RANGES_SET) == 0x0)
1756 setParameterMappedRange(parameterId, paramRanges.min, paramRanges.max, true, true);
1758 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1759 char strBuf[STR_MAX+1];
1760 carla_zeroChars(strBuf, STR_MAX+1);
1761 if (! getParameterName(parameterId, strBuf))
1762 std::snprintf(strBuf, STR_MAX, "Param %u", parameterId);
1764 const uint portNameSize = pData->engine->getMaxPortNameSize();
1765 if (portNameSize < STR_MAX)
1766 strBuf[portNameSize] = '\0';
1768 // was learning something else before, stop that first
1769 if (pData->midiLearnParameterIndex >= 0 && pData->midiLearnParameterIndex != static_cast<int32_t>(parameterId))
1771 const int32_t oldParameterId = pData->midiLearnParameterIndex;
1772 pData->midiLearnParameterIndex = -1;
1774 CARLA_SAFE_ASSERT_RETURN(oldParameterId < static_cast<int32_t>(pData->param.count),);
1776 pData->param.data[oldParameterId].mappedControlIndex = CONTROL_INDEX_NONE;
1777 pData->engine->callback(true, true,
1778 ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED,
1779 pData->id,
1780 oldParameterId,
1781 CONTROL_INDEX_NONE,
1782 0, 0.0f, nullptr);
1785 // mapping new parameter to CV
1786 if (index == CONTROL_INDEX_CV)
1788 CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,);
1789 CARLA_SAFE_ASSERT_RETURN(paramData.type == PARAMETER_INPUT,);
1790 CARLA_SAFE_ASSERT_RETURN(paramData.hints & PARAMETER_CAN_BE_CV_CONTROLLED,);
1792 CarlaEngineCVPort* const cvPort =
1793 (CarlaEngineCVPort*)pData->client->addPort(kEnginePortTypeCV, strBuf, true, parameterId);
1794 cvPort->setRange(paramData.mappedMinimum, paramData.mappedMaximum);
1795 pData->event.cvSourcePorts->addCVSource(cvPort, parameterId, reconfigureNow);
1797 // unmapping from CV
1798 else if (paramData.mappedControlIndex == CONTROL_INDEX_CV)
1800 CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,);
1802 CARLA_SAFE_ASSERT(pData->client->removePort(kEnginePortTypeCV, strBuf, true));
1803 CARLA_SAFE_ASSERT(pData->event.cvSourcePorts->removeCVSource(parameterId));
1805 // mapping to something new
1806 else if (paramData.mappedControlIndex == CONTROL_INDEX_NONE)
1808 // when doing MIDI CC mapping, ensure ranges are within bounds
1809 if (paramData.mappedMinimum < paramRanges.min || paramData.mappedMaximum > paramRanges.max)
1810 setParameterMappedRange(parameterId,
1811 std::max(paramData.mappedMinimum, paramRanges.min),
1812 std::min(paramData.mappedMaximum, paramRanges.max),
1813 true, true);
1815 #endif
1817 paramData.mappedControlIndex = index;
1819 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1820 if (index == CONTROL_INDEX_MIDI_LEARN)
1821 pData->midiLearnParameterIndex = static_cast<int32_t>(parameterId);
1822 else
1823 pData->midiLearnParameterIndex = -1;
1825 pData->engine->callback(sendCallback, sendOsc,
1826 ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED,
1827 pData->id,
1828 static_cast<int>(parameterId),
1829 index,
1830 0, 0.0f, nullptr);
1831 #else
1832 return;
1833 // unused
1834 (void)reconfigureNow;
1835 #endif
1838 void CarlaPlugin::setParameterMappedRange(const uint32_t parameterId, const float minimum, const float maximum,
1839 const bool sendOsc, const bool sendCallback) noexcept
1841 if (pData->engineBridged) {
1842 CARLA_SAFE_ASSERT_RETURN(!sendOsc && !sendCallback,);
1843 } else {
1844 CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback,); // never call this from RT
1846 CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1848 ParameterData& paramData(pData->param.data[parameterId]);
1850 if (carla_isEqual(paramData.mappedMinimum, minimum) &&
1851 carla_isEqual(paramData.mappedMaximum, maximum) &&
1852 (paramData.hints & PARAMETER_MAPPED_RANGES_SET) != 0x0)
1853 return;
1855 if (paramData.mappedControlIndex != CONTROL_INDEX_NONE && paramData.mappedControlIndex != CONTROL_INDEX_CV)
1857 const ParameterRanges& paramRanges(pData->param.ranges[parameterId]);
1858 CARLA_SAFE_ASSERT_RETURN(minimum >= paramRanges.min,);
1859 CARLA_SAFE_ASSERT_RETURN(maximum <= paramRanges.max,);
1862 paramData.hints |= PARAMETER_MAPPED_RANGES_SET;
1863 paramData.mappedMinimum = minimum;
1864 paramData.mappedMaximum = maximum;
1866 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1867 if (pData->event.cvSourcePorts != nullptr && paramData.mappedControlIndex == CONTROL_INDEX_CV)
1868 pData->event.cvSourcePorts->setCVSourceRange(parameterId, minimum, maximum);
1870 char strBuf[STR_MAX+1];
1871 carla_zeroChars(strBuf, STR_MAX+1);
1872 std::snprintf(strBuf, STR_MAX, "%.12g:%.12g", static_cast<double>(minimum), static_cast<double>(maximum));
1874 pData->engine->callback(sendCallback, sendOsc,
1875 ENGINE_CALLBACK_PARAMETER_MAPPED_RANGE_CHANGED,
1876 pData->id,
1877 static_cast<int>(parameterId),
1878 0, 0, 0.0f,
1879 strBuf);
1880 #endif
1883 void CarlaPlugin::setCustomData(const char* const type, const char* const key, const char* const value, const bool)
1885 CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
1886 CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
1887 CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
1889 // Ignore some keys
1890 if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) == 0)
1892 const PluginType ptype = getType();
1894 if ((ptype == PLUGIN_INTERNAL && std::strncmp(key, "CarlaAlternateFile", 18) == 0) ||
1895 (ptype == PLUGIN_DSSI && std::strcmp (key, "guiVisible") == 0) ||
1896 (ptype == PLUGIN_LV2 && std::strncmp(key, "OSC:", 4) == 0))
1897 return;
1900 // Check if we already have this key
1901 for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
1903 CustomData& customData(it.getValue(kCustomDataFallbackNC));
1904 CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
1906 if (std::strcmp(customData.key, key) == 0)
1908 if (customData.value != nullptr)
1909 delete[] customData.value;
1911 customData.value = carla_strdup(value);
1912 return;
1916 // Otherwise store it
1917 CustomData customData;
1918 customData.type = carla_strdup(type);
1919 customData.key = carla_strdup(key);
1920 customData.value = carla_strdup(value);
1921 pData->custom.append(customData);
1924 void CarlaPlugin::setChunkData(const void* const data, const std::size_t dataSize)
1926 CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
1927 CARLA_SAFE_ASSERT_RETURN(dataSize > 0,);
1928 CARLA_SAFE_ASSERT(false); // this should never happen
1931 void CarlaPlugin::setProgram(const int32_t index,
1932 const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
1934 CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->prog.count),);
1936 pData->prog.current = index;
1938 pData->engine->callback(sendCallback, sendOsc,
1939 ENGINE_CALLBACK_PROGRAM_CHANGED,
1940 pData->id,
1941 index,
1942 0, 0, 0.0f, nullptr);
1944 // Change default parameter values
1945 if (index >= 0)
1947 if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
1948 uiProgramChange(static_cast<uint32_t>(index));
1950 switch (getType())
1952 case PLUGIN_SF2:
1953 case PLUGIN_SFZ:
1954 break;
1956 default:
1957 pData->updateParameterValues(this, sendCallback, sendOsc, true);
1958 break;
1963 void CarlaPlugin::setMidiProgram(const int32_t index,
1964 const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
1966 CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
1968 pData->midiprog.current = index;
1970 pData->engine->callback(sendCallback, sendOsc,
1971 ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
1972 pData->id,
1973 index,
1974 0, 0, 0.0f, nullptr);
1976 // Change default parameter values
1977 if (index >= 0)
1979 if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
1980 uiMidiProgramChange(static_cast<uint32_t>(index));
1982 switch (getType())
1984 case PLUGIN_SF2:
1985 case PLUGIN_SFZ:
1986 break;
1988 default:
1989 pData->updateParameterValues(this, sendCallback, sendOsc, true);
1990 break;
1995 void CarlaPlugin::setMidiProgramById(const uint32_t bank, const uint32_t program, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
1997 for (uint32_t i=0; i < pData->midiprog.count; ++i)
1999 if (pData->midiprog.data[i].bank == bank && pData->midiprog.data[i].program == program)
2000 return setMidiProgram(static_cast<int32_t>(i), sendGui, sendOsc, sendCallback);
2004 void CarlaPlugin::setProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
2006 CARLA_SAFE_ASSERT_RETURN(uindex < pData->prog.count,);
2008 const int32_t index = static_cast<int32_t>(uindex);
2009 pData->prog.current = index;
2011 // Change default parameter values
2012 switch (getType())
2014 case PLUGIN_SF2:
2015 case PLUGIN_SFZ:
2016 break;
2018 default:
2019 pData->updateDefaultParameterValues(this);
2020 break;
2023 pData->postponeProgramChangeRtEvent(sendCallbackLater, uindex);
2026 void CarlaPlugin::setMidiProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
2028 CARLA_SAFE_ASSERT_RETURN(uindex < pData->midiprog.count,);
2030 const int32_t index = static_cast<int32_t>(uindex);
2031 pData->midiprog.current = index;
2033 // Change default parameter values
2034 switch (getType())
2036 case PLUGIN_SF2:
2037 case PLUGIN_SFZ:
2038 break;
2040 default:
2041 pData->updateDefaultParameterValues(this);
2042 break;
2045 pData->postponeMidiProgramChangeRtEvent(sendCallbackLater, uindex);
2048 // -------------------------------------------------------------------
2049 // Plugin state
2051 void CarlaPlugin::reloadPrograms(const bool)
2055 // -------------------------------------------------------------------
2056 // Plugin processing
2058 void CarlaPlugin::activate() noexcept
2060 CARLA_SAFE_ASSERT(! pData->active);
2063 void CarlaPlugin::deactivate() noexcept
2065 CARLA_SAFE_ASSERT(pData->active);
2068 void CarlaPlugin::bufferSizeChanged(const uint32_t newBufferSize)
2070 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2071 delete[] pData->postProc.extraBuffer;
2072 pData->postProc.extraBuffer = new float[newBufferSize];
2073 #else
2074 // unused
2075 (void)newBufferSize;
2076 #endif
2079 void CarlaPlugin::sampleRateChanged(const double)
2083 void CarlaPlugin::offlineModeChanged(const bool)
2087 // -------------------------------------------------------------------
2088 // Misc
2090 void CarlaPlugin::idle()
2092 if (! pData->enabled)
2093 return;
2095 const bool hasUI = pData->hints & PLUGIN_HAS_CUSTOM_UI;
2096 const bool needsUiMainThread = pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD;
2097 const uint32_t latency = getLatencyInFrames();
2099 if (pData->latency.frames != latency)
2101 carla_stdout("latency changed to %i samples", latency);
2103 const ScopedSingleProcessLocker sspl(this, true);
2105 pData->client->setLatency(latency);
2106 #ifndef BUILD_BRIDGE
2107 pData->latency.recreateBuffers(pData->latency.channels, latency);
2108 #else
2109 pData->latency.frames = latency;
2110 #endif
2113 ProtectedData::PostRtEvents::Access rtEvents(pData->postRtEvents);
2115 if (rtEvents.isEmpty())
2116 return;
2118 for (RtLinkedList<PluginPostRtEvent>::Itenerator it = rtEvents.getDataIterator(); it.valid(); it.next())
2120 const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
2121 CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
2123 switch (event.type)
2125 case kPluginPostRtEventNull: {
2126 } break;
2128 case kPluginPostRtEventParameterChange: {
2129 // Update UI
2130 if (event.parameter.index >= 0 && hasUI)
2132 if (needsUiMainThread)
2133 pData->postUiEvents.append(event);
2134 else
2135 uiParameterChange(static_cast<uint32_t>(event.parameter.index), event.parameter.value);
2138 if (event.sendCallback)
2140 // Update Host
2141 pData->engine->callback(true, true,
2142 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
2143 pData->id,
2144 event.parameter.index,
2145 0, 0,
2146 event.parameter.value,
2147 nullptr);
2149 } break;
2151 case kPluginPostRtEventProgramChange: {
2152 // Update UI
2153 if (hasUI)
2155 if (needsUiMainThread)
2156 pData->postUiEvents.append(event);
2157 else
2158 uiProgramChange(event.program.index);
2161 // Update param values
2162 for (uint32_t j=0; j < pData->param.count; ++j)
2164 const float paramDefault(pData->param.ranges[j].def);
2165 const float paramValue(getParameterValue(j));
2167 pData->engine->callback(true, true,
2168 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
2169 pData->id,
2170 static_cast<int>(j),
2171 0, 0,
2172 paramValue,
2173 nullptr);
2174 pData->engine->callback(true, true,
2175 ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
2176 pData->id,
2177 static_cast<int>(j),
2178 0, 0,
2179 paramDefault,
2180 nullptr);
2183 if (event.sendCallback)
2185 // Update Host
2186 pData->engine->callback(true, true,
2187 ENGINE_CALLBACK_PROGRAM_CHANGED,
2188 pData->id,
2189 static_cast<int>(event.program.index),
2190 0, 0, 0.0f, nullptr);
2192 } break;
2194 case kPluginPostRtEventMidiProgramChange: {
2195 // Update UI
2196 if (hasUI)
2198 if (needsUiMainThread)
2199 pData->postUiEvents.append(event);
2200 else
2201 uiMidiProgramChange(event.program.index);
2204 // Update param values
2205 for (uint32_t j=0; j < pData->param.count; ++j)
2207 const float paramDefault(pData->param.ranges[j].def);
2208 const float paramValue(getParameterValue(j));
2210 pData->engine->callback(true, true,
2211 ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
2212 pData->id,
2213 static_cast<int>(j),
2214 0, 0,
2215 paramValue,
2216 nullptr);
2217 pData->engine->callback(true, true,
2218 ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
2219 pData->id,
2220 static_cast<int>(j),
2221 0, 0,
2222 paramDefault,
2223 nullptr);
2226 if (event.sendCallback)
2228 // Update Host
2229 pData->engine->callback(true, true,
2230 ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
2231 pData->id,
2232 static_cast<int>(event.program.index),
2233 0, 0, 0.0f, nullptr);
2235 } break;
2237 case kPluginPostRtEventNoteOn: {
2238 CARLA_SAFE_ASSERT_BREAK(event.note.channel < MAX_MIDI_CHANNELS);
2239 CARLA_SAFE_ASSERT_BREAK(event.note.note < MAX_MIDI_NOTE);
2240 CARLA_SAFE_ASSERT_BREAK(event.note.velocity < MAX_MIDI_VALUE);
2242 // Update UI
2243 if (hasUI)
2245 if (needsUiMainThread)
2246 pData->postUiEvents.append(event);
2247 else
2248 uiNoteOn(event.note.channel, event.note.note, event.note.velocity);
2251 if (event.sendCallback)
2253 // Update Host
2254 pData->engine->callback(true, true,
2255 ENGINE_CALLBACK_NOTE_ON,
2256 pData->id,
2257 static_cast<int>(event.note.channel),
2258 static_cast<int>(event.note.note),
2259 static_cast<int>(event.note.velocity),
2260 0.0f, nullptr);
2262 } break;
2264 case kPluginPostRtEventNoteOff: {
2265 CARLA_SAFE_ASSERT_BREAK(event.note.channel < MAX_MIDI_CHANNELS);
2266 CARLA_SAFE_ASSERT_BREAK(event.note.note < MAX_MIDI_NOTE);
2268 // Update UI
2269 if (hasUI)
2271 if (needsUiMainThread)
2272 pData->postUiEvents.append(event);
2273 else
2274 uiNoteOff(event.note.channel, event.note.note);
2277 if (event.sendCallback)
2279 // Update Host
2280 pData->engine->callback(true, true,
2281 ENGINE_CALLBACK_NOTE_OFF,
2282 pData->id,
2283 static_cast<int>(event.note.channel),
2284 static_cast<int>(event.note.note),
2285 0, 0.0f, nullptr);
2287 } break;
2289 case kPluginPostRtEventMidiLearn: {
2290 CARLA_SAFE_ASSERT_BREAK(event.midiLearn.cc < MAX_MIDI_VALUE);
2291 CARLA_SAFE_ASSERT_BREAK(event.midiLearn.channel < MAX_MIDI_CHANNELS);
2293 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2294 if (event.sendCallback)
2296 pData->engine->callback(true, true,
2297 ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED,
2298 pData->id,
2299 static_cast<int>(event.midiLearn.parameter),
2300 static_cast<int>(event.midiLearn.cc),
2301 0, 0.0f, nullptr);
2303 pData->engine->callback(true, true,
2304 ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED,
2305 pData->id,
2306 static_cast<int>(event.midiLearn.parameter),
2307 static_cast<int>(event.midiLearn.channel),
2308 0, 0.0f, nullptr);
2310 #endif
2311 } break;
2316 bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept
2318 if (forcedOffline)
2320 #ifndef STOAT_TEST_BUILD
2321 pData->masterMutex.lock();
2322 return true;
2323 #endif
2326 return pData->masterMutex.tryLock();
2329 void CarlaPlugin::unlock() noexcept
2331 pData->masterMutex.unlock();
2334 // -------------------------------------------------------------------
2335 // Plugin buffers
2337 void CarlaPlugin::initBuffers() const noexcept
2339 pData->audioIn.initBuffers();
2340 pData->audioOut.initBuffers();
2341 pData->cvIn.initBuffers();
2342 pData->cvOut.initBuffers();
2343 pData->event.initBuffers();
2346 void CarlaPlugin::clearBuffers() noexcept
2348 pData->clearBuffers();
2351 // -------------------------------------------------------------------
2352 // OSC stuff
2354 // FIXME
2355 void CarlaPlugin::handleOscMessage(const char*, int, const void*, const char*, void*)
2357 // do nothing
2360 // -------------------------------------------------------------------
2361 // MIDI events
2363 void CarlaPlugin::sendMidiSingleNote(const uint8_t channel, const uint8_t note, const uint8_t velo, const bool sendGui, const bool sendOsc, const bool sendCallback)
2365 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2366 CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2367 CARLA_SAFE_ASSERT_RETURN(velo < MAX_MIDI_VALUE,);
2369 if (! pData->active)
2370 return;
2372 ExternalMidiNote extNote;
2373 extNote.channel = static_cast<int8_t>(channel);
2374 extNote.note = note;
2375 extNote.velo = velo;
2377 pData->extNotes.appendNonRT(extNote);
2379 if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
2381 if (velo > 0)
2382 uiNoteOn(channel, note, velo);
2383 else
2384 uiNoteOff(channel, note);
2387 pData->engine->callback(sendCallback, sendOsc,
2388 (velo > 0) ? ENGINE_CALLBACK_NOTE_ON : ENGINE_CALLBACK_NOTE_OFF,
2389 pData->id,
2390 channel,
2391 note,
2392 velo,
2393 0.0f, nullptr);
2396 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2397 void CarlaPlugin::postponeRtAllNotesOff()
2399 if (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS)
2400 return;
2402 PluginPostRtEvent postEvent = { kPluginPostRtEventNoteOff, true, {} };
2403 postEvent.note.channel = static_cast<uint8_t>(pData->ctrlChannel);
2405 for (uint8_t i=0; i < MAX_MIDI_NOTE; ++i)
2407 postEvent.note.note = i;
2408 pData->postRtEvents.appendRT(postEvent);
2411 #endif
2413 // -------------------------------------------------------------------
2414 // UI Stuff
2416 void CarlaPlugin::setCustomUITitle(const char* const title) noexcept
2418 pData->uiTitle = title;
2421 void CarlaPlugin::showCustomUI(const bool yesNo)
2423 if (yesNo) {
2424 CARLA_SAFE_ASSERT(false);
2428 void* CarlaPlugin::embedCustomUI(void*)
2430 return nullptr;
2433 void CarlaPlugin::uiIdle()
2435 if (pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD)
2437 // Update parameter outputs
2438 for (uint32_t i=0; i < pData->param.count; ++i)
2440 if (pData->param.data[i].type == PARAMETER_OUTPUT)
2441 uiParameterChange(i, getParameterValue(i));
2444 const CarlaMutexLocker sl(pData->postUiEvents.mutex);
2446 for (LinkedList<PluginPostRtEvent>::Itenerator it = pData->postUiEvents.data.begin2(); it.valid(); it.next())
2448 const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
2449 CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
2451 switch (event.type)
2453 case kPluginPostRtEventNull:
2454 case kPluginPostRtEventMidiLearn:
2455 break;
2457 case kPluginPostRtEventParameterChange:
2458 uiParameterChange(static_cast<uint32_t>(event.parameter.index), event.parameter.value);
2459 break;
2461 case kPluginPostRtEventProgramChange:
2462 uiProgramChange(event.program.index);
2463 break;
2465 case kPluginPostRtEventMidiProgramChange:
2466 uiMidiProgramChange(event.program.index);
2467 break;
2469 case kPluginPostRtEventNoteOn:
2470 uiNoteOn(event.note.channel, event.note.note, event.note.velocity);
2471 break;
2473 case kPluginPostRtEventNoteOff:
2474 uiNoteOff(event.note.channel, event.note.note);
2475 break;
2479 pData->postUiEvents.data.clear();
2482 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2483 if (pData->transientTryCounter == 0)
2484 return;
2485 if (++pData->transientTryCounter % 10 != 0)
2486 return;
2487 if (pData->transientTryCounter >= 200)
2488 return;
2490 carla_stdout("Trying to get window...");
2492 CarlaString uiTitle;
2494 if (pData->uiTitle.isNotEmpty())
2496 uiTitle = pData->uiTitle;
2498 else
2500 uiTitle = pData->name;
2501 uiTitle += " (GUI)";
2504 if (CarlaPluginUI::tryTransientWinIdMatch(getUiBridgeProcessId(), uiTitle,
2505 pData->engine->getOptions().frontendWinId, pData->transientFirstTry))
2507 pData->transientTryCounter = 0;
2508 pData->transientFirstTry = false;
2510 #endif
2513 void CarlaPlugin::uiParameterChange(const uint32_t index, const float value) noexcept
2515 CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
2516 return;
2518 // unused
2519 (void)value;
2522 void CarlaPlugin::uiProgramChange(const uint32_t index) noexcept
2524 CARLA_SAFE_ASSERT_RETURN(index < getProgramCount(),);
2527 void CarlaPlugin::uiMidiProgramChange(const uint32_t index) noexcept
2529 CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(),);
2532 void CarlaPlugin::uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept
2534 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2535 CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2536 CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
2539 void CarlaPlugin::uiNoteOff(const uint8_t channel, const uint8_t note) noexcept
2541 CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2542 CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2545 CarlaEngine* CarlaPlugin::getEngine() const noexcept
2547 return pData->engine;
2550 CarlaEngineClient* CarlaPlugin::getEngineClient() const noexcept
2552 return pData->client;
2555 CarlaEngineAudioPort* CarlaPlugin::getAudioInPort(const uint32_t index) const noexcept
2557 return pData->audioIn.ports[index].port;
2560 CarlaEngineAudioPort* CarlaPlugin::getAudioOutPort(const uint32_t index) const noexcept
2562 return pData->audioOut.ports[index].port;
2565 CarlaEngineCVPort* CarlaPlugin::getCVInPort(const uint32_t index) const noexcept
2567 return pData->cvIn.ports[index].port;
2570 CarlaEngineCVPort* CarlaPlugin::getCVOutPort(const uint32_t index) const noexcept
2572 return pData->cvOut.ports[index].port;
2575 CarlaEngineEventPort* CarlaPlugin::getDefaultEventInPort() const noexcept
2577 return pData->event.portIn;
2580 CarlaEngineEventPort* CarlaPlugin::getDefaultEventOutPort() const noexcept
2582 return pData->event.portOut;
2585 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2586 void CarlaPlugin::checkForMidiLearn(EngineEvent& event) noexcept
2588 if (pData->midiLearnParameterIndex < 0)
2589 return;
2590 if (event.ctrl.param == MIDI_CONTROL_BANK_SELECT || event.ctrl.param == MIDI_CONTROL_BANK_SELECT__LSB)
2591 return;
2592 if (event.ctrl.param >= MAX_MIDI_CONTROL)
2593 return;
2595 const uint32_t parameterId = static_cast<uint32_t>(pData->midiLearnParameterIndex);
2596 CARLA_SAFE_ASSERT_UINT2_RETURN(parameterId < pData->param.count, parameterId, pData->param.count,);
2598 ParameterData& paramData(pData->param.data[parameterId]);
2599 CARLA_SAFE_ASSERT_INT_RETURN(paramData.mappedControlIndex == CONTROL_INDEX_MIDI_LEARN,
2600 paramData.mappedControlIndex,);
2602 event.ctrl.handled = true;
2603 paramData.mappedControlIndex = static_cast<int16_t>(event.ctrl.param);
2604 paramData.midiChannel = event.channel;
2606 pData->postponeMidiLearnRtEvent(true, parameterId, static_cast<uint8_t>(event.ctrl.param), event.channel);
2607 pData->midiLearnParameterIndex = -1;
2609 #endif
2611 void* CarlaPlugin::getNativeHandle() const noexcept
2613 return nullptr;
2616 const void* CarlaPlugin::getNativeDescriptor() const noexcept
2618 return nullptr;
2621 uintptr_t CarlaPlugin::getUiBridgeProcessId() const noexcept
2623 return 0;
2626 // -------------------------------------------------------------------
2628 uint32_t CarlaPlugin::getPatchbayNodeId() const noexcept
2630 return pData->nodeId;
2633 void CarlaPlugin::setPatchbayNodeId(const uint32_t nodeId) noexcept
2635 pData->nodeId = nodeId;
2638 // -------------------------------------------------------------------
2640 void CarlaPlugin::cloneLV2Files(const CarlaPlugin&)
2642 carla_stderr2("Warning: cloneLV2Files() called for non-implemented type");
2645 void CarlaPlugin::restoreLV2State(const bool temporary) noexcept
2647 carla_stderr2("Warning: restoreLV2State(%s) called for non-implemented type", bool2str(temporary));
2650 void CarlaPlugin::prepareForDeletion() noexcept
2652 carla_debug("CarlaPlugin::prepareForDeletion");
2654 const CarlaMutexLocker cml(pData->masterMutex);
2656 pData->client->deactivate(true);
2659 void CarlaPlugin::waitForBridgeSaveSignal() noexcept
2663 // -------------------------------------------------------------------
2664 // Scoped Disabler
2666 CarlaPlugin::ScopedDisabler::ScopedDisabler(CarlaPlugin* const plugin) noexcept
2667 : fPlugin(plugin),
2668 fWasEnabled(false)
2670 CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
2671 CARLA_SAFE_ASSERT_RETURN(plugin->pData != nullptr,);
2672 CARLA_SAFE_ASSERT_RETURN(plugin->pData->client != nullptr,);
2673 carla_debug("CarlaPlugin::ScopedDisabler(%p)", plugin);
2675 plugin->pData->masterMutex.lock();
2677 if (plugin->pData->enabled)
2679 fWasEnabled = true;
2680 plugin->pData->enabled = false;
2682 if (plugin->pData->client->isActive())
2683 plugin->pData->client->deactivate(false);
2687 CarlaPlugin::ScopedDisabler::~ScopedDisabler() noexcept
2689 CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
2690 CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
2691 CARLA_SAFE_ASSERT_RETURN(fPlugin->pData->client != nullptr,);
2692 carla_debug("CarlaPlugin::~ScopedDisabler()");
2694 if (fWasEnabled)
2696 fPlugin->pData->enabled = true;
2697 fPlugin->pData->client->activate();
2700 fPlugin->pData->masterMutex.unlock();
2703 // -------------------------------------------------------------------
2704 // Scoped Process Locker
2706 CarlaPlugin::ScopedSingleProcessLocker::ScopedSingleProcessLocker(CarlaPlugin* const plugin, const bool block) noexcept
2707 : fPlugin(plugin),
2708 fBlock(block)
2710 CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
2711 CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
2712 carla_debug("CarlaPlugin::ScopedSingleProcessLocker(%p, %s)", plugin, bool2str(block));
2714 if (! fBlock)
2715 return;
2717 plugin->pData->singleMutex.lock();
2720 CarlaPlugin::ScopedSingleProcessLocker::~ScopedSingleProcessLocker() noexcept
2722 CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
2723 CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
2724 carla_debug("CarlaPlugin::~ScopedSingleProcessLocker()");
2726 if (! fBlock)
2727 return;
2729 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2730 if (fPlugin->pData->singleMutex.wasTryLockCalled())
2731 fPlugin->pData->needsReset = true;
2732 #endif
2734 fPlugin->pData->singleMutex.unlock();
2737 // -------------------------------------------------------------------
2739 CARLA_BACKEND_END_NAMESPACE