1 /*
2  * Carla Plugin
3  * Copyright (C) 2011-2020 Filipe Coelho <falktx@falktx.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
16  */
17 
18 #include "CarlaPluginInternal.hpp"
19 #include "CarlaEngine.hpp"
20 
21 #include "CarlaBackendUtils.hpp"
22 #include "CarlaBase64Utils.hpp"
23 #include "CarlaMathUtils.hpp"
24 #include "CarlaMIDI.h"
25 #include "CarlaPluginUI.hpp"
26 #include "CarlaScopeUtils.hpp"
27 #include "CarlaStringList.hpp"
28 
29 #include <ctime>
30 
31 #include "water/files/File.h"
32 #include "water/streams/MemoryOutputStream.h"
33 #include "water/xml/XmlDocument.h"
34 #include "water/xml/XmlElement.h"
35 
36 using water::CharPointer_UTF8;
37 using water::File;
38 using water::MemoryOutputStream;
39 using water::Result;
40 using water::String;
41 using water::XmlDocument;
42 using water::XmlElement;
43 
44 CARLA_BACKEND_START_NAMESPACE
45 
46 // -------------------------------------------------------------------------------------------------------------------
47 // Fallback data
48 
49 static const ParameterData   kParameterDataNull   = { PARAMETER_UNKNOWN, 0x0, PARAMETER_NULL, -1, 0, CONTROL_INDEX_NONE, 0.0f, 1.0f, 0x0 };
50 static const ParameterRanges kParameterRangesNull = { 0.0f, 0.0f, 1.0f, 0.01f, 0.0001f, 0.1f };
51 static const MidiProgramData kMidiProgramDataNull = { 0, 0, nullptr };
52 
53 static const CustomData        kCustomDataFallback        = { nullptr, nullptr, nullptr };
54 static /* */ CustomData        kCustomDataFallbackNC      = { nullptr, nullptr, nullptr };
55 static const PluginPostRtEvent kPluginPostRtEventFallback = { kPluginPostRtEventNull, false, {} };
56 
57 // -------------------------------------------------------------------------------------------------------------------
58 // ParamSymbol struct, needed for CarlaPlugin::loadStateSave()
59 
60 struct ParamSymbol {
61     int32_t index;
62     const char* symbol;
63 
ParamSymbolParamSymbol64     ParamSymbol(const uint32_t i, const char* const s)
65         : index(static_cast<int32_t>(i)),
66           symbol(carla_strdup(s)) {}
67 
~ParamSymbolParamSymbol68     ~ParamSymbol() noexcept
69     {
70         CARLA_SAFE_ASSERT_RETURN(symbol != nullptr,)
71 
72         delete[] symbol;
73         symbol = nullptr;
74     }
75 
76 #ifdef CARLA_PROPER_CPP11_SUPPORT
77     ParamSymbol() = delete;
78     CARLA_DECLARE_NON_COPY_STRUCT(ParamSymbol)
79 #endif
80 };
81 
82 // -------------------------------------------------------------------------------------------------------------------
83 // Constructor and destructor
84 
CarlaPlugin(CarlaEngine * const engine,const uint id)85 CarlaPlugin::CarlaPlugin(CarlaEngine* const engine, const uint id)
86     : pData(new ProtectedData(engine, id))
87 {
88     CARLA_SAFE_ASSERT_RETURN(engine != nullptr,);
89     CARLA_SAFE_ASSERT(id < engine->getMaxPluginNumber());
90     carla_debug("CarlaPlugin::CarlaPlugin(%p, %i)", engine, id);
91 
92     switch (engine->getProccessMode())
93     {
94     case ENGINE_PROCESS_MODE_SINGLE_CLIENT:
95     case ENGINE_PROCESS_MODE_MULTIPLE_CLIENTS:
96         CARLA_SAFE_ASSERT(id < MAX_DEFAULT_PLUGINS);
97         break;
98 
99     case ENGINE_PROCESS_MODE_CONTINUOUS_RACK:
100         CARLA_SAFE_ASSERT(id < MAX_RACK_PLUGINS);
101         break;
102 
103     case ENGINE_PROCESS_MODE_PATCHBAY:
104         CARLA_SAFE_ASSERT(id < MAX_PATCHBAY_PLUGINS);
105         break;
106 
107     case ENGINE_PROCESS_MODE_BRIDGE:
108         CARLA_SAFE_ASSERT(id == 0);
109         break;
110     }
111 }
112 
~CarlaPlugin()113 CarlaPlugin::~CarlaPlugin()
114 {
115     carla_debug("CarlaPlugin::~CarlaPlugin()");
116 
117     delete pData;
118 }
119 
120 // -------------------------------------------------------------------
121 // Information (base)
122 
getId() const123 uint CarlaPlugin::getId() const noexcept
124 {
125     return pData->id;
126 }
127 
getHints() const128 uint CarlaPlugin::getHints() const noexcept
129 {
130     return pData->hints;
131 }
132 
getOptionsEnabled() const133 uint CarlaPlugin::getOptionsEnabled() const noexcept
134 {
135     return pData->options;
136 }
137 
isEnabled() const138 bool CarlaPlugin::isEnabled() const noexcept
139 {
140     return pData->enabled;
141 }
142 
getName() const143 const char* CarlaPlugin::getName() const noexcept
144 {
145     return pData->name;
146 }
147 
getFilename() const148 const char* CarlaPlugin::getFilename() const noexcept
149 {
150     return pData->filename;
151 }
152 
getIconName() const153 const char* CarlaPlugin::getIconName() const noexcept
154 {
155     return pData->iconName;
156 }
157 
getCategory() const158 PluginCategory CarlaPlugin::getCategory() const noexcept
159 {
160     return getPluginCategoryFromName(pData->name);
161 }
162 
getUniqueId() const163 int64_t CarlaPlugin::getUniqueId() const noexcept
164 {
165     return 0;
166 }
167 
getLatencyInFrames() const168 uint32_t CarlaPlugin::getLatencyInFrames() const noexcept
169 {
170     return 0;
171 }
172 
173 // -------------------------------------------------------------------
174 // Information (count)
175 
getAudioInCount() const176 uint32_t CarlaPlugin::getAudioInCount() const noexcept
177 {
178     return pData->audioIn.count;
179 }
180 
getAudioOutCount() const181 uint32_t CarlaPlugin::getAudioOutCount() const noexcept
182 {
183     return pData->audioOut.count;
184 }
185 
getCVInCount() const186 uint32_t CarlaPlugin::getCVInCount() const noexcept
187 {
188     return pData->cvIn.count;
189 }
190 
getCVOutCount() const191 uint32_t CarlaPlugin::getCVOutCount() const noexcept
192 {
193     return pData->cvOut.count;
194 }
195 
getMidiInCount() const196 uint32_t CarlaPlugin::getMidiInCount() const noexcept
197 {
198     return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_IN) ? 1 : 0;
199 }
200 
getMidiOutCount() const201 uint32_t CarlaPlugin::getMidiOutCount() const noexcept
202 {
203     return (pData->extraHints & PLUGIN_EXTRA_HINT_HAS_MIDI_OUT) ? 1 : 0;
204 }
205 
getParameterCount() const206 uint32_t CarlaPlugin::getParameterCount() const noexcept
207 {
208     return pData->param.count;
209 }
210 
getParameterScalePointCount(const uint32_t parameterId) const211 uint32_t CarlaPlugin::getParameterScalePointCount(const uint32_t parameterId) const noexcept
212 {
213     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0);
214     return 0;
215 }
216 
getProgramCount() const217 uint32_t CarlaPlugin::getProgramCount() const noexcept
218 {
219     return pData->prog.count;
220 }
221 
getMidiProgramCount() const222 uint32_t CarlaPlugin::getMidiProgramCount() const noexcept
223 {
224     return pData->midiprog.count;
225 }
226 
getCustomDataCount() const227 uint32_t CarlaPlugin::getCustomDataCount() const noexcept
228 {
229     return static_cast<uint32_t>(pData->custom.count());
230 }
231 
232 // -------------------------------------------------------------------
233 // Information (current data)
234 
getCurrentProgram() const235 int32_t CarlaPlugin::getCurrentProgram() const noexcept
236 {
237     return pData->prog.current;
238 }
239 
getCurrentMidiProgram() const240 int32_t CarlaPlugin::getCurrentMidiProgram() const noexcept
241 {
242     return pData->midiprog.current;
243 }
244 
getParameterData(const uint32_t parameterId) const245 const ParameterData& CarlaPlugin::getParameterData(const uint32_t parameterId) const noexcept
246 {
247     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterDataNull);
248     return pData->param.data[parameterId];
249 }
250 
getParameterRanges(const uint32_t parameterId) const251 const ParameterRanges& CarlaPlugin::getParameterRanges(const uint32_t parameterId) const noexcept
252 {
253     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, kParameterRangesNull);
254     return pData->param.ranges[parameterId];
255 }
256 
isParameterOutput(const uint32_t parameterId) const257 bool CarlaPlugin::isParameterOutput(const uint32_t parameterId) const noexcept
258 {
259     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
260     return (pData->param.data[parameterId].type == PARAMETER_OUTPUT);
261 }
262 
getMidiProgramData(const uint32_t index) const263 const MidiProgramData& CarlaPlugin::getMidiProgramData(const uint32_t index) const noexcept
264 {
265     CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, kMidiProgramDataNull);
266     return pData->midiprog.data[index];
267 }
268 
getCustomData(const uint32_t index) const269 const CustomData& CarlaPlugin::getCustomData(const uint32_t index) const noexcept
270 {
271     return pData->custom.getAt(index, kCustomDataFallback);
272 }
273 
getChunkData(void ** const dataPtr)274 std::size_t CarlaPlugin::getChunkData(void** const dataPtr) noexcept
275 {
276     CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0);
277     CARLA_SAFE_ASSERT(false); // this should never happen
278     return 0;
279 }
280 
281 // -------------------------------------------------------------------
282 // Information (per-plugin data)
283 
getOptionsAvailable() const284 uint CarlaPlugin::getOptionsAvailable() const noexcept
285 {
286     CARLA_SAFE_ASSERT(false); // this should never happen
287     return 0x0;
288 }
289 
getParameterValue(const uint32_t parameterId) const290 float CarlaPlugin::getParameterValue(const uint32_t parameterId) const noexcept
291 {
292     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
293     CARLA_SAFE_ASSERT(false); // this should never happen
294     return 0.0f;
295 }
296 
getParameterScalePointValue(const uint32_t parameterId,const uint32_t scalePointId) const297 float CarlaPlugin::getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) const noexcept
298 {
299     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), 0.0f);
300     CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), 0.0f);
301     CARLA_SAFE_ASSERT(false); // this should never happen
302     return 0.0f;
303 }
304 
getLabel(char * const strBuf) const305 bool CarlaPlugin::getLabel(char* const strBuf) const noexcept
306 {
307     strBuf[0] = '\0';
308     return false;
309 }
310 
getMaker(char * const strBuf) const311 bool CarlaPlugin::getMaker(char* const strBuf) const noexcept
312 {
313     strBuf[0] = '\0';
314     return false;
315 }
316 
getCopyright(char * const strBuf) const317 bool CarlaPlugin::getCopyright(char* const strBuf) const noexcept
318 {
319     strBuf[0] = '\0';
320     return false;
321 }
322 
getRealName(char * const strBuf) const323 bool CarlaPlugin::getRealName(char* const strBuf) const noexcept
324 {
325     strBuf[0] = '\0';
326     return false;
327 }
328 
getParameterName(const uint32_t parameterId,char * const strBuf) const329 bool CarlaPlugin::getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept
330 {
331     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
332     CARLA_SAFE_ASSERT(false); // this should never happen
333     strBuf[0] = '\0';
334     return false;
335 }
336 
getParameterSymbol(const uint32_t parameterId,char * const strBuf) const337 bool CarlaPlugin::getParameterSymbol(const uint32_t parameterId, char* const strBuf) const noexcept
338 {
339     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
340     strBuf[0] = '\0';
341     return false;
342 }
343 
getParameterText(const uint32_t parameterId,char * const strBuf)344 bool CarlaPlugin::getParameterText(const uint32_t parameterId, char* const strBuf) noexcept
345 {
346     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
347     CARLA_SAFE_ASSERT(false); // this should never happen
348     strBuf[0] = '\0';
349     return false;
350 }
351 
getParameterUnit(const uint32_t parameterId,char * const strBuf) const352 bool CarlaPlugin::getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept
353 {
354     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
355     strBuf[0] = '\0';
356     return false;
357 }
358 
getParameterComment(const uint32_t parameterId,char * const strBuf) const359 bool CarlaPlugin::getParameterComment(const uint32_t parameterId, char* const strBuf) const noexcept
360 {
361     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
362     strBuf[0] = '\0';
363     return false;
364 }
365 
getParameterGroupName(const uint32_t parameterId,char * const strBuf) const366 bool CarlaPlugin::getParameterGroupName(const uint32_t parameterId, char* const strBuf) const noexcept
367 {
368     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
369     strBuf[0] = '\0';
370     return false;
371 }
372 
getParameterScalePointLabel(const uint32_t parameterId,const uint32_t scalePointId,char * const strBuf) const373 bool CarlaPlugin::getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) const noexcept
374 {
375     CARLA_SAFE_ASSERT_RETURN(parameterId < getParameterCount(), false);
376     CARLA_SAFE_ASSERT_RETURN(scalePointId < getParameterScalePointCount(parameterId), false);
377     CARLA_SAFE_ASSERT(false); // this should never happen
378     strBuf[0] = '\0';
379     return false;
380 }
381 
getInternalParameterValue(const int32_t parameterId) const382 float CarlaPlugin::getInternalParameterValue(const int32_t parameterId) const noexcept
383 {
384 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
385     CARLA_SAFE_ASSERT_RETURN(parameterId != PARAMETER_NULL && parameterId > PARAMETER_MAX, 0.0f);
386 
387     switch (parameterId)
388     {
389     case PARAMETER_ACTIVE:
390         return pData->active;
391     case PARAMETER_CTRL_CHANNEL:
392         return pData->ctrlChannel;
393     case PARAMETER_DRYWET:
394         return pData->postProc.dryWet;
395     case PARAMETER_VOLUME:
396         return pData->postProc.volume;
397     case PARAMETER_BALANCE_LEFT:
398         return pData->postProc.balanceLeft;
399     case PARAMETER_BALANCE_RIGHT:
400         return pData->postProc.balanceRight;
401     case PARAMETER_PANNING:
402         return pData->postProc.panning;
403     };
404 #endif
405     CARLA_SAFE_ASSERT_RETURN(parameterId >= 0, 0.0f);
406 
407     return getParameterValue(static_cast<uint32_t>(parameterId));
408 }
409 
getProgramName(const uint32_t index,char * const strBuf) const410 bool CarlaPlugin::getProgramName(const uint32_t index, char* const strBuf) const noexcept
411 {
412     CARLA_SAFE_ASSERT_RETURN(index < pData->prog.count, false);
413     CARLA_SAFE_ASSERT_RETURN(pData->prog.names[index] != nullptr, false);
414     std::strncpy(strBuf, pData->prog.names[index], STR_MAX);
415     return true;
416 }
417 
getMidiProgramName(const uint32_t index,char * const strBuf) const418 bool CarlaPlugin::getMidiProgramName(const uint32_t index, char* const strBuf) const noexcept
419 {
420     CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count, false);
421     CARLA_SAFE_ASSERT_RETURN(pData->midiprog.data[index].name != nullptr, false);
422     std::strncpy(strBuf, pData->midiprog.data[index].name, STR_MAX);
423     return true;
424 }
425 
getParameterCountInfo(uint32_t & ins,uint32_t & outs) const426 void CarlaPlugin::getParameterCountInfo(uint32_t& ins, uint32_t& outs) const noexcept
427 {
428     ins  = 0;
429     outs = 0;
430 
431     for (uint32_t i=0; i < pData->param.count; ++i)
432     {
433         if (pData->param.data[i].type == PARAMETER_INPUT)
434             ++ins;
435         else if (pData->param.data[i].type == PARAMETER_OUTPUT)
436             ++outs;
437     }
438 }
439 
440 // -------------------------------------------------------------------
441 // Set data (state)
442 
prepareForSave(bool)443 void CarlaPlugin::prepareForSave(bool)
444 {
445 }
446 
resetParameters()447 void CarlaPlugin::resetParameters() noexcept
448 {
449     for (uint i=0; i < pData->param.count; ++i)
450     {
451         const ParameterData&   paramData(pData->param.data[i]);
452         const ParameterRanges& paramRanges(pData->param.ranges[i]);
453 
454         if (paramData.type != PARAMETER_INPUT)
455             continue;
456         if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
457             continue;
458 
459         setParameterValue(i, paramRanges.def, true, true, true);
460     }
461 }
462 
randomizeParameters()463 void CarlaPlugin::randomizeParameters() noexcept
464 {
465     float value, random;
466 
467     char strBuf[STR_MAX+1];
468     strBuf[STR_MAX] = '\0';
469 
470     std::srand(static_cast<uint>(std::time(nullptr)));
471 
472     for (uint i=0; i < pData->param.count; ++i)
473     {
474         const ParameterData& paramData(pData->param.data[i]);
475 
476         if (paramData.type != PARAMETER_INPUT)
477             continue;
478         if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
479             continue;
480 
481         if (! getParameterName(i, strBuf))
482             strBuf[0] = '\0';
483 
484         if (std::strstr(strBuf, "olume") != nullptr)
485             continue;
486         if (std::strstr(strBuf, "Master") != nullptr)
487             continue;
488 
489         const ParameterRanges& paramRanges(pData->param.ranges[i]);
490 
491         if (paramData.hints & PARAMETER_IS_BOOLEAN)
492         {
493             random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
494             value  = random > 0.5f ? paramRanges.max : paramRanges.min;
495         }
496         else
497         {
498             random = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);
499             value  = random * (paramRanges.max - paramRanges.min) + paramRanges.min;
500 
501             if (paramData.hints & PARAMETER_IS_INTEGER)
502                 value = std::rint(value);
503         }
504 
505         setParameterValue(i, value, true, true, true);
506     }
507 }
508 
getStateSave(const bool callPrepareForSave)509 const CarlaStateSave& CarlaPlugin::getStateSave(const bool callPrepareForSave)
510 {
511     pData->stateSave.clear();
512 
513     if (callPrepareForSave)
514     {
515         pData->stateSave.temporary = true;
516         prepareForSave(true);
517     }
518 
519     const PluginType pluginType(getType());
520 
521     char strBuf[STR_MAX+1];
522     carla_zeroChars(strBuf, STR_MAX+1);
523 
524     // ---------------------------------------------------------------
525     // Basic info
526 
527     if (! getLabel(strBuf))
528         strBuf[0] = '\0';
529 
530     pData->stateSave.type     = carla_strdup(getPluginTypeAsString(pluginType));
531     pData->stateSave.name     = carla_strdup(pData->name);
532     pData->stateSave.label    = carla_strdup(strBuf);
533     pData->stateSave.uniqueId = getUniqueId();
534 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
535     pData->stateSave.options  = pData->options;
536 #endif
537 
538     if (pData->filename != nullptr)
539         pData->stateSave.binary = carla_strdup(pData->filename);
540 
541 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
542     // ---------------------------------------------------------------
543     // Internals
544 
545     pData->stateSave.active       = pData->active;
546     pData->stateSave.dryWet       = pData->postProc.dryWet;
547     pData->stateSave.volume       = pData->postProc.volume;
548     pData->stateSave.balanceLeft  = pData->postProc.balanceLeft;
549     pData->stateSave.balanceRight = pData->postProc.balanceRight;
550     pData->stateSave.panning      = pData->postProc.panning;
551     pData->stateSave.ctrlChannel  = pData->ctrlChannel;
552 #endif
553 
554     if (pData->hints & PLUGIN_IS_BRIDGE)
555         waitForBridgeSaveSignal();
556 
557     // ---------------------------------------------------------------
558     // Chunk
559 
560     bool usingChunk = false;
561 
562     if (pData->options & PLUGIN_OPTION_USE_CHUNKS)
563     {
564         void* data = nullptr;
565         const std::size_t dataSize(getChunkData(&data));
566 
567         if (data != nullptr && dataSize > 0)
568         {
569             pData->stateSave.chunk = CarlaString::asBase64(data, dataSize).dup();
570 
571             if (pluginType != PLUGIN_INTERNAL)
572                 usingChunk = true;
573         }
574     }
575 
576     // ---------------------------------------------------------------
577     // Current Program
578 
579     if (pData->prog.current >= 0 && pluginType != PLUGIN_LV2)
580     {
581         pData->stateSave.currentProgramIndex = pData->prog.current;
582         pData->stateSave.currentProgramName  = carla_strdup(pData->prog.names[pData->prog.current]);
583     }
584 
585     // ---------------------------------------------------------------
586     // Current MIDI Program
587 
588     if (pData->midiprog.current >= 0 && pluginType != PLUGIN_LV2 && pluginType != PLUGIN_SF2)
589     {
590         const MidiProgramData& mpData(pData->midiprog.getCurrent());
591 
592         pData->stateSave.currentMidiBank    = static_cast<int32_t>(mpData.bank);
593         pData->stateSave.currentMidiProgram = static_cast<int32_t>(mpData.program);
594     }
595 
596     // ---------------------------------------------------------------
597     // Parameters
598 
599     const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
600 
601     for (uint32_t i=0; i < pData->param.count; ++i)
602     {
603         const ParameterData& paramData(pData->param.data[i]);
604 
605         if ((paramData.hints & PARAMETER_IS_ENABLED) == 0)
606             continue;
607         if (paramData.hints & PARAMETER_IS_NOT_SAVED)
608             continue;
609 
610         const bool dummy = paramData.type != PARAMETER_INPUT || usingChunk;
611 
612         if (dummy && paramData.mappedControlIndex <= CONTROL_INDEX_NONE)
613             continue;
614 
615         CarlaStateSave::Parameter* const stateParameter(new CarlaStateSave::Parameter());
616 
617         stateParameter->dummy = dummy;
618         stateParameter->index = paramData.index;
619 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
620         if (paramData.mappedControlIndex != CONTROL_INDEX_MIDI_LEARN)
621         {
622             stateParameter->mappedControlIndex = paramData.mappedControlIndex;
623             stateParameter->midiChannel        = paramData.midiChannel;
624 
625             if (paramData.hints & PARAMETER_MAPPED_RANGES_SET)
626             {
627                 stateParameter->mappedMinimum = paramData.mappedMinimum;
628                 stateParameter->mappedMaximum = paramData.mappedMaximum;
629                 stateParameter->mappedRangeValid = true;
630 
631                 if (paramData.hints & PARAMETER_USES_SAMPLERATE)
632                 {
633                     stateParameter->mappedMinimum /= sampleRate;
634                     stateParameter->mappedMaximum /= sampleRate;
635                 }
636             }
637         }
638 #endif
639 
640         if (! getParameterName(i, strBuf))
641             strBuf[0] = '\0';
642         stateParameter->name = carla_strdup(strBuf);
643 
644         if (! getParameterSymbol(i, strBuf))
645             strBuf[0] = '\0';
646         stateParameter->symbol = carla_strdup(strBuf);;
647 
648         if (! dummy)
649         {
650             stateParameter->value = getParameterValue(i);
651 
652             if (paramData.hints & PARAMETER_USES_SAMPLERATE)
653                 stateParameter->value /= sampleRate;
654         }
655 
656         pData->stateSave.parameters.append(stateParameter);
657     }
658 
659     // ---------------------------------------------------------------
660     // Custom Data
661 
662     for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
663     {
664         const CustomData& cData(it.getValue(kCustomDataFallback));
665         CARLA_SAFE_ASSERT_CONTINUE(cData.isValid());
666 
667         CarlaStateSave::CustomData* stateCustomData(new CarlaStateSave::CustomData());
668 
669         stateCustomData->type  = carla_strdup(cData.type);
670         stateCustomData->key   = carla_strdup(cData.key);
671         stateCustomData->value = carla_strdup(cData.value);
672 
673         pData->stateSave.customData.append(stateCustomData);
674     }
675 
676     return pData->stateSave;
677 }
678 
loadStateSave(const CarlaStateSave & stateSave)679 void CarlaPlugin::loadStateSave(const CarlaStateSave& stateSave)
680 {
681     const bool usesMultiProgs(pData->hints & PLUGIN_USES_MULTI_PROGS);
682     const PluginType pluginType(getType());
683 
684     char strBuf[STR_MAX+1];
685     carla_zeroChars(strBuf, STR_MAX+1);
686 
687     // ---------------------------------------------------------------
688     // Part 1 - PRE-set custom data (only those which reload programs)
689 
690     for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
691     {
692         const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
693         CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
694         CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
695 
696         const char* const key(stateCustomData->key);
697 
698         /**/ if (pluginType == PLUGIN_DSSI && (std::strcmp (key, "reloadprograms") == 0 ||
699                                                std::strcmp (key, "load"          ) == 0 ||
700                                                std::strncmp(key, "patches",     7) == 0 ))
701             pass();
702         else if (usesMultiProgs && std::strcmp(key, "midiPrograms") == 0)
703             pass();
704         else
705             continue;
706 
707         setCustomData(stateCustomData->type, key, stateCustomData->value, true);
708     }
709 
710     // ---------------------------------------------------------------
711     // Part 2 - set program
712 
713     if (stateSave.currentProgramIndex >= 0 && stateSave.currentProgramName != nullptr)
714     {
715         int32_t programId = -1;
716 
717         // index < count
718         if (stateSave.currentProgramIndex < static_cast<int32_t>(pData->prog.count))
719         {
720             programId = stateSave.currentProgramIndex;
721         }
722         // index not valid, try to find by name
723         else
724         {
725             for (uint32_t i=0; i < pData->prog.count; ++i)
726             {
727                 if (getProgramName(i, strBuf) && std::strcmp(stateSave.currentProgramName, strBuf) == 0)
728                 {
729                     programId = static_cast<int32_t>(i);
730                     break;
731                 }
732             }
733         }
734 
735         // set program now, if valid
736         if (programId >= 0)
737             setProgram(programId, true, true, true);
738     }
739 
740     // ---------------------------------------------------------------
741     // Part 3 - set midi program
742 
743     if (stateSave.currentMidiBank >= 0 && stateSave.currentMidiProgram >= 0 && ! usesMultiProgs)
744         setMidiProgramById(static_cast<uint32_t>(stateSave.currentMidiBank), static_cast<uint32_t>(stateSave.currentMidiProgram), true, true, true);
745 
746     // ---------------------------------------------------------------
747     // Part 4a - get plugin parameter symbols
748 
749     LinkedList<ParamSymbol*> paramSymbols;
750 
751     if (pluginType == PLUGIN_LADSPA || pluginType == PLUGIN_LV2)
752     {
753         for (uint32_t i=0; i < pData->param.count; ++i)
754         {
755             if (pData->param.data[i].hints & PARAMETER_IS_NOT_SAVED)
756                 continue;
757 
758             if (getParameterSymbol(i, strBuf))
759             {
760                 ParamSymbol* const paramSymbol(new ParamSymbol(i, strBuf));
761                 paramSymbols.append(paramSymbol);
762             }
763         }
764     }
765 
766     // ---------------------------------------------------------------
767     // Part 4b - set parameter values (carefully)
768 
769     const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
770 
771     for (CarlaStateSave::ParameterItenerator it = stateSave.parameters.begin2(); it.valid(); it.next())
772     {
773         CarlaStateSave::Parameter* const stateParameter(it.getValue(nullptr));
774         CARLA_SAFE_ASSERT_CONTINUE(stateParameter != nullptr);
775 
776         int32_t index = -1;
777 
778         if (pluginType == PLUGIN_LADSPA)
779         {
780             // Try to set by symbol, otherwise use index
781             if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
782             {
783                 for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
784                 {
785                     ParamSymbol* const paramSymbol(it2.getValue(nullptr));
786                     CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
787                     CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
788 
789                     if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
790                     {
791                         index = paramSymbol->index;
792                         break;
793                     }
794                 }
795                 if (index == -1)
796                     index = stateParameter->index;
797             }
798             else
799             {
800                 index = stateParameter->index;
801             }
802         }
803         else if (pluginType == PLUGIN_LV2)
804         {
805             // Symbol only
806             if (stateParameter->symbol != nullptr && stateParameter->symbol[0] != '\0')
807             {
808                 for (LinkedList<ParamSymbol*>::Itenerator it2 = paramSymbols.begin2(); it2.valid(); it2.next())
809                 {
810                     ParamSymbol* const paramSymbol(it2.getValue(nullptr));
811                     CARLA_SAFE_ASSERT_CONTINUE(paramSymbol != nullptr);
812                     CARLA_SAFE_ASSERT_CONTINUE(paramSymbol->symbol != nullptr);
813 
814                     if (std::strcmp(stateParameter->symbol, paramSymbol->symbol) == 0)
815                     {
816                         index = paramSymbol->index;
817                         break;
818                     }
819                 }
820                 if (index == -1)
821                     carla_stderr("Failed to find LV2 parameter symbol '%s' for '%s'",
822                                  stateParameter->symbol, pData->name);
823             }
824             else
825             {
826                 carla_stderr("LV2 Plugin parameter '%s' has no symbol", stateParameter->name);
827             }
828         }
829         else
830         {
831             // Index only
832             index = stateParameter->index;
833         }
834 
835         // Now set parameter
836         if (index >= 0 && index < static_cast<int32_t>(pData->param.count))
837         {
838             //CARLA_SAFE_ASSERT(stateParameter->isInput == (pData
839 
840             if (! stateParameter->dummy)
841             {
842                 if (pData->param.data[index].hints & PARAMETER_USES_SAMPLERATE)
843                     stateParameter->value *= sampleRate;
844 
845                 setParameterValue(static_cast<uint32_t>(index), stateParameter->value, true, true, true);
846             }
847 
848 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
849             if (stateParameter->mappedRangeValid)
850             {
851                 if (pData->param.data[index].hints & PARAMETER_USES_SAMPLERATE)
852                 {
853                     stateParameter->mappedMinimum *= sampleRate;
854                     stateParameter->mappedMaximum *= sampleRate;
855                 }
856 
857                 setParameterMappedRange(static_cast<uint32_t>(index),
858                                         stateParameter->mappedMinimum,
859                                         stateParameter->mappedMaximum, true, true);
860             }
861 
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
866         }
867         else
868             carla_stderr("Could not set parameter '%s' value for '%s'",
869                          stateParameter->name, pData->name);
870     }
871 
872     // ---------------------------------------------------------------
873     // Part 4c - clear
874 
875     for (LinkedList<ParamSymbol*>::Itenerator it = paramSymbols.begin2(); it.valid(); it.next())
876     {
877         ParamSymbol* const paramSymbol(it.getValue(nullptr));
878         delete paramSymbol;
879     }
880 
881     paramSymbols.clear();
882 
883     // ---------------------------------------------------------------
884     // Part 5 - set custom data
885 
886     for (CarlaStateSave::CustomDataItenerator it = stateSave.customData.begin2(); it.valid(); it.next())
887     {
888         const CarlaStateSave::CustomData* const stateCustomData(it.getValue(nullptr));
889         CARLA_SAFE_ASSERT_CONTINUE(stateCustomData != nullptr);
890         CARLA_SAFE_ASSERT_CONTINUE(stateCustomData->isValid());
891 
892         const char* const key(stateCustomData->key);
893 
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;
900 
901         setCustomData(stateCustomData->type, key, stateCustomData->value, true);
902     }
903 
904     // ---------------------------------------------------------------
905     // Part 5x - set lv2 state
906 
907     if (pluginType == PLUGIN_LV2)
908     {
909         for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
910         {
911             const CustomData& customData(it.getValue(kCustomDataFallback));
912             CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
913 
914             if (std::strcmp(customData.type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
915                 continue;
916 
917             restoreLV2State(stateSave.temporary);
918             break;
919         }
920     }
921 
922     // ---------------------------------------------------------------
923     // Part 6 - set chunk
924 
925     if (stateSave.chunk != nullptr && (pData->options & PLUGIN_OPTION_USE_CHUNKS) != 0)
926     {
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
933     }
934 
935 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
936     // ---------------------------------------------------------------
937     // Part 6 - set internal stuff
938 
939     const uint availOptions(getOptionsAvailable());
940 
941     for (uint i=0; i<10; ++i) // FIXME - get this value somehow...
942     {
943         const uint option(1u << i);
944 
945         if (availOptions & option)
946             setOption(option, (stateSave.options & option) != 0, true);
947     }
948 
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);
956 
957     if (! pData->engine->isLoadingProject())
958         pData->engine->callback(true, true, ENGINE_CALLBACK_UPDATE, pData->id, 0, 0, 0, 0.0f, nullptr);
959 #endif
960 }
961 
saveStateToFile(const char * const filename)962 bool CarlaPlugin::saveStateToFile(const char* const filename)
963 {
964     CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
965     carla_debug("CarlaPlugin::saveStateToFile(\"%s\")", filename);
966 
967     MemoryOutputStream out, streamState;
968     getStateSave().dumpToMemoryStream(streamState);
969 
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";
975 
976     const String jfilename = String(CharPointer_UTF8(filename));
977     File file(jfilename);
978 
979     if (file.replaceWithData(out.getData(), out.getDataSize()))
980         return true;
981 
982     pData->engine->setLastError("Failed to write file");
983     return false;
984 }
985 
loadStateFromFile(const char * const filename)986 bool CarlaPlugin::loadStateFromFile(const char* const filename)
987 {
988     // TODO set errors
989 
990     CARLA_SAFE_ASSERT_RETURN(filename != nullptr && filename[0] != '\0', false);
991     carla_debug("CarlaPlugin::loadStateFromFile(\"%s\")", filename);
992 
993     const String jfilename = String(CharPointer_UTF8(filename));
994     File file(jfilename);
995     CARLA_SAFE_ASSERT_RETURN(file.existsAsFile(), false);
996 
997     XmlDocument xml(file);
998     CarlaScopedPointer<XmlElement> xmlElement(xml.getDocumentElement(true));
999     CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
1000     CARLA_SAFE_ASSERT_RETURN(xmlElement->getTagName().equalsIgnoreCase("carla-preset"), false);
1001 
1002     // completely load file
1003     xmlElement = xml.getDocumentElement(false);
1004     CARLA_SAFE_ASSERT_RETURN(xmlElement != nullptr, false);
1005 
1006     if (pData->stateSave.fillFromXmlElement(xmlElement))
1007     {
1008         loadStateSave(pData->stateSave);
1009         return true;
1010     }
1011 
1012     return false;
1013 }
1014 
exportAsLV2(const char * const lv2path)1015 bool CarlaPlugin::exportAsLV2(const char* const lv2path)
1016 {
1017     CARLA_SAFE_ASSERT_RETURN(lv2path != nullptr && lv2path[0] != '\0', false);
1018     carla_debug("CarlaPlugin::exportAsLV2(\"%s\")", lv2path);
1019 
1020     CarlaString bundlepath(lv2path);
1021 
1022     if (! bundlepath.endsWith(".lv2"))
1023         bundlepath += ".lv2";
1024 
1025     const File bundlefolder(bundlepath.buffer());
1026 
1027     if (bundlefolder.existsAsFile())
1028     {
1029         pData->engine->setLastError("Requested filename already exists as file, use a folder instead");
1030         return false;
1031     }
1032 
1033     if (! bundlefolder.exists())
1034     {
1035         const Result res(bundlefolder.createDirectory());
1036 
1037         if (res.failed())
1038         {
1039             pData->engine->setLastError(res.getErrorMessage().toRawUTF8());
1040             return false;
1041         }
1042     }
1043 
1044     CarlaString symbol(pData->name);
1045     symbol.toBasic();
1046 
1047     {
1048         const CarlaString pluginFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".xml");
1049 
1050         if (! saveStateToFile(pluginFilename))
1051             return false;
1052     }
1053 
1054     {
1055         MemoryOutputStream manifestStream;
1056 
1057         manifestStream << "@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .\n";
1058         manifestStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
1059         manifestStream << "@prefix ui:   <http://lv2plug.in/ns/extensions/ui#> .\n";
1060         manifestStream << "\n";
1061         manifestStream << "<" << symbol.buffer() << ".ttl>\n";
1062         manifestStream << "    a lv2:Plugin ;\n";
1063         manifestStream << "    lv2:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
1064         manifestStream << "    rdfs:seeAlso <" << symbol.buffer() << ".ttl> .\n";
1065         manifestStream << "\n";
1066         manifestStream << "<ext-ui>\n";
1067         manifestStream << "    a <http://kxstudio.sf.net/ns/lv2ext/external-ui#Widget> ;\n";
1068         manifestStream << "    ui:binary <" << symbol.buffer() << CARLA_LIB_EXT "> ;\n";
1069         manifestStream << "    lv2:extensionData <http://lv2plug.in/ns/extensions/ui#idleInterface> ,\n";
1070         manifestStream << "                      <http://lv2plug.in/ns/extensions/ui#showInterface> ;\n";
1071         manifestStream << "    lv2:requiredFeature <http://lv2plug.in/ns/ext/instance-access> .\n";
1072         manifestStream << "\n";
1073 
1074         const CarlaString manifestFilename(bundlepath + CARLA_OS_SEP_STR "manifest.ttl");
1075         const File manifestFile(manifestFilename.buffer());
1076 
1077         if (! manifestFile.replaceWithData(manifestStream.getData(), manifestStream.getDataSize()))
1078         {
1079             pData->engine->setLastError("Failed to write manifest.ttl file");
1080             return false;
1081         }
1082     }
1083 
1084     {
1085         MemoryOutputStream mainStream;
1086 
1087         mainStream << "@prefix atom: <http://lv2plug.in/ns/ext/atom#> .\n";
1088         mainStream << "@prefix doap: <http://usefulinc.com/ns/doap#> .\n";
1089         mainStream << "@prefix foaf: <http://xmlns.com/foaf/0.1/> .\n";
1090         mainStream << "@prefix lv2:  <http://lv2plug.in/ns/lv2core#> .\n";
1091         mainStream << "@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .\n";
1092         mainStream << "@prefix ui:   <http://lv2plug.in/ns/extensions/ui#> .\n";
1093         mainStream << "\n";
1094         mainStream << "<>\n";
1095         mainStream << "    a lv2:Plugin ;\n";
1096         mainStream << "\n";
1097         mainStream << "    lv2:requiredFeature <http://lv2plug.in/ns/ext/buf-size#boundedBlockLength> ,\n";
1098         mainStream << "                        <http://lv2plug.in/ns/ext/options#options> ,\n";
1099         mainStream << "                        <http://lv2plug.in/ns/ext/urid#map> ;\n";
1100         mainStream << "\n";
1101 
1102         if (pData->hints & PLUGIN_HAS_CUSTOM_UI)
1103         {
1104             mainStream << "    ui:ui <ext-ui> ;\n";
1105             mainStream << "\n";
1106         }
1107 
1108         const uint32_t midiIns  = getMidiInCount();
1109         const uint32_t midiOuts = getMidiOutCount();
1110 
1111         int portIndex = 0;
1112 
1113         if (midiIns > 0)
1114         {
1115             mainStream << "    lv2:port [\n";
1116             mainStream << "        a lv2:InputPort, atom:AtomPort ;\n";
1117             mainStream << "        lv2:index 0 ;\n";
1118             mainStream << "        lv2:symbol \"clv2_events_in\" ;\n";
1119             mainStream << "        lv2:name \"Events Input\" ;\n";
1120             mainStream << "        atom:bufferType atom:Sequence ;\n";
1121             mainStream << "        atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ,\n";
1122             mainStream << "                      <http://lv2plug.in/ns/ext/time#Position> ;\n";
1123             mainStream << "    ] ;\n";
1124             ++portIndex;
1125 
1126             for (uint32_t i=1; i<midiIns; ++i)
1127             {
1128                 const String portIndexNum(portIndex++);
1129                 const String portIndexLabel(portIndex);
1130 
1131                 mainStream << "    lv2:port [\n";
1132                 mainStream << "        a lv2:InputPort, atom:AtomPort ;\n";
1133                 mainStream << "        lv2:index " << portIndexNum << " ;\n";
1134                 mainStream << "        lv2:symbol \"clv2_midi_in_" << portIndexLabel << "\" ;\n";
1135                 mainStream << "        lv2:name \"MIDI Input " << portIndexLabel << "\" ;\n";
1136                 mainStream << "    ] ;\n";
1137             }
1138         }
1139         else
1140         {
1141             mainStream << "    lv2:port [\n";
1142             mainStream << "        a lv2:InputPort, atom:AtomPort ;\n";
1143             mainStream << "        lv2:index 0 ;\n";
1144             mainStream << "        lv2:symbol \"clv2_time_info\" ;\n";
1145             mainStream << "        lv2:name \"Time Info\" ;\n";
1146             mainStream << "        atom:bufferType atom:Sequence ;\n";
1147             mainStream << "        atom:supports <http://lv2plug.in/ns/ext/time#Position> ;\n";
1148             mainStream << "    ] ;\n";
1149             ++portIndex;
1150         }
1151 
1152         for (uint32_t i=0; i<midiOuts; ++i)
1153         {
1154             const String portIndexNum(portIndex++);
1155             const String portIndexLabel(portIndex);
1156 
1157             mainStream << "    lv2:port [\n";
1158             mainStream << "        a lv2:InputPort, atom:AtomPort ;\n";
1159             mainStream << "        lv2:index " << portIndexNum << " ;\n";
1160             mainStream << "        lv2:symbol \"clv2_midi_out_" << portIndexLabel << "\" ;\n";
1161             mainStream << "        lv2:name \"MIDI Output " << portIndexLabel << "\" ;\n";
1162             mainStream << "        atom:bufferType atom:Sequence ;\n";
1163             mainStream << "        atom:supports <http://lv2plug.in/ns/ext/midi#MidiEvent> ;\n";
1164             mainStream << "    ] ;\n";
1165         }
1166 
1167         mainStream << "    lv2:port [\n";
1168         mainStream << "        a lv2:InputPort, lv2:ControlPort ;\n";
1169         mainStream << "        lv2:index " << String(portIndex++) << " ;\n";
1170         mainStream << "        lv2:name \"freewheel\" ;\n";
1171         mainStream << "        lv2:symbol \"clv2_freewheel\" ;\n";
1172         mainStream << "        lv2:default 0 ;\n";
1173         mainStream << "        lv2:minimum 0 ;\n";
1174         mainStream << "        lv2:maximum 1 ;\n";
1175         mainStream << "        lv2:designation lv2:freeWheeling ;\n";
1176         mainStream << "        lv2:portProperty lv2:toggled , lv2:integer ;\n";
1177         mainStream << "        lv2:portProperty <http://lv2plug.in/ns/ext/port-props#notOnGUI> ;\n";
1178         mainStream << "    ] ;\n";
1179 
1180         for (uint32_t i=0; i<pData->audioIn.count; ++i)
1181         {
1182             const String portIndexNum(portIndex++);
1183             const String portIndexLabel(i+1);
1184 
1185             mainStream << "    lv2:port [\n";
1186             mainStream << "        a lv2:InputPort, lv2:AudioPort ;\n";
1187             mainStream << "        lv2:index " << portIndexNum << " ;\n";
1188             mainStream << "        lv2:symbol \"clv2_audio_in_" << portIndexLabel << "\" ;\n";
1189             mainStream << "        lv2:name \"Audio Input " << portIndexLabel << "\" ;\n";
1190             mainStream << "    ] ;\n";
1191         }
1192 
1193         for (uint32_t i=0; i<pData->audioOut.count; ++i)
1194         {
1195             const String portIndexNum(portIndex++);
1196             const String portIndexLabel(i+1);
1197 
1198             mainStream << "    lv2:port [\n";
1199             mainStream << "        a lv2:OutputPort, lv2:AudioPort ;\n";
1200             mainStream << "        lv2:index " << portIndexNum << " ;\n";
1201             mainStream << "        lv2:symbol \"clv2_audio_out_" << portIndexLabel << "\" ;\n";
1202             mainStream << "        lv2:name \"Audio Output " << portIndexLabel << "\" ;\n";
1203             mainStream << "    ] ;\n";
1204         }
1205 
1206         CarlaStringList uniqueSymbolNames;
1207 
1208         char strBufName[STR_MAX+1];
1209         char strBufSymbol[STR_MAX+1];
1210         carla_zeroChars(strBufName, STR_MAX+1);
1211         carla_zeroChars(strBufSymbol, STR_MAX+1);
1212 
1213         for (uint32_t i=0; i<pData->param.count; ++i)
1214         {
1215             const ParameterData&   paramData(pData->param.data[i]);
1216             const ParameterRanges& paramRanges(pData->param.ranges[i]);
1217 
1218             const String portIndexNum(portIndex++);
1219 
1220             mainStream << "    lv2:port [\n";
1221 
1222             if (paramData.type == PARAMETER_INPUT)
1223                 mainStream << "        a lv2:InputPort, lv2:ControlPort ;\n";
1224             else
1225                 mainStream << "        a lv2:OutputPort, lv2:ControlPort ;\n";
1226 
1227             if (paramData.hints & PARAMETER_IS_BOOLEAN)
1228                 mainStream << "        lv2:portProperty lv2:toggled ;\n";
1229 
1230             if (paramData.hints & PARAMETER_IS_INTEGER)
1231                 mainStream << "        lv2:portProperty lv2:integer ;\n";
1232 
1233             // TODO logarithmic, enabled (not on gui), automable, samplerate, scalepoints
1234 
1235             if (! getParameterName(i, strBufName))
1236                 strBufName[0] = '\0';
1237             if (! getParameterSymbol(i, strBufSymbol))
1238                 strBufSymbol[0] = '\0';
1239 
1240             if (strBufSymbol[0] == '\0')
1241             {
1242                 CarlaString s(strBufName);
1243                 s.toBasic();
1244                 std::memcpy(strBufSymbol, s.buffer(), s.length()+1);
1245 
1246                 if (strBufSymbol[0] >= '0' && strBufSymbol[0] <= '9')
1247                 {
1248                     const size_t len(std::strlen(strBufSymbol));
1249                     std::memmove(strBufSymbol+1, strBufSymbol, len);
1250                     strBufSymbol[0]   = '_';
1251                     strBufSymbol[len+1] = '\0';
1252                 }
1253             }
1254 
1255             if (uniqueSymbolNames.contains(strBufSymbol))
1256                 std::snprintf(strBufSymbol, STR_MAX, "clv2_param_%d", i+1);
1257 
1258             mainStream << "        lv2:index " << portIndexNum << " ;\n";
1259             mainStream << "        lv2:symbol \"" << strBufSymbol << "\" ;\n";
1260             mainStream << "        lv2:name \"\"\"" << strBufName << "\"\"\" ;\n";
1261             mainStream << "        lv2:default " << String(paramRanges.def) << " ;\n";
1262             mainStream << "        lv2:minimum " << String(paramRanges.min) << " ;\n";
1263             mainStream << "        lv2:maximum " << String(paramRanges.max) << " ;\n";
1264 
1265             // TODO midiCC, midiChannel
1266 
1267             mainStream << "    ] ;\n";
1268         }
1269 
1270         char strBuf[STR_MAX+1];
1271         carla_zeroChars(strBuf, STR_MAX+1);
1272 
1273         if (! getMaker(strBuf))
1274             strBuf[0] = '\0';
1275 
1276         mainStream << "    rdfs:comment \"Plugin generated using Carla LV2 export.\" ;\n";
1277         mainStream << "    doap:name \"\"\"" << getName() << "\"\"\" ;\n";
1278         mainStream << "    doap:maintainer [ foaf:name \"\"\"" << strBuf << "\"\"\" ] .\n";
1279         mainStream << "\n";
1280 
1281         const CarlaString mainFilename(bundlepath + CARLA_OS_SEP_STR + symbol + ".ttl");
1282         const File mainFile(mainFilename.buffer());
1283 
1284         if (! mainFile.replaceWithData(mainStream.getData(), mainStream.getDataSize()))
1285         {
1286             pData->engine->setLastError("Failed to write main plugin ttl file");
1287             return false;
1288         }
1289     }
1290 
1291     const CarlaString binaryFilename(bundlepath + CARLA_OS_SEP_STR + symbol + CARLA_LIB_EXT);
1292 
1293     const File binaryFileSource(File::getSpecialLocation(File::currentExecutableFile).getSiblingFile("carla-bridge-lv2" CARLA_LIB_EXT));
1294     const File binaryFileTarget(binaryFilename.buffer());
1295 
1296     const EngineOptions& opts(pData->engine->getOptions());
1297 
1298     const CarlaString binFolderTarget(bundlepath + CARLA_OS_SEP_STR + "bin");
1299     const CarlaString resFolderTarget(bundlepath + CARLA_OS_SEP_STR + "res");
1300 
1301     if (! binaryFileSource.copyFileTo(binaryFileTarget))
1302     {
1303         pData->engine->setLastError("Failed to copy plugin binary");
1304         return false;
1305     }
1306 
1307 #ifdef CARLA_OS_WIN
1308     File(opts.resourceDir).copyDirectoryTo(File(resFolderTarget.buffer()));
1309 
1310     // Copying all the binaries is pointless, just go through the expected needed bits
1311     const File binFolder1(opts.binaryDir);
1312     const File binFolder2(binFolderTarget.buffer());
1313     binFolder2.createDirectory();
1314 
1315     static const char* files[] = {
1316       "carla-bridge-native.exe",
1317       "carla-bridge-win32.exe",
1318       "carla-discovery-win32.exe",
1319       "carla-discovery-win64.exe",
1320       "libcarla_utils.dll"
1321     };
1322 
1323     for (int i=0; i<5; ++i)
1324         binFolder1.getChildFile(files[i]).copyFileTo(binFolder2.getChildFile(files[i]));;
1325 #else
1326     File(opts.binaryDir).createSymbolicLink(File(binFolderTarget.buffer()), true);
1327     File(opts.resourceDir).createSymbolicLink(File(resFolderTarget.buffer()), true);
1328 #endif
1329 
1330     return true;
1331 }
1332 
1333 // -------------------------------------------------------------------
1334 // Set data (internal stuff)
1335 
setId(const uint newId)1336 void CarlaPlugin::setId(const uint newId) noexcept
1337 {
1338     pData->id = newId;
1339 }
1340 
setName(const char * const newName)1341 void CarlaPlugin::setName(const char* const newName)
1342 {
1343     CARLA_SAFE_ASSERT_RETURN(newName != nullptr && newName[0] != '\0',);
1344 
1345     if (pData->name != nullptr)
1346         delete[] pData->name;
1347 
1348     pData->name = carla_strdup(newName);
1349 }
1350 
setOption(const uint option,const bool yesNo,const bool sendCallback)1351 void CarlaPlugin::setOption(const uint option, const bool yesNo, const bool sendCallback)
1352 {
1353     CARLA_SAFE_ASSERT_UINT2_RETURN(getOptionsAvailable() & option, getOptionsAvailable(), option,);
1354 
1355     if (yesNo)
1356         pData->options |= option;
1357     else
1358         pData->options &= ~option;
1359 
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
1372 }
1373 
setEnabled(const bool yesNo)1374 void CarlaPlugin::setEnabled(const bool yesNo) noexcept
1375 {
1376     if (pData->enabled == yesNo)
1377         return;
1378 
1379     pData->masterMutex.lock();
1380     pData->enabled = yesNo;
1381 
1382     if (yesNo && ! pData->client->isActive())
1383         pData->client->activate();
1384 
1385     pData->masterMutex.unlock();
1386 }
1387 
setActive(const bool active,const bool sendOsc,const bool sendCallback)1388 void CarlaPlugin::setActive(const bool active, const bool sendOsc, const bool sendCallback) noexcept
1389 {
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
1396     }
1397 
1398     if (pData->active == active)
1399         return;
1400 
1401     {
1402         const ScopedSingleProcessLocker spl(this, true);
1403 
1404         if (active)
1405             activate();
1406         else
1407             deactivate();
1408     }
1409 
1410     pData->active = active;
1411 
1412 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1413     const float value = active ? 1.0f : 0.0f;
1414 
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
1423 }
1424 
1425 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
setDryWet(const float value,const bool sendOsc,const bool sendCallback)1426 void CarlaPlugin::setDryWet(const float value, const bool sendOsc, const bool sendCallback) noexcept
1427 {
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
1432     }
1433     CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
1434 
1435     const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
1436 
1437     if (carla_isEqual(pData->postProc.dryWet, fixedValue))
1438         return;
1439 
1440     pData->postProc.dryWet = fixedValue;
1441 
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);
1449 }
1450 
setVolume(const float value,const bool sendOsc,const bool sendCallback)1451 void CarlaPlugin::setVolume(const float value, const bool sendOsc, const bool sendCallback) noexcept
1452 {
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
1457     }
1458     CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
1459 
1460     const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
1461 
1462     if (carla_isEqual(pData->postProc.volume, fixedValue))
1463         return;
1464 
1465     pData->postProc.volume = fixedValue;
1466 
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);
1474 }
1475 
setBalanceLeft(const float value,const bool sendOsc,const bool sendCallback)1476 void CarlaPlugin::setBalanceLeft(const float value, const bool sendOsc, const bool sendCallback) noexcept
1477 {
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
1482     }
1483     CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1484 
1485     const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1486 
1487     if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
1488         return;
1489 
1490     pData->postProc.balanceLeft = fixedValue;
1491 
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);
1499 }
1500 
setBalanceRight(const float value,const bool sendOsc,const bool sendCallback)1501 void CarlaPlugin::setBalanceRight(const float value, const bool sendOsc, const bool sendCallback) noexcept
1502 {
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
1507     }
1508     CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1509 
1510     const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1511 
1512     if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
1513         return;
1514 
1515     pData->postProc.balanceRight = fixedValue;
1516 
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);
1524 }
1525 
setPanning(const float value,const bool sendOsc,const bool sendCallback)1526 void CarlaPlugin::setPanning(const float value, const bool sendOsc, const bool sendCallback) noexcept
1527 {
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
1532     }
1533     CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1534 
1535     const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1536 
1537     if (carla_isEqual(pData->postProc.panning, fixedValue))
1538         return;
1539 
1540     pData->postProc.panning = fixedValue;
1541 
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);
1549 }
1550 
setDryWetRT(const float value,const bool sendCallbackLater)1551 void CarlaPlugin::setDryWetRT(const float value, const bool sendCallbackLater) noexcept
1552 {
1553     CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.0f);
1554 
1555     const float fixedValue(carla_fixedValue<float>(0.0f, 1.0f, value));
1556 
1557     if (carla_isEqual(pData->postProc.dryWet, fixedValue))
1558         return;
1559 
1560     pData->postProc.dryWet = fixedValue;
1561     pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_DRYWET, fixedValue);
1562 }
1563 
setVolumeRT(const float value,const bool sendCallbackLater)1564 void CarlaPlugin::setVolumeRT(const float value, const bool sendCallbackLater) noexcept
1565 {
1566     CARLA_SAFE_ASSERT(value >= 0.0f && value <= 1.27f);
1567 
1568     const float fixedValue(carla_fixedValue<float>(0.0f, 1.27f, value));
1569 
1570     if (carla_isEqual(pData->postProc.volume, fixedValue))
1571         return;
1572 
1573     pData->postProc.volume = fixedValue;
1574     pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_VOLUME, fixedValue);
1575 }
1576 
setBalanceLeftRT(const float value,const bool sendCallbackLater)1577 void CarlaPlugin::setBalanceLeftRT(const float value, const bool sendCallbackLater) noexcept
1578 {
1579     CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1580 
1581     const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1582 
1583     if (carla_isEqual(pData->postProc.balanceLeft, fixedValue))
1584         return;
1585 
1586     pData->postProc.balanceLeft = fixedValue;
1587     pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_BALANCE_LEFT, fixedValue);
1588 }
1589 
setBalanceRightRT(const float value,const bool sendCallbackLater)1590 void CarlaPlugin::setBalanceRightRT(const float value, const bool sendCallbackLater) noexcept
1591 {
1592     CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1593 
1594     const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1595 
1596     if (carla_isEqual(pData->postProc.balanceRight, fixedValue))
1597         return;
1598 
1599     pData->postProc.balanceRight = fixedValue;
1600     pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_BALANCE_RIGHT, fixedValue);
1601 }
1602 
setPanningRT(const float value,const bool sendCallbackLater)1603 void CarlaPlugin::setPanningRT(const float value, const bool sendCallbackLater) noexcept
1604 {
1605     CARLA_SAFE_ASSERT(value >= -1.0f && value <= 1.0f);
1606 
1607     const float fixedValue(carla_fixedValue<float>(-1.0f, 1.0f, value));
1608 
1609     if (carla_isEqual(pData->postProc.panning, fixedValue))
1610         return;
1611 
1612     pData->postProc.panning = fixedValue;
1613     pData->postponeParameterChangeRtEvent(sendCallbackLater, PARAMETER_PANNING, fixedValue);
1614 }
1615 #endif // ! BUILD_BRIDGE_ALTERNATIVE_ARCH
1616 
setCtrlChannel(const int8_t channel,const bool sendOsc,const bool sendCallback)1617 void CarlaPlugin::setCtrlChannel(const int8_t channel, const bool sendOsc, const bool sendCallback) noexcept
1618 {
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
1623     }
1624     CARLA_SAFE_ASSERT_RETURN(channel >= -1 && channel < MAX_MIDI_CHANNELS,);
1625 
1626     if (pData->ctrlChannel == channel)
1627         return;
1628 
1629     pData->ctrlChannel = channel;
1630 
1631 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1632     const float channelf = static_cast<float>(channel);
1633 
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
1641 }
1642 
1643 // -------------------------------------------------------------------
1644 // Set data (plugin-specific stuff)
1645 
setParameterValue(const uint32_t parameterId,const float value,const bool sendGui,const bool sendOsc,const bool sendCallback)1646 void CarlaPlugin::setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
1647 {
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
1655     }
1656     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1657 
1658     if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
1659         uiParameterChange(parameterId, value);
1660 
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);
1668 }
1669 
setParameterValueRT(const uint32_t parameterId,const float value,const bool sendCallbackLater)1670 void CarlaPlugin::setParameterValueRT(const uint32_t parameterId, const float value, const bool sendCallbackLater) noexcept
1671 {
1672     pData->postponeParameterChangeRtEvent(sendCallbackLater, static_cast<int32_t>(parameterId), value);
1673 }
1674 
setParameterValueByRealIndex(const int32_t rindex,const float value,const bool sendGui,const bool sendOsc,const bool sendCallback)1675 void CarlaPlugin::setParameterValueByRealIndex(const int32_t rindex, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
1676 {
1677 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1678     CARLA_SAFE_ASSERT_RETURN(rindex > PARAMETER_MAX && rindex != PARAMETER_NULL,);
1679 
1680     switch (rindex)
1681     {
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);
1696     }
1697 #endif
1698     CARLA_SAFE_ASSERT_RETURN(rindex >= 0,);
1699 
1700     for (uint32_t i=0; i < pData->param.count; ++i)
1701     {
1702         if (pData->param.data[i].rindex == rindex)
1703         {
1704             //if (carla_isNotEqual(getParameterValue(i), value))
1705             setParameterValue(i, value, sendGui, sendOsc, sendCallback);
1706             break;
1707         }
1708     }
1709 }
1710 
setParameterMidiChannel(const uint32_t parameterId,const uint8_t channel,const bool sendOsc,const bool sendCallback)1711 void CarlaPlugin::setParameterMidiChannel(const uint32_t parameterId, const uint8_t channel, const bool sendOsc, const bool sendCallback) noexcept
1712 {
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
1717     }
1718     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1719     CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
1720 
1721     if (pData->param.data[parameterId].midiChannel == channel)
1722         return;
1723 
1724     pData->param.data[parameterId].midiChannel = channel;
1725 
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
1734 }
1735 
setParameterMappedControlIndex(const uint32_t parameterId,const int16_t index,const bool sendOsc,const bool sendCallback,const bool reconfigureNow)1736 void CarlaPlugin::setParameterMappedControlIndex(const uint32_t parameterId, const int16_t index,
1737                                                  const bool sendOsc, const bool sendCallback,
1738                                                  const bool reconfigureNow) noexcept
1739 {
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
1744     }
1745     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1746     CARLA_SAFE_ASSERT_RETURN(index >= CONTROL_INDEX_NONE && index <= CONTROL_INDEX_MAX_ALLOWED,);
1747 
1748     ParameterData& paramData(pData->param.data[parameterId]);
1749 
1750     if (paramData.mappedControlIndex == index)
1751         return;
1752 
1753     const ParameterRanges& paramRanges(pData->param.ranges[parameterId]);
1754 
1755     if ((paramData.hints & PARAMETER_MAPPED_RANGES_SET) == 0x0)
1756         setParameterMappedRange(parameterId, paramRanges.min, paramRanges.max, true, true);
1757 
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);
1763 
1764     const uint portNameSize = pData->engine->getMaxPortNameSize();
1765     if (portNameSize < STR_MAX)
1766         strBuf[portNameSize] = '\0';
1767 
1768     // was learning something else before, stop that first
1769     if (pData->midiLearnParameterIndex >= 0 && pData->midiLearnParameterIndex != static_cast<int32_t>(parameterId))
1770     {
1771         const int32_t oldParameterId = pData->midiLearnParameterIndex;
1772         pData->midiLearnParameterIndex = -1;
1773 
1774         CARLA_SAFE_ASSERT_RETURN(oldParameterId < static_cast<int32_t>(pData->param.count),);
1775 
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);
1783     }
1784 
1785     // mapping new parameter to CV
1786     if (index == CONTROL_INDEX_CV)
1787     {
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,);
1791 
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);
1796     }
1797     // unmapping from CV
1798     else if (paramData.mappedControlIndex == CONTROL_INDEX_CV)
1799     {
1800         CARLA_SAFE_ASSERT_RETURN(pData->event.cvSourcePorts != nullptr,);
1801 
1802         CARLA_SAFE_ASSERT(pData->client->removePort(kEnginePortTypeCV, strBuf, true));
1803         CARLA_SAFE_ASSERT(pData->event.cvSourcePorts->removeCVSource(parameterId));
1804     }
1805     // mapping to something new
1806     else if (paramData.mappedControlIndex == CONTROL_INDEX_NONE)
1807     {
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);
1814     }
1815 #endif
1816 
1817     paramData.mappedControlIndex = index;
1818 
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;
1824 
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
1836 }
1837 
setParameterMappedRange(const uint32_t parameterId,const float minimum,const float maximum,const bool sendOsc,const bool sendCallback)1838 void CarlaPlugin::setParameterMappedRange(const uint32_t parameterId, const float minimum, const float maximum,
1839                                           const bool sendOsc, const bool sendCallback) noexcept
1840 {
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
1845     }
1846     CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
1847 
1848     ParameterData& paramData(pData->param.data[parameterId]);
1849 
1850     if (carla_isEqual(paramData.mappedMinimum, minimum) &&
1851         carla_isEqual(paramData.mappedMaximum, maximum) &&
1852         (paramData.hints & PARAMETER_MAPPED_RANGES_SET) != 0x0)
1853         return;
1854 
1855     if (paramData.mappedControlIndex != CONTROL_INDEX_NONE && paramData.mappedControlIndex != CONTROL_INDEX_CV)
1856     {
1857         const ParameterRanges& paramRanges(pData->param.ranges[parameterId]);
1858         CARLA_SAFE_ASSERT_RETURN(minimum >= paramRanges.min,);
1859         CARLA_SAFE_ASSERT_RETURN(maximum <= paramRanges.max,);
1860     }
1861 
1862     paramData.hints |= PARAMETER_MAPPED_RANGES_SET;
1863     paramData.mappedMinimum = minimum;
1864     paramData.mappedMaximum = maximum;
1865 
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);
1869 
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));
1873 
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
1881 }
1882 
setCustomData(const char * const type,const char * const key,const char * const value,const bool)1883 void CarlaPlugin::setCustomData(const char* const type, const char* const key, const char* const value, const bool)
1884 {
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,);
1888 
1889     // Ignore some keys
1890     if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) == 0)
1891     {
1892         const PluginType ptype = getType();
1893 
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;
1898     }
1899 
1900     // Check if we already have this key
1901     for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
1902     {
1903         CustomData& customData(it.getValue(kCustomDataFallbackNC));
1904         CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
1905 
1906         if (std::strcmp(customData.key, key) == 0)
1907         {
1908             if (customData.value != nullptr)
1909                 delete[] customData.value;
1910 
1911             customData.value = carla_strdup(value);
1912             return;
1913         }
1914     }
1915 
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);
1922 }
1923 
setChunkData(const void * const data,const std::size_t dataSize)1924 void CarlaPlugin::setChunkData(const void* const data, const std::size_t dataSize)
1925 {
1926     CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
1927     CARLA_SAFE_ASSERT_RETURN(dataSize > 0,);
1928     CARLA_SAFE_ASSERT(false); // this should never happen
1929 }
1930 
setProgram(const int32_t index,const bool sendGui,const bool sendOsc,const bool sendCallback,const bool)1931 void CarlaPlugin::setProgram(const int32_t index,
1932                              const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
1933 {
1934     CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->prog.count),);
1935 
1936     pData->prog.current = index;
1937 
1938     pData->engine->callback(sendCallback, sendOsc,
1939                             ENGINE_CALLBACK_PROGRAM_CHANGED,
1940                             pData->id,
1941                             index,
1942                             0, 0, 0.0f, nullptr);
1943 
1944     // Change default parameter values
1945     if (index >= 0)
1946     {
1947         if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
1948             uiProgramChange(static_cast<uint32_t>(index));
1949 
1950         switch (getType())
1951         {
1952         case PLUGIN_SF2:
1953         case PLUGIN_SFZ:
1954             break;
1955 
1956         default:
1957             pData->updateParameterValues(this, sendCallback, sendOsc, true);
1958             break;
1959         }
1960     }
1961 }
1962 
setMidiProgram(const int32_t index,const bool sendGui,const bool sendOsc,const bool sendCallback,const bool)1963 void CarlaPlugin::setMidiProgram(const int32_t index,
1964                                  const bool sendGui, const bool sendOsc, const bool sendCallback, const bool) noexcept
1965 {
1966     CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
1967 
1968     pData->midiprog.current = index;
1969 
1970     pData->engine->callback(sendCallback, sendOsc,
1971                             ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
1972                             pData->id,
1973                             index,
1974                             0, 0, 0.0f, nullptr);
1975 
1976     // Change default parameter values
1977     if (index >= 0)
1978     {
1979         if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
1980             uiMidiProgramChange(static_cast<uint32_t>(index));
1981 
1982         switch (getType())
1983         {
1984         case PLUGIN_SF2:
1985         case PLUGIN_SFZ:
1986             break;
1987 
1988         default:
1989             pData->updateParameterValues(this, sendCallback, sendOsc, true);
1990             break;
1991         }
1992     }
1993 }
1994 
setMidiProgramById(const uint32_t bank,const uint32_t program,const bool sendGui,const bool sendOsc,const bool sendCallback)1995 void CarlaPlugin::setMidiProgramById(const uint32_t bank, const uint32_t program, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept
1996 {
1997     for (uint32_t i=0; i < pData->midiprog.count; ++i)
1998     {
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);
2001     }
2002 }
2003 
setProgramRT(const uint32_t uindex,const bool sendCallbackLater)2004 void CarlaPlugin::setProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
2005 {
2006     CARLA_SAFE_ASSERT_RETURN(uindex < pData->prog.count,);
2007 
2008     const int32_t index = static_cast<int32_t>(uindex);
2009     pData->prog.current = index;
2010 
2011     // Change default parameter values
2012     switch (getType())
2013     {
2014     case PLUGIN_SF2:
2015     case PLUGIN_SFZ:
2016         break;
2017 
2018     default:
2019         pData->updateDefaultParameterValues(this);
2020         break;
2021     }
2022 
2023     pData->postponeProgramChangeRtEvent(sendCallbackLater, uindex);
2024 }
2025 
setMidiProgramRT(const uint32_t uindex,const bool sendCallbackLater)2026 void CarlaPlugin::setMidiProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept
2027 {
2028     CARLA_SAFE_ASSERT_RETURN(uindex < pData->midiprog.count,);
2029 
2030     const int32_t index = static_cast<int32_t>(uindex);
2031     pData->midiprog.current = index;
2032 
2033     // Change default parameter values
2034     switch (getType())
2035     {
2036     case PLUGIN_SF2:
2037     case PLUGIN_SFZ:
2038         break;
2039 
2040     default:
2041         pData->updateDefaultParameterValues(this);
2042         break;
2043     }
2044 
2045     pData->postponeMidiProgramChangeRtEvent(sendCallbackLater, uindex);
2046 }
2047 
2048 // -------------------------------------------------------------------
2049 // Plugin state
2050 
reloadPrograms(const bool)2051 void CarlaPlugin::reloadPrograms(const bool)
2052 {
2053 }
2054 
2055 // -------------------------------------------------------------------
2056 // Plugin processing
2057 
activate()2058 void CarlaPlugin::activate() noexcept
2059 {
2060     CARLA_SAFE_ASSERT(! pData->active);
2061 }
2062 
deactivate()2063 void CarlaPlugin::deactivate() noexcept
2064 {
2065     CARLA_SAFE_ASSERT(pData->active);
2066 }
2067 
bufferSizeChanged(const uint32_t)2068 void CarlaPlugin::bufferSizeChanged(const uint32_t)
2069 {
2070 }
2071 
sampleRateChanged(const double)2072 void CarlaPlugin::sampleRateChanged(const double)
2073 {
2074 }
2075 
offlineModeChanged(const bool)2076 void CarlaPlugin::offlineModeChanged(const bool)
2077 {
2078 }
2079 
2080 // -------------------------------------------------------------------
2081 // Misc
2082 
idle()2083 void CarlaPlugin::idle()
2084 {
2085     if (! pData->enabled)
2086         return;
2087 
2088     const bool hasUI(pData->hints & PLUGIN_HAS_CUSTOM_UI);
2089     const bool needsUiMainThread(pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD);
2090     const uint32_t latency(getLatencyInFrames());
2091 
2092     if (pData->latency.frames != latency)
2093     {
2094         carla_stdout("latency changed to %i samples", latency);
2095 
2096         const ScopedSingleProcessLocker sspl(this, true);
2097 
2098         pData->client->setLatency(latency);
2099 #ifndef BUILD_BRIDGE
2100         pData->latency.recreateBuffers(pData->latency.channels, latency);
2101 #else
2102         pData->latency.frames = latency;
2103 #endif
2104     }
2105 
2106     ProtectedData::PostRtEvents::Access rtEvents(pData->postRtEvents);
2107 
2108     if (rtEvents.isEmpty())
2109         return;
2110 
2111     for (RtLinkedList<PluginPostRtEvent>::Itenerator it = rtEvents.getDataIterator(); it.valid(); it.next())
2112     {
2113         const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
2114         CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
2115 
2116         switch (event.type)
2117         {
2118         case kPluginPostRtEventNull: {
2119         } break;
2120 
2121         case kPluginPostRtEventParameterChange: {
2122             // Update UI
2123             if (event.parameter.index >= 0 && hasUI)
2124             {
2125                 if (needsUiMainThread)
2126                     pData->postUiEvents.append(event);
2127                 else
2128                     uiParameterChange(static_cast<uint32_t>(event.parameter.index), event.parameter.value);
2129             }
2130 
2131             if (event.sendCallback)
2132             {
2133                 // Update Host
2134                 pData->engine->callback(true, true,
2135                                         ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
2136                                         pData->id,
2137                                         event.parameter.index,
2138                                         0, 0,
2139                                         event.parameter.value,
2140                                         nullptr);
2141             }
2142         } break;
2143 
2144         case kPluginPostRtEventProgramChange: {
2145             // Update UI
2146             if (hasUI)
2147             {
2148                 if (needsUiMainThread)
2149                     pData->postUiEvents.append(event);
2150                 else
2151                     uiProgramChange(event.program.index);
2152             }
2153 
2154             // Update param values
2155             for (uint32_t j=0; j < pData->param.count; ++j)
2156             {
2157                 const float paramDefault(pData->param.ranges[j].def);
2158                 const float paramValue(getParameterValue(j));
2159 
2160                 pData->engine->callback(true, true,
2161                                         ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
2162                                         pData->id,
2163                                         static_cast<int>(j),
2164                                         0, 0,
2165                                         paramValue,
2166                                         nullptr);
2167                 pData->engine->callback(true, true,
2168                                         ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
2169                                         pData->id,
2170                                         static_cast<int>(j),
2171                                         0, 0,
2172                                         paramDefault,
2173                                         nullptr);
2174             }
2175 
2176             if (event.sendCallback)
2177             {
2178                 // Update Host
2179                 pData->engine->callback(true, true,
2180                                         ENGINE_CALLBACK_PROGRAM_CHANGED,
2181                                         pData->id,
2182                                         static_cast<int>(event.program.index),
2183                                         0, 0, 0.0f, nullptr);
2184             }
2185         } break;
2186 
2187         case kPluginPostRtEventMidiProgramChange: {
2188             // Update UI
2189             if (hasUI)
2190             {
2191                 if (needsUiMainThread)
2192                     pData->postUiEvents.append(event);
2193                 else
2194                     uiMidiProgramChange(event.program.index);
2195             }
2196 
2197             // Update param values
2198             for (uint32_t j=0; j < pData->param.count; ++j)
2199             {
2200                 const float paramDefault(pData->param.ranges[j].def);
2201                 const float paramValue(getParameterValue(j));
2202 
2203                 pData->engine->callback(true, true,
2204                                         ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
2205                                         pData->id,
2206                                         static_cast<int>(j),
2207                                         0, 0,
2208                                         paramValue,
2209                                         nullptr);
2210                 pData->engine->callback(true, true,
2211                                         ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
2212                                         pData->id,
2213                                         static_cast<int>(j),
2214                                         0, 0,
2215                                         paramDefault,
2216                                         nullptr);
2217             }
2218 
2219             if (event.sendCallback)
2220             {
2221                 // Update Host
2222                 pData->engine->callback(true, true,
2223                                         ENGINE_CALLBACK_MIDI_PROGRAM_CHANGED,
2224                                         pData->id,
2225                                         static_cast<int>(event.program.index),
2226                                         0, 0, 0.0f, nullptr);
2227             }
2228         } break;
2229 
2230         case kPluginPostRtEventNoteOn: {
2231             CARLA_SAFE_ASSERT_BREAK(event.note.channel  < MAX_MIDI_CHANNELS);
2232             CARLA_SAFE_ASSERT_BREAK(event.note.note     < MAX_MIDI_NOTE);
2233             CARLA_SAFE_ASSERT_BREAK(event.note.velocity < MAX_MIDI_VALUE);
2234 
2235             // Update UI
2236             if (hasUI)
2237             {
2238                 if (needsUiMainThread)
2239                     pData->postUiEvents.append(event);
2240                 else
2241                     uiNoteOn(event.note.channel, event.note.note, event.note.velocity);
2242             }
2243 
2244             if (event.sendCallback)
2245             {
2246                 // Update Host
2247                 pData->engine->callback(true, true,
2248                                         ENGINE_CALLBACK_NOTE_ON,
2249                                         pData->id,
2250                                         static_cast<int>(event.note.channel),
2251                                         static_cast<int>(event.note.note),
2252                                         static_cast<int>(event.note.velocity),
2253                                         0.0f, nullptr);
2254             }
2255         } break;
2256 
2257         case kPluginPostRtEventNoteOff: {
2258             CARLA_SAFE_ASSERT_BREAK(event.note.channel  < MAX_MIDI_CHANNELS);
2259             CARLA_SAFE_ASSERT_BREAK(event.note.note     < MAX_MIDI_NOTE);
2260 
2261             // Update UI
2262             if (hasUI)
2263             {
2264                 if (needsUiMainThread)
2265                     pData->postUiEvents.append(event);
2266                 else
2267                     uiNoteOff(event.note.channel, event.note.note);
2268             }
2269 
2270             if (event.sendCallback)
2271             {
2272                 // Update Host
2273                 pData->engine->callback(true, true,
2274                                         ENGINE_CALLBACK_NOTE_OFF,
2275                                         pData->id,
2276                                         static_cast<int>(event.note.channel),
2277                                         static_cast<int>(event.note.note),
2278                                         0, 0.0f, nullptr);
2279             }
2280         } break;
2281 
2282         case kPluginPostRtEventMidiLearn: {
2283             CARLA_SAFE_ASSERT_BREAK(event.midiLearn.cc      < MAX_MIDI_VALUE);
2284             CARLA_SAFE_ASSERT_BREAK(event.midiLearn.channel < MAX_MIDI_CHANNELS);
2285 
2286 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2287             if (event.sendCallback)
2288             {
2289                 pData->engine->callback(true, true,
2290                                         ENGINE_CALLBACK_PARAMETER_MAPPED_CONTROL_INDEX_CHANGED,
2291                                         pData->id,
2292                                         static_cast<int>(event.midiLearn.parameter),
2293                                         static_cast<int>(event.midiLearn.cc),
2294                                         0, 0.0f, nullptr);
2295 
2296                 pData->engine->callback(true, true,
2297                                         ENGINE_CALLBACK_PARAMETER_MIDI_CHANNEL_CHANGED,
2298                                         pData->id,
2299                                         static_cast<int>(event.midiLearn.parameter),
2300                                         static_cast<int>(event.midiLearn.channel),
2301                                         0, 0.0f, nullptr);
2302             }
2303 #endif
2304         } break;
2305         }
2306     }
2307 }
2308 
tryLock(const bool forcedOffline)2309 bool CarlaPlugin::tryLock(const bool forcedOffline) noexcept
2310 {
2311     if (forcedOffline)
2312     {
2313 #ifndef STOAT_TEST_BUILD
2314         pData->masterMutex.lock();
2315         return true;
2316 #endif
2317     }
2318 
2319     return pData->masterMutex.tryLock();
2320 }
2321 
unlock()2322 void CarlaPlugin::unlock() noexcept
2323 {
2324     pData->masterMutex.unlock();
2325 }
2326 
2327 // -------------------------------------------------------------------
2328 // Plugin buffers
2329 
initBuffers() const2330 void CarlaPlugin::initBuffers() const noexcept
2331 {
2332     pData->audioIn.initBuffers();
2333     pData->audioOut.initBuffers();
2334     pData->cvIn.initBuffers();
2335     pData->cvOut.initBuffers();
2336     pData->event.initBuffers();
2337 }
2338 
clearBuffers()2339 void CarlaPlugin::clearBuffers() noexcept
2340 {
2341     pData->clearBuffers();
2342 }
2343 
2344 // -------------------------------------------------------------------
2345 // OSC stuff
2346 
2347 // FIXME
handleOscMessage(const char * const,const int,const void * const,const char * const,const lo_message)2348 void CarlaPlugin::handleOscMessage(const char* const, const int, const void* const, const char* const, const lo_message)
2349 {
2350     // do nothing
2351 }
2352 
2353 // -------------------------------------------------------------------
2354 // MIDI events
2355 
sendMidiSingleNote(const uint8_t channel,const uint8_t note,const uint8_t velo,const bool sendGui,const bool sendOsc,const bool sendCallback)2356 void CarlaPlugin::sendMidiSingleNote(const uint8_t channel, const uint8_t note, const uint8_t velo, const bool sendGui, const bool sendOsc, const bool sendCallback)
2357 {
2358     CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2359     CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2360     CARLA_SAFE_ASSERT_RETURN(velo < MAX_MIDI_VALUE,);
2361 
2362     if (! pData->active)
2363         return;
2364 
2365     ExternalMidiNote extNote;
2366     extNote.channel = static_cast<int8_t>(channel);
2367     extNote.note    = note;
2368     extNote.velo    = velo;
2369 
2370     pData->extNotes.appendNonRT(extNote);
2371 
2372     if (sendGui && (pData->hints & PLUGIN_HAS_CUSTOM_UI) != 0)
2373     {
2374         if (velo > 0)
2375             uiNoteOn(channel, note, velo);
2376         else
2377             uiNoteOff(channel, note);
2378     }
2379 
2380     pData->engine->callback(sendCallback, sendOsc,
2381                             (velo > 0) ? ENGINE_CALLBACK_NOTE_ON : ENGINE_CALLBACK_NOTE_OFF,
2382                             pData->id,
2383                             channel,
2384                             note,
2385                             velo,
2386                             0.0f, nullptr);
2387 }
2388 
2389 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
postponeRtAllNotesOff()2390 void CarlaPlugin::postponeRtAllNotesOff()
2391 {
2392     if (pData->ctrlChannel < 0 || pData->ctrlChannel >= MAX_MIDI_CHANNELS)
2393         return;
2394 
2395     PluginPostRtEvent postEvent = { kPluginPostRtEventNoteOff, true, {} };
2396     postEvent.note.channel = static_cast<uint8_t>(pData->ctrlChannel);
2397 
2398     for (uint8_t i=0; i < MAX_MIDI_NOTE; ++i)
2399     {
2400         postEvent.note.note = i;
2401         pData->postRtEvents.appendRT(postEvent);
2402     }
2403 }
2404 #endif
2405 
2406 // -------------------------------------------------------------------
2407 // UI Stuff
2408 
setCustomUITitle(const char * const title)2409 void CarlaPlugin::setCustomUITitle(const char* const title) noexcept
2410 {
2411     pData->uiTitle = title;
2412 }
2413 
showCustomUI(const bool yesNo)2414 void CarlaPlugin::showCustomUI(const bool yesNo)
2415 {
2416     if (yesNo) {
2417         CARLA_SAFE_ASSERT(false);
2418     }
2419 }
2420 
embedCustomUI(void *)2421 void* CarlaPlugin::embedCustomUI(void*)
2422 {
2423     return nullptr;
2424 }
2425 
uiIdle()2426 void CarlaPlugin::uiIdle()
2427 {
2428     if (pData->hints & PLUGIN_NEEDS_UI_MAIN_THREAD)
2429     {
2430         // Update parameter outputs
2431         for (uint32_t i=0; i < pData->param.count; ++i)
2432         {
2433             if (pData->param.data[i].type == PARAMETER_OUTPUT)
2434                 uiParameterChange(i, getParameterValue(i));
2435         }
2436 
2437         const CarlaMutexLocker sl(pData->postUiEvents.mutex);
2438 
2439         for (LinkedList<PluginPostRtEvent>::Itenerator it = pData->postUiEvents.data.begin2(); it.valid(); it.next())
2440         {
2441             const PluginPostRtEvent& event(it.getValue(kPluginPostRtEventFallback));
2442             CARLA_SAFE_ASSERT_CONTINUE(event.type != kPluginPostRtEventNull);
2443 
2444             switch (event.type)
2445             {
2446             case kPluginPostRtEventNull:
2447             case kPluginPostRtEventMidiLearn:
2448                 break;
2449 
2450             case kPluginPostRtEventParameterChange:
2451                 uiParameterChange(static_cast<uint32_t>(event.parameter.index), event.parameter.value);
2452                 break;
2453 
2454             case kPluginPostRtEventProgramChange:
2455                 uiProgramChange(event.program.index);
2456                 break;
2457 
2458             case kPluginPostRtEventMidiProgramChange:
2459                 uiMidiProgramChange(event.program.index);
2460                 break;
2461 
2462             case kPluginPostRtEventNoteOn:
2463                 uiNoteOn(event.note.channel, event.note.note, event.note.velocity);
2464                 break;
2465 
2466             case kPluginPostRtEventNoteOff:
2467                 uiNoteOff(event.note.channel, event.note.note);
2468                 break;
2469             }
2470         }
2471 
2472         pData->postUiEvents.data.clear();
2473     }
2474 
2475 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2476     if (pData->transientTryCounter == 0)
2477         return;
2478     if (++pData->transientTryCounter % 10 != 0)
2479         return;
2480     if (pData->transientTryCounter >= 200)
2481         return;
2482 
2483     carla_stdout("Trying to get window...");
2484 
2485     CarlaString uiTitle;
2486 
2487     if (pData->uiTitle.isNotEmpty())
2488     {
2489         uiTitle = pData->uiTitle;
2490     }
2491     else
2492     {
2493         uiTitle  = pData->name;
2494         uiTitle += " (GUI)";
2495     }
2496 
2497     if (CarlaPluginUI::tryTransientWinIdMatch(getUiBridgeProcessId(), uiTitle,
2498                                               pData->engine->getOptions().frontendWinId, pData->transientFirstTry))
2499     {
2500         pData->transientTryCounter = 0;
2501         pData->transientFirstTry = false;
2502     }
2503 #endif
2504 }
2505 
uiParameterChange(const uint32_t index,const float value)2506 void CarlaPlugin::uiParameterChange(const uint32_t index, const float value) noexcept
2507 {
2508     CARLA_SAFE_ASSERT_RETURN(index < getParameterCount(),);
2509     return;
2510 
2511     // unused
2512     (void)value;
2513 }
2514 
uiProgramChange(const uint32_t index)2515 void CarlaPlugin::uiProgramChange(const uint32_t index) noexcept
2516 {
2517     CARLA_SAFE_ASSERT_RETURN(index < getProgramCount(),);
2518 }
2519 
uiMidiProgramChange(const uint32_t index)2520 void CarlaPlugin::uiMidiProgramChange(const uint32_t index) noexcept
2521 {
2522     CARLA_SAFE_ASSERT_RETURN(index < getMidiProgramCount(),);
2523 }
2524 
uiNoteOn(const uint8_t channel,const uint8_t note,const uint8_t velo)2525 void CarlaPlugin::uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept
2526 {
2527     CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2528     CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2529     CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
2530 }
2531 
uiNoteOff(const uint8_t channel,const uint8_t note)2532 void CarlaPlugin::uiNoteOff(const uint8_t channel, const uint8_t note) noexcept
2533 {
2534     CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2535     CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2536 }
2537 
getEngine() const2538 CarlaEngine* CarlaPlugin::getEngine() const noexcept
2539 {
2540     return pData->engine;
2541 }
2542 
getEngineClient() const2543 CarlaEngineClient* CarlaPlugin::getEngineClient() const noexcept
2544 {
2545     return pData->client;
2546 }
2547 
getAudioInPort(const uint32_t index) const2548 CarlaEngineAudioPort* CarlaPlugin::getAudioInPort(const uint32_t index) const noexcept
2549 {
2550     return pData->audioIn.ports[index].port;
2551 }
2552 
getAudioOutPort(const uint32_t index) const2553 CarlaEngineAudioPort* CarlaPlugin::getAudioOutPort(const uint32_t index) const noexcept
2554 {
2555     return pData->audioOut.ports[index].port;
2556 }
2557 
getCVInPort(const uint32_t index) const2558 CarlaEngineCVPort* CarlaPlugin::getCVInPort(const uint32_t index) const noexcept
2559 {
2560     return pData->cvIn.ports[index].port;
2561 }
2562 
getCVOutPort(const uint32_t index) const2563 CarlaEngineCVPort* CarlaPlugin::getCVOutPort(const uint32_t index) const noexcept
2564 {
2565     return pData->cvOut.ports[index].port;
2566 }
2567 
getDefaultEventInPort() const2568 CarlaEngineEventPort* CarlaPlugin::getDefaultEventInPort() const noexcept
2569 {
2570     return pData->event.portIn;
2571 }
2572 
getDefaultEventOutPort() const2573 CarlaEngineEventPort* CarlaPlugin::getDefaultEventOutPort() const noexcept
2574 {
2575     return pData->event.portOut;
2576 }
2577 
2578 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
checkForMidiLearn(EngineEvent & event)2579 void CarlaPlugin::checkForMidiLearn(EngineEvent& event) noexcept
2580 {
2581     if (pData->midiLearnParameterIndex < 0)
2582         return;
2583     if (event.ctrl.param == MIDI_CONTROL_BANK_SELECT || event.ctrl.param == MIDI_CONTROL_BANK_SELECT__LSB)
2584         return;
2585     if (event.ctrl.param >= MAX_MIDI_CONTROL)
2586         return;
2587 
2588     const uint32_t parameterId = static_cast<uint32_t>(pData->midiLearnParameterIndex);
2589     CARLA_SAFE_ASSERT_UINT2_RETURN(parameterId < pData->param.count, parameterId, pData->param.count,);
2590 
2591     ParameterData& paramData(pData->param.data[parameterId]);
2592     CARLA_SAFE_ASSERT_INT_RETURN(paramData.mappedControlIndex == CONTROL_INDEX_MIDI_LEARN,
2593                                  paramData.mappedControlIndex,);
2594 
2595     event.ctrl.handled = true;
2596     paramData.mappedControlIndex = static_cast<int16_t>(event.ctrl.param);
2597     paramData.midiChannel = event.channel;
2598 
2599     pData->postponeMidiLearnRtEvent(true, parameterId, static_cast<uint8_t>(event.ctrl.param), event.channel);
2600     pData->midiLearnParameterIndex = -1;
2601 }
2602 #endif
2603 
getNativeHandle() const2604 void* CarlaPlugin::getNativeHandle() const noexcept
2605 {
2606     return nullptr;
2607 }
2608 
getNativeDescriptor() const2609 const void* CarlaPlugin::getNativeDescriptor() const noexcept
2610 {
2611     return nullptr;
2612 }
2613 
getUiBridgeProcessId() const2614 uintptr_t CarlaPlugin::getUiBridgeProcessId() const noexcept
2615 {
2616     return 0;
2617 }
2618 
2619 // -------------------------------------------------------------------
2620 
getPatchbayNodeId() const2621 uint32_t CarlaPlugin::getPatchbayNodeId() const noexcept
2622 {
2623     return pData->nodeId;
2624 }
2625 
setPatchbayNodeId(const uint32_t nodeId)2626 void CarlaPlugin::setPatchbayNodeId(const uint32_t nodeId) noexcept
2627 {
2628     pData->nodeId = nodeId;
2629 }
2630 
2631 // -------------------------------------------------------------------
2632 
cloneLV2Files(const CarlaPlugin &)2633 void CarlaPlugin::cloneLV2Files(const CarlaPlugin&)
2634 {
2635     carla_stderr2("Warning: cloneLV2Files() called for non-implemented type");
2636 }
2637 
restoreLV2State(const bool temporary)2638 void CarlaPlugin::restoreLV2State(const bool temporary) noexcept
2639 {
2640     carla_stderr2("Warning: restoreLV2State(%s) called for non-implemented type", bool2str(temporary));
2641 }
2642 
prepareForDeletion()2643 void CarlaPlugin::prepareForDeletion() noexcept
2644 {
2645     carla_debug("CarlaPlugin::prepareForDeletion");
2646 
2647     const CarlaMutexLocker cml(pData->masterMutex);
2648 
2649     pData->client->deactivate(true);
2650 }
2651 
waitForBridgeSaveSignal()2652 void CarlaPlugin::waitForBridgeSaveSignal() noexcept
2653 {
2654 }
2655 
2656 // -------------------------------------------------------------------
2657 // Scoped Disabler
2658 
ScopedDisabler(CarlaPlugin * const plugin)2659 CarlaPlugin::ScopedDisabler::ScopedDisabler(CarlaPlugin* const plugin) noexcept
2660     : fPlugin(plugin),
2661       fWasEnabled(false)
2662 {
2663     CARLA_SAFE_ASSERT_RETURN(plugin != nullptr,);
2664     CARLA_SAFE_ASSERT_RETURN(plugin->pData != nullptr,);
2665     CARLA_SAFE_ASSERT_RETURN(plugin->pData->client != nullptr,);
2666     carla_debug("CarlaPlugin::ScopedDisabler(%p)", plugin);
2667 
2668     plugin->pData->masterMutex.lock();
2669 
2670     if (plugin->pData->enabled)
2671     {
2672         fWasEnabled = true;
2673         plugin->pData->enabled = false;
2674 
2675         if (plugin->pData->client->isActive())
2676             plugin->pData->client->deactivate(false);
2677     }
2678 }
2679 
~ScopedDisabler()2680 CarlaPlugin::ScopedDisabler::~ScopedDisabler() noexcept
2681 {
2682     CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
2683     CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
2684     CARLA_SAFE_ASSERT_RETURN(fPlugin->pData->client != nullptr,);
2685     carla_debug("CarlaPlugin::~ScopedDisabler()");
2686 
2687     if (fWasEnabled)
2688     {
2689         fPlugin->pData->enabled = true;
2690         fPlugin->pData->client->activate();
2691     }
2692 
2693     fPlugin->pData->masterMutex.unlock();
2694 }
2695 
2696 // -------------------------------------------------------------------
2697 // Scoped Process Locker
2698 
ScopedSingleProcessLocker(CarlaPlugin * const plugin,const bool block)2699 CarlaPlugin::ScopedSingleProcessLocker::ScopedSingleProcessLocker(CarlaPlugin* const plugin, const bool block) noexcept
2700     : fPlugin(plugin),
2701       fBlock(block)
2702 {
2703     CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
2704     CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
2705     carla_debug("CarlaPlugin::ScopedSingleProcessLocker(%p, %s)", plugin, bool2str(block));
2706 
2707     if (! fBlock)
2708         return;
2709 
2710     plugin->pData->singleMutex.lock();
2711 }
2712 
~ScopedSingleProcessLocker()2713 CarlaPlugin::ScopedSingleProcessLocker::~ScopedSingleProcessLocker() noexcept
2714 {
2715     CARLA_SAFE_ASSERT_RETURN(fPlugin != nullptr,);
2716     CARLA_SAFE_ASSERT_RETURN(fPlugin->pData != nullptr,);
2717     carla_debug("CarlaPlugin::~ScopedSingleProcessLocker()");
2718 
2719     if (! fBlock)
2720         return;
2721 
2722 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2723     if (fPlugin->pData->singleMutex.wasTryLockCalled())
2724         fPlugin->pData->needsReset = true;
2725 #endif
2726 
2727     fPlugin->pData->singleMutex.unlock();
2728 }
2729 
2730 // -------------------------------------------------------------------
2731 
2732 CARLA_BACKEND_END_NAMESPACE
2733