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