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 "CarlaLibCounter.hpp"
22 #include "CarlaMathUtils.hpp"
23 #include "CarlaMIDI.h"
24 
25 CARLA_BACKEND_START_NAMESPACE
26 
27 // -------------------------------------------------------------------
28 // Fallback data
29 
30 static const MidiProgramData kMidiProgramDataNull  = { 0, 0, nullptr };
31 static /* */ CustomData      kCustomDataFallbackNC = { nullptr, nullptr, nullptr };
32 
33 // -----------------------------------------------------------------------
34 // PluginAudioData
35 
PluginAudioData()36 PluginAudioData::PluginAudioData() noexcept
37     : count(0),
38       ports(nullptr) {}
39 
~PluginAudioData()40 PluginAudioData::~PluginAudioData() noexcept
41 {
42     CARLA_SAFE_ASSERT_INT(count == 0, count);
43     CARLA_SAFE_ASSERT(ports == nullptr);
44 }
45 
createNew(const uint32_t newCount)46 void PluginAudioData::createNew(const uint32_t newCount)
47 {
48     CARLA_SAFE_ASSERT_INT(count == 0, count);
49     CARLA_SAFE_ASSERT_RETURN(ports == nullptr,);
50     CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
51 
52     ports = new PluginAudioPort[newCount];
53     carla_zeroStructs(ports, newCount);
54 
55     count = newCount;
56 }
57 
clear()58 void PluginAudioData::clear() noexcept
59 {
60     if (ports != nullptr)
61     {
62         for (uint32_t i=0; i < count; ++i)
63         {
64             if (ports[i].port != nullptr)
65             {
66                 delete ports[i].port;
67                 ports[i].port = nullptr;
68             }
69         }
70 
71         delete[] ports;
72         ports = nullptr;
73     }
74 
75     count = 0;
76 }
77 
initBuffers() const78 void PluginAudioData::initBuffers() const noexcept
79 {
80     for (uint32_t i=0; i < count; ++i)
81     {
82         if (ports[i].port != nullptr)
83             ports[i].port->initBuffer();
84     }
85 }
86 
87 // -----------------------------------------------------------------------
88 // PluginCVData
89 
PluginCVData()90 PluginCVData::PluginCVData() noexcept
91     : count(0),
92       ports(nullptr) {}
93 
~PluginCVData()94 PluginCVData::~PluginCVData() noexcept
95 {
96     CARLA_SAFE_ASSERT_INT(count == 0, count);
97     CARLA_SAFE_ASSERT(ports == nullptr);
98 }
99 
createNew(const uint32_t newCount)100 void PluginCVData::createNew(const uint32_t newCount)
101 {
102     CARLA_SAFE_ASSERT_INT(count == 0, count);
103     CARLA_SAFE_ASSERT_RETURN(ports == nullptr,);
104     CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
105 
106     ports = new PluginCVPort[newCount];
107     carla_zeroStructs(ports, newCount);
108 
109     count = newCount;
110 }
111 
clear()112 void PluginCVData::clear() noexcept
113 {
114     if (ports != nullptr)
115     {
116         for (uint32_t i=0; i < count; ++i)
117         {
118             if (ports[i].port != nullptr)
119             {
120                 delete ports[i].port;
121                 ports[i].port = nullptr;
122             }
123         }
124 
125         delete[] ports;
126         ports = nullptr;
127     }
128 
129     count = 0;
130 }
131 
initBuffers() const132 void PluginCVData::initBuffers() const noexcept
133 {
134     for (uint32_t i=0; i < count; ++i)
135     {
136         if (ports[i].port != nullptr)
137             ports[i].port->initBuffer();
138     }
139 }
140 
141 // -----------------------------------------------------------------------
142 // PluginEventData
143 
PluginEventData()144 PluginEventData::PluginEventData() noexcept
145     : portIn(nullptr),
146       portOut(nullptr)
147 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
148     , cvSourcePorts(nullptr)
149 #endif
150     {
151     }
152 
~PluginEventData()153 PluginEventData::~PluginEventData() noexcept
154 {
155     CARLA_SAFE_ASSERT(portIn == nullptr);
156     CARLA_SAFE_ASSERT(portOut == nullptr);
157 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
158     CARLA_SAFE_ASSERT(cvSourcePorts == nullptr);
159 #endif
160 }
161 
clear()162 void PluginEventData::clear() noexcept
163 {
164     if (portIn != nullptr)
165     {
166         delete portIn;
167         portIn = nullptr;
168     }
169 
170     if (portOut != nullptr)
171     {
172         delete portOut;
173         portOut = nullptr;
174     }
175 
176 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
177     if (cvSourcePorts != nullptr)
178     {
179         cvSourcePorts->cleanup();
180         cvSourcePorts = nullptr;
181     }
182 #endif
183 }
184 
initBuffers() const185 void PluginEventData::initBuffers() const noexcept
186 {
187     if (portIn != nullptr)
188         portIn->initBuffer();
189 
190     if (portOut != nullptr)
191         portOut->initBuffer();
192 }
193 
194 // -----------------------------------------------------------------------
195 // PluginParameterData
196 
PluginParameterData()197 PluginParameterData::PluginParameterData() noexcept
198     : count(0),
199       data(nullptr),
200       ranges(nullptr),
201       special(nullptr) {}
202 
~PluginParameterData()203 PluginParameterData::~PluginParameterData() noexcept
204 {
205     CARLA_SAFE_ASSERT_INT(count == 0, count);
206     CARLA_SAFE_ASSERT(data == nullptr);
207     CARLA_SAFE_ASSERT(ranges == nullptr);
208     CARLA_SAFE_ASSERT(special == nullptr);
209 }
210 
createNew(const uint32_t newCount,const bool withSpecial)211 void PluginParameterData::createNew(const uint32_t newCount, const bool withSpecial)
212 {
213     CARLA_SAFE_ASSERT_INT(count == 0, count);
214     CARLA_SAFE_ASSERT_RETURN(data == nullptr,);
215     CARLA_SAFE_ASSERT_RETURN(ranges == nullptr,);
216     CARLA_SAFE_ASSERT_RETURN(special == nullptr,);
217     CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
218 
219     data = new ParameterData[newCount];
220     carla_zeroStructs(data, newCount);
221 
222     for (uint32_t i=0; i < newCount; ++i)
223     {
224         data[i].index  = PARAMETER_NULL;
225         data[i].rindex = PARAMETER_NULL;
226         data[i].mappedControlIndex = CONTROL_INDEX_NONE;
227         data[i].mappedMinimum = -1.0f;
228         data[i].mappedMaximum = 1.0f;
229     }
230 
231     ranges = new ParameterRanges[newCount];
232     carla_zeroStructs(ranges, newCount);
233 
234     if (withSpecial)
235     {
236         special = new SpecialParameterType[newCount];
237         carla_zeroStructs(special, newCount);
238     }
239 
240     count = newCount;
241 }
242 
clear()243 void PluginParameterData::clear() noexcept
244 {
245     if (data != nullptr)
246     {
247         delete[] data;
248         data = nullptr;
249     }
250 
251     if (ranges != nullptr)
252     {
253         delete[] ranges;
254         ranges = nullptr;
255     }
256 
257     if (special != nullptr)
258     {
259         delete[] special;
260         special = nullptr;
261     }
262 
263     count = 0;
264 }
265 
getFixedValue(const uint32_t parameterId,float value) const266 float PluginParameterData::getFixedValue(const uint32_t parameterId, float value) const noexcept
267 {
268     CARLA_SAFE_ASSERT_RETURN(parameterId < count, 0.0f);
269 
270     const uint             paramHints (data[parameterId].hints);
271     const ParameterRanges& paramRanges(ranges[parameterId]);
272 
273     // if boolean, return either min or max
274     if (paramHints & PARAMETER_IS_BOOLEAN)
275     {
276         const float middlePoint = paramRanges.min + (paramRanges.max-paramRanges.min)/2.0f;
277         return value >= middlePoint ? paramRanges.max : paramRanges.min;
278     }
279 
280     // if integer, round first
281     if (paramHints & PARAMETER_IS_INTEGER)
282         return paramRanges.getFixedValue(std::round(value));
283 
284     // normal mode
285     return paramRanges.getFixedValue(value);
286 }
287 
288 // copied from ParameterRanges::getUnnormalizedValue
_getUnnormalizedValue(const float min,const float max,const float value)289 static float _getUnnormalizedValue(const float min, const float max, const float value) noexcept
290 {
291     if (value <= 0.0f)
292         return min;
293     if (value >= 1.0f)
294         return max;
295 
296     return value * (max - min) + min;
297 }
298 
299 // copied from ParameterRanges::getUnnormalizedLogValue
_getUnnormalizedLogValue(const float min,const float max,const float value)300 static float _getUnnormalizedLogValue(const float min, const float max, const float value) noexcept
301 {
302     if (value <= 0.0f)
303         return min;
304     if (value >= 1.0f)
305         return max;
306 
307     float rmin = min;
308 
309     if (std::abs(min) < std::numeric_limits<float>::epsilon())
310         rmin = 0.00001f;
311 
312     return rmin * std::pow(max/rmin, value);
313 }
314 
getFinalUnnormalizedValue(const uint32_t parameterId,const float normalizedValue) const315 float PluginParameterData::getFinalUnnormalizedValue(const uint32_t parameterId,
316                                                      const float normalizedValue) const noexcept
317 {
318     float min, max, value;
319 
320     if (data[parameterId].mappedControlIndex != CONTROL_INDEX_CV
321         && (data[parameterId].hints & PARAMETER_MAPPED_RANGES_SET) != 0x0)
322     {
323         min = data[parameterId].mappedMinimum;
324         max = data[parameterId].mappedMaximum;
325     }
326     else
327     {
328         min = ranges[parameterId].min;
329         max = ranges[parameterId].max;
330     }
331 
332     if (data[parameterId].hints & PARAMETER_IS_BOOLEAN)
333     {
334         value = (normalizedValue < 0.5f) ? min : max;
335     }
336     else
337     {
338         if (data[parameterId].hints & PARAMETER_IS_LOGARITHMIC)
339             value = _getUnnormalizedLogValue(min, max, normalizedValue);
340         else
341             value = _getUnnormalizedValue(min, max, normalizedValue);
342 
343         if (data[parameterId].hints & PARAMETER_IS_INTEGER)
344             value = std::rint(value);
345     }
346 
347     return value;
348 }
349 
getFinalValueWithMidiDelta(const uint32_t parameterId,float value,int8_t delta) const350 float PluginParameterData::getFinalValueWithMidiDelta(const uint32_t parameterId,
351                                                       float value, int8_t delta) const noexcept
352 {
353     if (delta < 0)
354         return value;
355     if (data[parameterId].mappedControlIndex <= 0 || data[parameterId].mappedControlIndex >= MAX_MIDI_CONTROL)
356         return value;
357 
358     float min, max;
359 
360     if ((data[parameterId].hints & PARAMETER_MAPPED_RANGES_SET) != 0x0)
361     {
362         min = data[parameterId].mappedMinimum;
363         max = data[parameterId].mappedMaximum;
364     }
365     else
366     {
367         min = ranges[parameterId].min;
368         max = ranges[parameterId].max;
369     }
370 
371     if (data[parameterId].hints & PARAMETER_IS_BOOLEAN)
372     {
373         value = delta > 63 ? min : max;
374     }
375     else
376     {
377         if (data[parameterId].hints & PARAMETER_IS_INTEGER)
378         {
379             if (delta > 63)
380                 value += delta - 128.0f;
381             else
382                 value += delta;
383         }
384         else
385         {
386             if (delta > 63)
387                 delta = static_cast<int8_t>(delta - 128);
388 
389             value += (max - min) * (static_cast<float>(delta) / 127.0f);
390         }
391 
392         if (value < min)
393             value = min;
394         else if (value > max)
395             value = max;
396     }
397 
398     return value;
399 }
400 
401 // -----------------------------------------------------------------------
402 // PluginProgramData
403 
PluginProgramData()404 PluginProgramData::PluginProgramData() noexcept
405     : count(0),
406       current(-1),
407       names(nullptr) {}
408 
~PluginProgramData()409 PluginProgramData::~PluginProgramData() noexcept
410 {
411     CARLA_SAFE_ASSERT_INT(count == 0, count);
412     CARLA_SAFE_ASSERT_INT(current == -1, current);
413     CARLA_SAFE_ASSERT(names == nullptr);
414 }
415 
createNew(const uint32_t newCount)416 void PluginProgramData::createNew(const uint32_t newCount)
417 {
418     CARLA_SAFE_ASSERT_INT(count == 0, count);
419     CARLA_SAFE_ASSERT_INT(current == -1, current);
420     CARLA_SAFE_ASSERT_RETURN(names == nullptr,);
421     CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
422 
423     names = new ProgramName[newCount];
424     carla_zeroStructs(names, newCount);
425 
426     count   = newCount;
427     current = -1;
428 }
429 
clear()430 void PluginProgramData::clear() noexcept
431 {
432     if (names != nullptr)
433     {
434         for (uint32_t i=0; i < count; ++i)
435         {
436             if (names[i] != nullptr)
437             {
438                 delete[] names[i];
439                 names[i] = nullptr;
440             }
441         }
442 
443         delete[] names;
444         names = nullptr;
445     }
446 
447     count   = 0;
448     current = -1;
449 }
450 
451 // -----------------------------------------------------------------------
452 // PluginMidiProgramData
453 
PluginMidiProgramData()454 PluginMidiProgramData::PluginMidiProgramData() noexcept
455     : count(0),
456       current(-1),
457       data(nullptr) {}
458 
~PluginMidiProgramData()459 PluginMidiProgramData::~PluginMidiProgramData() noexcept
460 {
461     CARLA_SAFE_ASSERT_INT(count == 0, count);
462     CARLA_SAFE_ASSERT_INT(current == -1, current);
463     CARLA_SAFE_ASSERT(data == nullptr);
464 }
465 
createNew(const uint32_t newCount)466 void PluginMidiProgramData::createNew(const uint32_t newCount)
467 {
468     CARLA_SAFE_ASSERT_INT(count == 0, count);
469     CARLA_SAFE_ASSERT_INT(current == -1, current);
470     CARLA_SAFE_ASSERT_RETURN(data == nullptr,);
471     CARLA_SAFE_ASSERT_RETURN(newCount > 0,);
472 
473     data = new MidiProgramData[newCount];
474     carla_zeroStructs(data, newCount);
475 
476     count   = newCount;
477     current = -1;
478 }
479 
clear()480 void PluginMidiProgramData::clear() noexcept
481 {
482     if (data != nullptr)
483     {
484         for (uint32_t i=0; i < count; ++i)
485         {
486             if (data[i].name != nullptr)
487             {
488                 delete[] data[i].name;
489                 data[i].name = nullptr;
490             }
491         }
492 
493         delete[] data;
494         data = nullptr;
495     }
496 
497     count   = 0;
498     current = -1;
499 }
500 
getCurrent() const501 const MidiProgramData& PluginMidiProgramData::getCurrent() const noexcept
502 {
503     CARLA_SAFE_ASSERT_RETURN(current >= 0 && current < static_cast<int32_t>(count), kMidiProgramDataNull);
504     return data[current];
505 }
506 
507 // -----------------------------------------------------------------------
508 // ProtectedData::ExternalNotes
509 
ExternalNotes()510 CarlaPlugin::ProtectedData::ExternalNotes::ExternalNotes() noexcept
511     : mutex(),
512       dataPool("CarlaPlugin::ProtectedData::ExternalNotes", 32, 152),
513       data(dataPool) {}
514 
~ExternalNotes()515 CarlaPlugin::ProtectedData::ExternalNotes::~ExternalNotes() noexcept
516 {
517     clear();
518 }
519 
appendNonRT(const ExternalMidiNote & note)520 void CarlaPlugin::ProtectedData::ExternalNotes::appendNonRT(const ExternalMidiNote& note) noexcept
521 {
522     mutex.lock();
523     data.append_sleepy(note);
524     mutex.unlock();
525 }
526 
clear()527 void CarlaPlugin::ProtectedData::ExternalNotes::clear() noexcept
528 {
529     mutex.lock();
530     data.clear();
531     mutex.unlock();
532 }
533 
534 // -----------------------------------------------------------------------
535 // ProtectedData::Latency
536 
Latency()537 CarlaPlugin::ProtectedData::Latency::Latency() noexcept
538 #ifdef BUILD_BRIDGE
539     : frames(0) {}
540 #else
541     : frames(0),
542       channels(0),
543       buffers(nullptr) {}
544 #endif
545 
546 #ifndef BUILD_BRIDGE
~Latency()547 CarlaPlugin::ProtectedData::Latency::~Latency() noexcept
548 {
549     clearBuffers();
550 }
551 
clearBuffers()552 void CarlaPlugin::ProtectedData::Latency::clearBuffers() noexcept
553 {
554     if (buffers != nullptr)
555     {
556         for (uint32_t i=0; i < channels; ++i)
557         {
558             CARLA_SAFE_ASSERT_CONTINUE(buffers[i] != nullptr);
559 
560             delete[] buffers[i];
561             buffers[i] = nullptr;
562         }
563 
564         delete[] buffers;
565         buffers = nullptr;
566     }
567 
568     channels = 0;
569     frames   = 0;
570 }
571 
recreateBuffers(const uint32_t newChannels,const uint32_t newFrames)572 void CarlaPlugin::ProtectedData::Latency::recreateBuffers(const uint32_t newChannels, const uint32_t newFrames)
573 {
574     CARLA_SAFE_ASSERT_RETURN(channels != newChannels || frames != newFrames,);
575 
576     const bool retrieveOldBuffer = (channels == newChannels && channels > 0 && frames > 0 && newFrames > 0);
577     float** const oldBuffers = buffers;
578     const uint32_t oldFrames = frames;
579 
580     channels = newChannels;
581     frames   = newFrames;
582 
583     if (channels > 0 && frames > 0)
584     {
585         buffers = new float*[channels];
586 
587         for (uint32_t i=0; i < channels; ++i)
588         {
589             buffers[i] = new float[frames];
590 
591             if (retrieveOldBuffer)
592             {
593                 if (oldFrames > frames)
594                 {
595                     const uint32_t diff = oldFrames - frames;
596                     carla_copyFloats(buffers[i], oldBuffers[i] + diff, frames);
597                 }
598                 else
599                 {
600                     const uint32_t diff = frames - oldFrames;
601                     carla_zeroFloats(buffers[i], diff);
602                     carla_copyFloats(buffers[i] + diff, oldBuffers[i], oldFrames);
603                 }
604             }
605             else
606             {
607                 carla_zeroFloats(buffers[i], frames);
608             }
609         }
610     }
611     else
612     {
613         buffers = nullptr;
614     }
615 
616     // delete old buffer
617     if (oldBuffers != nullptr)
618     {
619         for (uint32_t i=0; i < channels; ++i)
620         {
621             CARLA_SAFE_ASSERT_CONTINUE(oldBuffers[i] != nullptr);
622 
623             delete[] oldBuffers[i];
624             oldBuffers[i] = nullptr;
625         }
626 
627         delete[] oldBuffers;
628     }
629 }
630 #endif
631 
632 // -----------------------------------------------------------------------
633 // ProtectedData::PostRtEvents
634 
PostRtEvents()635 CarlaPlugin::ProtectedData::PostRtEvents::PostRtEvents() noexcept
636     : dataPool("CarlaPlugin::ProtectedData::PostRtEvents", 512, 512),
637       data(dataPool),
638       dataPendingRT(dataPool),
639       dataMutex(),
640       dataPendingMutex(),
641       poolMutex() {}
642 
~PostRtEvents()643 CarlaPlugin::ProtectedData::PostRtEvents::~PostRtEvents() noexcept
644 {
645     const CarlaMutexLocker cml1(dataMutex);
646     const CarlaMutexLocker cml2(dataPendingMutex);
647     const CarlaMutexLocker cml3(poolMutex);
648 
649     data.clear();
650     dataPendingRT.clear();
651 }
652 
appendRT(const PluginPostRtEvent & e)653 void CarlaPlugin::ProtectedData::PostRtEvents::appendRT(const PluginPostRtEvent& e) noexcept
654 {
655     CARLA_SAFE_ASSERT_INT_RETURN(dataPendingMutex.tryLock(), e.type,);
656     {
657         const CarlaMutexLocker cml(poolMutex);
658         dataPendingRT.append(e);
659     }
660     dataPendingMutex.unlock();
661 }
662 
trySplice()663 void CarlaPlugin::ProtectedData::PostRtEvents::trySplice() noexcept
664 {
665     const CarlaMutexTryLocker cmtl(dataPendingMutex);
666 
667     if (cmtl.wasLocked() && dataPendingRT.isNotEmpty() && dataMutex.tryLock())
668     {
669         {
670             const CarlaMutexLocker cml(poolMutex);
671             dataPendingRT.moveTo(data, true);
672         }
673         dataMutex.unlock();
674     }
675 }
676 
677 // -----------------------------------------------------------------------
678 // ProtectedData::PostUiEvents
679 
PostUiEvents()680 CarlaPlugin::ProtectedData::PostUiEvents::PostUiEvents() noexcept
681     : mutex(),
682       data() {}
683 
~PostUiEvents()684 CarlaPlugin::ProtectedData::PostUiEvents::~PostUiEvents() noexcept
685 {
686     clear();
687 }
688 
append(const PluginPostRtEvent & e)689 void CarlaPlugin::ProtectedData::PostUiEvents::append(const PluginPostRtEvent& e) noexcept
690 {
691     mutex.lock();
692     data.append(e);
693     mutex.unlock();
694 }
695 
clear()696 void CarlaPlugin::ProtectedData::PostUiEvents::clear() noexcept
697 {
698     mutex.lock();
699     data.clear();
700     mutex.unlock();
701 }
702 
703 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
704 // -----------------------------------------------------------------------
705 // ProtectedData::PostProc
706 
PostProc()707 CarlaPlugin::ProtectedData::PostProc::PostProc() noexcept
708     : dryWet(1.0f),
709       volume(1.0f),
710       balanceLeft(-1.0f),
711       balanceRight(1.0f),
712       panning(0.0f) {}
713 #endif
714 
715 // -----------------------------------------------------------------------
716 
ProtectedData(CarlaEngine * const eng,const uint idx)717 CarlaPlugin::ProtectedData::ProtectedData(CarlaEngine* const eng, const uint idx) noexcept
718     : engine(eng),
719       client(nullptr),
720       id(idx),
721       hints(0x0),
722       options(0x0),
723       nodeId(0),
724       active(false),
725       enabled(false),
726       needsReset(false),
727       engineBridged(eng->getType() == kEngineTypeBridge),
728       enginePlugin(eng->getType() == kEngineTypePlugin),
729       lib(nullptr),
730       uiLib(nullptr),
731       ctrlChannel(0),
732       extraHints(0x0),
733 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
734       midiLearnParameterIndex(-1),
735       transientTryCounter(0),
736       transientFirstTry(true),
737 #endif
738       name(nullptr),
739       filename(nullptr),
740       iconName(nullptr),
741       audioIn(),
742       audioOut(),
743       cvIn(),
744       cvOut(),
745       event(),
746       param(),
747       prog(),
748       midiprog(),
749       custom(),
750       masterMutex(),
751       singleMutex(),
752       stateSave(),
753       uiTitle(),
754       extNotes(),
755       latency(),
756       postRtEvents(),
757       postUiEvents()
758 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
759     , postProc()
760 #endif
761       {}
762 
~ProtectedData()763 CarlaPlugin::ProtectedData::~ProtectedData() noexcept
764 {
765     CARLA_SAFE_ASSERT(! (active && needsReset));
766 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
767     CARLA_SAFE_ASSERT(transientTryCounter == 0);
768 #endif
769 
770     {
771         // mutex MUST have been locked before
772         const bool lockMaster(masterMutex.tryLock());
773         const bool lockSingle(singleMutex.tryLock());
774         CARLA_SAFE_ASSERT(! lockMaster);
775         CARLA_SAFE_ASSERT(! lockSingle);
776     }
777 
778     if (client != nullptr)
779     {
780         if (client->isActive())
781         {
782             // must not happen
783             carla_safe_assert("client->isActive()", __FILE__, __LINE__);
784             client->deactivate(true);
785         }
786 
787         clearBuffers();
788 
789         delete client;
790         client = nullptr;
791     }
792 
793     if (name != nullptr)
794     {
795         delete[] name;
796         name = nullptr;
797     }
798 
799     if (filename != nullptr)
800     {
801         delete[] filename;
802         filename = nullptr;
803     }
804 
805     if (iconName != nullptr)
806     {
807         delete[] iconName;
808         iconName = nullptr;
809     }
810 
811     for (LinkedList<CustomData>::Itenerator it = custom.begin2(); it.valid(); it.next())
812     {
813         CustomData& customData(it.getValue(kCustomDataFallbackNC));
814         //CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
815 
816         if (customData.type != nullptr)
817         {
818             delete[] customData.type;
819             customData.type = nullptr;
820         }
821         else
822             carla_safe_assert("customData.type != nullptr", __FILE__, __LINE__);
823 
824         if (customData.key != nullptr)
825         {
826             delete[] customData.key;
827             customData.key = nullptr;
828         }
829         else
830             carla_safe_assert("customData.key != nullptr", __FILE__, __LINE__);
831 
832         if (customData.value != nullptr)
833         {
834             delete[] customData.value;
835             customData.value = nullptr;
836         }
837         else
838             carla_safe_assert("customData.value != nullptr", __FILE__, __LINE__);
839     }
840 
841     prog.clear();
842     midiprog.clear();
843     custom.clear();
844 
845     // MUST have been locked before
846     masterMutex.unlock();
847     singleMutex.unlock();
848 
849     CARLA_SAFE_ASSERT(uiLib == nullptr);
850 
851     if (lib != nullptr)
852         libClose();
853 }
854 
855 // -----------------------------------------------------------------------
856 // Buffer functions
857 
clearBuffers()858 void CarlaPlugin::ProtectedData::clearBuffers() noexcept
859 {
860     audioIn.clear();
861     audioOut.clear();
862     cvIn.clear();
863     cvOut.clear();
864     param.clear();
865     event.clear();
866 #ifndef BUILD_BRIDGE
867     latency.clearBuffers();
868 #endif
869 }
870 
871 // -----------------------------------------------------------------------
872 // Post-poned events
873 
postponeRtEvent(const PluginPostRtEvent & rtEvent)874 void CarlaPlugin::ProtectedData::postponeRtEvent(const PluginPostRtEvent& rtEvent) noexcept
875 {
876     CARLA_SAFE_ASSERT_RETURN(rtEvent.type != kPluginPostRtEventNull,);
877 
878     postRtEvents.appendRT(rtEvent);
879 }
880 
postponeParameterChangeRtEvent(const bool sendCallbackLater,const int32_t index,const float value)881 void CarlaPlugin::ProtectedData::postponeParameterChangeRtEvent(const bool sendCallbackLater,
882                                                                 const int32_t index,
883                                                                 const float value) noexcept
884 {
885     PluginPostRtEvent rtEvent = { kPluginPostRtEventParameterChange, sendCallbackLater, {} };
886     rtEvent.parameter.index = index;
887     rtEvent.parameter.value = value;
888 
889     postRtEvents.appendRT(rtEvent);
890 }
891 
postponeProgramChangeRtEvent(const bool sendCallbackLater,const uint32_t index)892 void CarlaPlugin::ProtectedData::postponeProgramChangeRtEvent(const bool sendCallbackLater,
893                                                               const uint32_t index) noexcept
894 {
895     PluginPostRtEvent rtEvent = { kPluginPostRtEventProgramChange, sendCallbackLater, {} };
896     rtEvent.program.index = index;
897 
898     postRtEvents.appendRT(rtEvent);
899 }
900 
postponeMidiProgramChangeRtEvent(const bool sendCallbackLater,const uint32_t index)901 void CarlaPlugin::ProtectedData::postponeMidiProgramChangeRtEvent(const bool sendCallbackLater,
902                                                                   const uint32_t index) noexcept
903 {
904     PluginPostRtEvent rtEvent = { kPluginPostRtEventMidiProgramChange, sendCallbackLater, {} };
905     rtEvent.program.index = index;
906 
907     postRtEvents.appendRT(rtEvent);
908 }
909 
postponeNoteOnRtEvent(const bool sendCallbackLater,const uint8_t channel,const uint8_t note,const uint8_t velocity)910 void CarlaPlugin::ProtectedData::postponeNoteOnRtEvent(const bool sendCallbackLater,
911                                                        const uint8_t channel,
912                                                        const uint8_t note,
913                                                        const uint8_t velocity) noexcept
914 {
915     PluginPostRtEvent rtEvent = { kPluginPostRtEventNoteOn, sendCallbackLater, {} };
916     rtEvent.note.channel = channel;
917     rtEvent.note.note = note;
918     rtEvent.note.velocity = velocity;
919 
920     postRtEvents.appendRT(rtEvent);
921 }
postponeNoteOffRtEvent(const bool sendCallbackLater,const uint8_t channel,const uint8_t note)922 void CarlaPlugin::ProtectedData::postponeNoteOffRtEvent(const bool sendCallbackLater,
923                                                         const uint8_t channel,
924                                                         const uint8_t note) noexcept
925 {
926     PluginPostRtEvent rtEvent = { kPluginPostRtEventNoteOff, sendCallbackLater, {} };
927     rtEvent.note.channel = channel;
928     rtEvent.note.note = note;
929 
930     postRtEvents.appendRT(rtEvent);
931 }
postponeMidiLearnRtEvent(const bool sendCallbackLater,const uint32_t parameter,const uint8_t cc,const uint8_t channel)932 void CarlaPlugin::ProtectedData::postponeMidiLearnRtEvent(const bool sendCallbackLater,
933                                                           const uint32_t parameter,
934                                                           const uint8_t cc,
935                                                           const uint8_t channel) noexcept
936 {
937     PluginPostRtEvent rtEvent = { kPluginPostRtEventMidiLearn, sendCallbackLater, {} };
938     rtEvent.midiLearn.parameter = parameter;
939     rtEvent.midiLearn.cc = cc;
940     rtEvent.midiLearn.channel = channel;
941 
942     postRtEvents.appendRT(rtEvent);
943 }
944 
945 // -----------------------------------------------------------------------
946 // Library functions
947 
948 static LibCounter sLibCounter;
949 
libError(const char * const fname)950 const char* CarlaPlugin::ProtectedData::libError(const char* const fname) noexcept
951 {
952     return lib_error(fname);
953 }
954 
libOpen(const char * const fname)955 bool CarlaPlugin::ProtectedData::libOpen(const char* const fname) noexcept
956 {
957     lib = sLibCounter.open(fname);
958     return (lib != nullptr);
959 }
960 
libClose()961 bool CarlaPlugin::ProtectedData::libClose() noexcept
962 {
963     const bool ret = sLibCounter.close(lib);
964     lib = nullptr;
965     return ret;
966 }
967 
setCanDeleteLib(const bool canDelete)968 void CarlaPlugin::ProtectedData::setCanDeleteLib(const bool canDelete) noexcept
969 {
970     sLibCounter.setCanDelete(lib, canDelete);
971 }
972 
uiLibOpen(const char * const fname,const bool canDelete)973 bool CarlaPlugin::ProtectedData::uiLibOpen(const char* const fname, const bool canDelete) noexcept
974 {
975     uiLib = sLibCounter.open(fname, canDelete);
976     return (uiLib != nullptr);
977 }
978 
uiLibClose()979 bool CarlaPlugin::ProtectedData::uiLibClose() noexcept
980 {
981     const bool ret = sLibCounter.close(uiLib);
982     uiLib = nullptr;
983     return ret;
984 }
985 
986 // -----------------------------------------------------------------------
987 
988 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
tryTransient()989 void CarlaPlugin::ProtectedData::tryTransient() noexcept
990 {
991     if (engine->getOptions().frontendWinId != 0)
992         transientTryCounter = 1;
993 }
994 #endif
995 
updateParameterValues(CarlaPlugin * const plugin,const bool sendCallback,const bool sendOsc,const bool useDefault)996 void CarlaPlugin::ProtectedData::updateParameterValues(CarlaPlugin* const plugin,
997                                                        const bool sendCallback,
998                                                        const bool sendOsc,
999                                                        const bool useDefault) noexcept
1000 {
1001     CARLA_SAFE_ASSERT_RETURN(sendOsc || sendCallback || useDefault,);
1002 
1003     for (uint32_t i=0; i < param.count; ++i)
1004     {
1005         const float value(param.ranges[i].getFixedValue(plugin->getParameterValue(i)));
1006 
1007         if (useDefault)
1008             param.ranges[i].def = value;
1009 
1010         if (useDefault) {
1011             engine->callback(sendCallback, sendOsc,
1012                              ENGINE_CALLBACK_PARAMETER_DEFAULT_CHANGED,
1013                              id,
1014                              static_cast<int>(i),
1015                              0, 0,
1016                              value,
1017                              nullptr);
1018         }
1019 
1020         engine->callback(sendCallback, sendOsc,
1021                          ENGINE_CALLBACK_PARAMETER_VALUE_CHANGED,
1022                          id,
1023                          static_cast<int>(i),
1024                          0, 0,
1025                          value,
1026                          nullptr);
1027     }
1028 }
1029 
updateDefaultParameterValues(CarlaPlugin * const plugin)1030 void CarlaPlugin::ProtectedData::updateDefaultParameterValues(CarlaPlugin* const plugin) noexcept
1031 {
1032     for (uint32_t i=0; i < param.count; ++i)
1033         param.ranges[i].def = param.ranges[i].getFixedValue(plugin->getParameterValue(i));
1034 }
1035 
1036 // -----------------------------------------------------------------------
1037 
1038 CARLA_BACKEND_END_NAMESPACE
1039