1 /*
2  * Carla Plugin, LADSPA/DSSI implementation
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 "CarlaEngineUtils.hpp"
20 
21 #include "CarlaBackendUtils.hpp"
22 #include "CarlaLadspaUtils.hpp"
23 #include "CarlaDssiUtils.hpp"
24 #include "CarlaMathUtils.hpp"
25 
26 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
27 # include "CarlaOscUtils.hpp"
28 # include "CarlaScopeUtils.hpp"
29 # include "CarlaThread.hpp"
30 # include "water/threads/ChildProcess.h"
31 using water::ChildProcess;
32 #endif
33 
34 using water::String;
35 using water::StringArray;
36 
37 #define CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(/* argc, types, */ argcToCompare, typesToCompare) \
38     /* check argument count */                                                                  \
39     if (argc != argcToCompare)                                                                  \
40     {                                                                                           \
41         carla_stderr("CarlaPluginLADSPADSSI::%s() - argument count mismatch: %i != %i",         \
42                      __FUNCTION__, argc, argcToCompare);                                        \
43         return;                                                                                 \
44     }                                                                                           \
45     if (argc > 0)                                                                               \
46     {                                                                                           \
47         /* check for nullness */                                                                \
48         if (types == nullptr || typesToCompare == nullptr)                                      \
49         {                                                                                       \
50             carla_stderr("CarlaPluginLADSPADSSI::%s() - argument types are null",               \
51                          __FUNCTION__);                                                         \
52             return;                                                                             \
53         }                                                                                       \
54         /* check argument types */                                                              \
55         if (std::strcmp(types, typesToCompare) != 0)                                            \
56         {                                                                                       \
57             carla_stderr("CarlaPluginLADSPADSSI::%s() - argument types mismatch: '%s' != '%s'", \
58                          __FUNCTION__, types, typesToCompare);                                  \
59             return;                                                                             \
60         }                                                                                       \
61     }
62 
63 CARLA_BACKEND_START_NAMESPACE
64 
65 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
66 // -------------------------------------------------------------------
67 // Fallback data
68 
69 static const CustomData kCustomDataFallback = { nullptr, nullptr, nullptr };
70 
71 // -------------------------------------------------------------------
72 
73 class CarlaThreadDSSIUI : public CarlaThread
74 {
75 public:
CarlaThreadDSSIUI(CarlaEngine * const engine,CarlaPlugin * const plugin,const CarlaOscData & oscData)76     CarlaThreadDSSIUI(CarlaEngine* const engine, CarlaPlugin* const plugin, const CarlaOscData& oscData) noexcept
77         : CarlaThread("CarlaThreadDSSIUI"),
78           kEngine(engine),
79           kPlugin(plugin),
80           fBinary(),
81           fLabel(),
82           fUiTitle(),
83           fOscData(oscData),
84           fProcess() {}
85 
setData(const char * const binary,const char * const label,const char * const uiTitle)86     void setData(const char* const binary, const char* const label, const char* const uiTitle) noexcept
87     {
88         CARLA_SAFE_ASSERT_RETURN(binary != nullptr && binary[0] != '\0',);
89         CARLA_SAFE_ASSERT_RETURN(label != nullptr,);
90         CARLA_SAFE_ASSERT_RETURN(uiTitle != nullptr && uiTitle[0] != '\0',);
91         CARLA_SAFE_ASSERT(! isThreadRunning());
92 
93         fBinary  = binary;
94         fLabel   = label;
95         fUiTitle = uiTitle;
96 
97         if (fLabel.isEmpty())
98             fLabel = "\"\"";
99     }
100 
setUITitle(const char * const uiTitle)101     void setUITitle(const char* const uiTitle) noexcept
102     {
103         CARLA_SAFE_ASSERT_RETURN(uiTitle != nullptr && uiTitle[0] != '\0',);
104 
105         fUiTitle = uiTitle;
106     }
107 
getProcessId() const108     uintptr_t getProcessId() const noexcept
109     {
110         CARLA_SAFE_ASSERT_RETURN(fProcess != nullptr, 0);
111 
112         return (uintptr_t)fProcess->getPID();
113     }
114 
run()115     void run()
116     {
117         carla_stdout("LADSPA/DSSI UI thread started");
118 
119         if (fProcess == nullptr)
120         {
121             fProcess = new ChildProcess();
122         }
123         else if (fProcess->isRunning())
124         {
125             carla_stderr("CarlaThreadDSSI::run() - already running, giving up...");
126 
127             fProcess->kill();
128             fProcess = nullptr;
129             kEngine->callback(true, true,
130                               ENGINE_CALLBACK_UI_STATE_CHANGED,
131                               kPlugin->getId(),
132                               0,
133                               0, 0, 0.0f, nullptr);
134             return;
135         }
136 
137         String name(kPlugin->getName());
138         String filename(kPlugin->getFilename());
139 
140         if (name.isEmpty())
141             name = "(none)";
142 
143         if (filename.isEmpty())
144             filename = "\"\"";
145 
146         StringArray arguments;
147 
148         // binary
149         arguments.add(fBinary.buffer());
150 
151         // osc-url
152         arguments.add(String(kEngine->getOscServerPathUDP()) + String("/") + String(kPlugin->getId()));
153 
154         // filename
155         arguments.add(filename);
156 
157         // label
158         arguments.add(fLabel.buffer());
159 
160         // ui-title
161         arguments.add(fUiTitle.buffer());
162 
163         bool started;
164 
165         {
166 #ifdef CARLA_OS_LINUX
167             /*
168              * If the frontend uses winId parent, set LD_PRELOAD to auto-map the DSSI UI.
169              * If not, unset LD_PRELOAD.
170              */
171             const uintptr_t winId(kEngine->getOptions().frontendWinId);
172 
173             // for CARLA_ENGINE_OPTION_FRONTEND_WIN_ID
174             char winIdStr[STR_MAX+1];
175             winIdStr[STR_MAX] = '\0';
176 
177             // for LD_PRELOAD
178             CarlaString ldPreloadValue;
179 
180             if (winId != 0)
181             {
182                 std::snprintf(winIdStr, STR_MAX, P_UINTPTR, winId);
183                 ldPreloadValue = (CarlaString(kEngine->getOptions().binaryDir)
184                                + "/libcarla_interposer-x11.so");
185             }
186             else
187             {
188                 winIdStr[0] = '\0';
189             }
190 
191             const ScopedEngineEnvironmentLocker _seel(kEngine);
192             const CarlaScopedEnvVar _sev1("CARLA_ENGINE_OPTION_FRONTEND_WIN_ID", winIdStr[0] != '\0' ? winIdStr : nullptr);
193             const CarlaScopedEnvVar _sev2("LD_PRELOAD", ldPreloadValue.isNotEmpty() ? ldPreloadValue.buffer() : nullptr);
194 #endif // CARLA_OS_LINUX
195 
196             // start the DSSI UI application
197             carla_stdout("starting DSSI UI...");
198             started = fProcess->start(arguments);
199         }
200 
201         if (! started)
202         {
203             carla_stdout("failed!");
204             fProcess = nullptr;
205             return;
206         }
207 
208         if (waitForOscGuiShow())
209         {
210             for (; fProcess->isRunning() && ! shouldThreadExit();)
211                 carla_sleep(1);
212 
213             // we only get here if UI was closed or thread asked to exit
214             if (fProcess->isRunning() && shouldThreadExit())
215             {
216                 fProcess->waitForProcessToFinish(static_cast<int>(kEngine->getOptions().uiBridgesTimeout));
217 
218                 if (fProcess->isRunning())
219                 {
220                     carla_stdout("CarlaThreadDSSIUI::run() - UI refused to close, force kill now");
221                     fProcess->kill();
222                 }
223                 else
224                 {
225                     carla_stdout("CarlaThreadDSSIUI::run() - UI auto-closed successfully");
226                 }
227             }
228             else if (fProcess->getExitCodeAndClearPID() != 0)
229                 carla_stderr("CarlaThreadDSSIUI::run() - UI crashed while running");
230             else
231                 carla_stdout("CarlaThreadDSSIUI::run() - UI closed cleanly");
232         }
233         else
234         {
235             fProcess->kill();
236             carla_stdout("CarlaThreadDSSIUI::run() - GUI timeout");
237         }
238 
239         fProcess = nullptr;
240         kEngine->callback(true, true,
241                           ENGINE_CALLBACK_UI_STATE_CHANGED,
242                           kPlugin->getId(),
243                           0,
244                           0, 0, 0.0f, nullptr);
245 
246         carla_stdout("LADSPA/DSSI UI thread finished");
247     }
248 
249 private:
250     CarlaEngine* const kEngine;
251     CarlaPlugin* const kPlugin;
252 
253     CarlaString fBinary;
254     CarlaString fLabel;
255     CarlaString fUiTitle;
256 
257     const CarlaOscData& fOscData;
258     CarlaScopedPointer<ChildProcess> fProcess;
259 
waitForOscGuiShow()260     bool waitForOscGuiShow()
261     {
262         carla_stdout("CarlaThreadDSSIUI::waitForOscGuiShow()");
263         const uint uiBridgesTimeout = kEngine->getOptions().uiBridgesTimeout;
264 
265         // wait for UI 'update' call
266         for (uint i=0; i < uiBridgesTimeout/100; ++i)
267         {
268             if (fOscData.target != nullptr)
269             {
270                 carla_stdout("CarlaThreadDSSIUI::waitForOscGuiShow() - got response, asking UI to show itself now");
271                 osc_send_show(fOscData);
272                 return true;
273             }
274 
275             if (fProcess != nullptr && fProcess->isRunning() && ! shouldThreadExit())
276                 carla_msleep(100);
277             else
278                 return false;
279         }
280 
281         carla_stdout("CarlaThreadDSSIUI::waitForOscGuiShow() - Timeout while waiting for UI to respond"
282                      "(waited %u msecs)", uiBridgesTimeout);
283         return false;
284     }
285 
286     CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaThreadDSSIUI)
287 };
288 #endif
289 
290 // -----------------------------------------------------
291 
292 class CarlaPluginLADSPADSSI : public CarlaPlugin
293 {
294 public:
CarlaPluginLADSPADSSI(CarlaEngine * const engine,const uint id)295     CarlaPluginLADSPADSSI(CarlaEngine* const engine, const uint id) noexcept
296         : CarlaPlugin(engine, id),
297           fHandles(),
298           fDescriptor(nullptr),
299           fDssiDescriptor(nullptr),
300           fRdfDescriptor(nullptr),
301           fAudioInBuffers(nullptr),
302           fAudioOutBuffers(nullptr),
303           fExtraStereoBuffer(),
304           fParamBuffers(nullptr),
305           fLatencyIndex(-1),
306           fForcedStereoIn(false),
307           fForcedStereoOut(false),
308           fNeedsFixedBuffers(false),
309           fUsesCustomData(false)
310 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
311         , fOscData(),
312           fThreadUI(engine, this, fOscData),
313           fUiFilename(nullptr)
314 #endif
315     {
316         carla_debug("CarlaPluginLADSPADSSI::CarlaPluginLADSPADSSI(%p, %i)", engine, id);
317 
318         carla_zeroPointers(fExtraStereoBuffer, 2);
319     }
320 
~CarlaPluginLADSPADSSI()321     ~CarlaPluginLADSPADSSI() noexcept override
322     {
323         carla_debug("CarlaPluginLADSPADSSI::~CarlaPluginLADSPADSSI()");
324 
325 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
326         // close UI
327         if (fUiFilename != nullptr)
328         {
329             showCustomUI(false);
330 
331             delete[] fUiFilename;
332             fUiFilename = nullptr;
333         }
334 #endif
335 
336         pData->singleMutex.lock();
337         pData->masterMutex.lock();
338 
339         if (pData->client != nullptr && pData->client->isActive())
340             pData->client->deactivate(true);
341 
342         if (pData->active)
343         {
344             deactivate();
345             pData->active = false;
346         }
347 
348         if (fDescriptor != nullptr)
349         {
350             if (fDescriptor->cleanup != nullptr)
351             {
352                 for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
353                 {
354                     LADSPA_Handle const handle(it.getValue(nullptr));
355                     CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
356 
357                     try {
358                         fDescriptor->cleanup(handle);
359                     } CARLA_SAFE_EXCEPTION("LADSPA/DSSI cleanup");
360                 }
361             }
362 
363             fHandles.clear();
364             fDescriptor = nullptr;
365             fDssiDescriptor = nullptr;
366         }
367 
368         if (fRdfDescriptor != nullptr)
369         {
370             delete fRdfDescriptor;
371             fRdfDescriptor = nullptr;
372         }
373 
374         clearBuffers();
375     }
376 
377     // -------------------------------------------------------------------
378     // Information (base)
379 
getType() const380     PluginType getType() const noexcept override
381     {
382         return fDssiDescriptor != nullptr ? PLUGIN_DSSI : PLUGIN_LADSPA;
383     }
384 
getCategory() const385     PluginCategory getCategory() const noexcept override
386     {
387         if (fRdfDescriptor != nullptr)
388         {
389             const LADSPA_RDF_PluginType category = fRdfDescriptor->Type;
390 
391             // Specific Types
392             if (category & (LADSPA_RDF_PLUGIN_DELAY|LADSPA_RDF_PLUGIN_REVERB))
393                 return PLUGIN_CATEGORY_DELAY;
394             if (category & (LADSPA_RDF_PLUGIN_PHASER|LADSPA_RDF_PLUGIN_FLANGER|LADSPA_RDF_PLUGIN_CHORUS))
395                 return PLUGIN_CATEGORY_MODULATOR;
396             if (category & (LADSPA_RDF_PLUGIN_AMPLIFIER))
397                 return PLUGIN_CATEGORY_DYNAMICS;
398             if (category & (LADSPA_RDF_PLUGIN_UTILITY|LADSPA_RDF_PLUGIN_SPECTRAL|LADSPA_RDF_PLUGIN_FREQUENCY_METER))
399                 return PLUGIN_CATEGORY_UTILITY;
400 
401             // Pre-set LADSPA Types
402             if (LADSPA_RDF_IS_PLUGIN_DYNAMICS(category))
403                 return PLUGIN_CATEGORY_DYNAMICS;
404             if (LADSPA_RDF_IS_PLUGIN_AMPLITUDE(category))
405                 return PLUGIN_CATEGORY_MODULATOR;
406             if (LADSPA_RDF_IS_PLUGIN_EQ(category))
407                 return PLUGIN_CATEGORY_EQ;
408             if (LADSPA_RDF_IS_PLUGIN_FILTER(category))
409                 return PLUGIN_CATEGORY_FILTER;
410             if (LADSPA_RDF_IS_PLUGIN_FREQUENCY(category))
411                 return PLUGIN_CATEGORY_UTILITY;
412             if (LADSPA_RDF_IS_PLUGIN_SIMULATOR(category))
413                 return PLUGIN_CATEGORY_OTHER;
414             if (LADSPA_RDF_IS_PLUGIN_TIME(category))
415                 return PLUGIN_CATEGORY_DELAY;
416             if (LADSPA_RDF_IS_PLUGIN_GENERATOR(category))
417                 return PLUGIN_CATEGORY_SYNTH;
418         }
419 
420         if (fDssiDescriptor != nullptr && fDssiDescriptor->run_synth != nullptr)
421             if (pData->audioIn.count == 0 && pData->audioOut.count > 0)
422                 return PLUGIN_CATEGORY_SYNTH;
423 
424         return CarlaPlugin::getCategory();
425     }
426 
getUniqueId() const427     int64_t getUniqueId() const noexcept override
428     {
429         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, 0);
430 
431         return static_cast<int64_t>(fDescriptor->UniqueID);
432     }
433 
getLatencyInFrames() const434     uint32_t getLatencyInFrames() const noexcept override
435     {
436         if (fLatencyIndex < 0 || fParamBuffers == nullptr)
437             return 0;
438 
439         const float latency(fParamBuffers[fLatencyIndex]);
440         CARLA_SAFE_ASSERT_RETURN(latency >= 0.0f, 0);
441 
442         return static_cast<uint32_t>(latency);
443     }
444 
445     // -------------------------------------------------------------------
446     // Information (count)
447 
getParameterScalePointCount(const uint32_t parameterId) const448     uint32_t getParameterScalePointCount(const uint32_t parameterId) const noexcept override
449     {
450         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0);
451 
452         if (fRdfDescriptor == nullptr)
453             return 0;
454 
455         const int32_t rindex(pData->param.data[parameterId].rindex);
456         CARLA_SAFE_ASSERT_RETURN(rindex >= 0, 0);
457 
458         if (rindex >= static_cast<int32_t>(fRdfDescriptor->PortCount))
459             return 0;
460 
461         const LADSPA_RDF_Port& port(fRdfDescriptor->Ports[rindex]);
462         return static_cast<uint32_t>(port.ScalePointCount);
463     }
464 
465     // -------------------------------------------------------------------
466     // Information (current data)
467 
getChunkData(void ** const dataPtr)468     std::size_t getChunkData(void** const dataPtr) noexcept override
469     {
470         CARLA_SAFE_ASSERT_RETURN(fUsesCustomData, 0);
471         CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS, 0);
472         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr, 0);
473         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor->get_custom_data != nullptr, 0);
474         CARLA_SAFE_ASSERT_RETURN(fHandles.count() > 0, 0);
475         CARLA_SAFE_ASSERT_RETURN(dataPtr != nullptr, 0);
476 
477         *dataPtr = nullptr;
478 
479         int ret = 0;
480         ulong dataSize = 0;
481 
482         try {
483             ret = fDssiDescriptor->get_custom_data(fHandles.getFirst(nullptr), dataPtr, &dataSize);
484         } CARLA_SAFE_EXCEPTION_RETURN("CarlaPluginLADSPADSSI::getChunkData", 0);
485 
486         return (ret != 0) ? dataSize : 0;
487     }
488 
489     // -------------------------------------------------------------------
490     // Information (per-plugin data)
491 
getOptionsAvailable() const492     uint getOptionsAvailable() const noexcept override
493     {
494         uint options = 0x0;
495 
496         // can't disable fixed buffers if using latency
497         if (fLatencyIndex == -1 && ! fNeedsFixedBuffers)
498             options |= PLUGIN_OPTION_FIXED_BUFFERS;
499 
500         // can't disable forced stereo if enabled in the engine
501         if (pData->engine->getOptions().forceStereo)
502             pass();
503         // if inputs or outputs are just 1, then yes we can force stereo
504         else if (pData->audioIn.count == 1 || pData->audioOut.count == 1 || fForcedStereoIn || fForcedStereoOut)
505             options |= PLUGIN_OPTION_FORCE_STEREO;
506 
507         if (fDssiDescriptor != nullptr)
508         {
509             if (fDssiDescriptor->get_program != nullptr && fDssiDescriptor->select_program != nullptr)
510                 options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
511 
512             if (fUsesCustomData)
513                 options |= PLUGIN_OPTION_USE_CHUNKS;
514 
515             if (fDssiDescriptor->run_synth != nullptr)
516             {
517                 options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
518                 options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
519                 options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
520                 options |= PLUGIN_OPTION_SEND_PITCHBEND;
521                 options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
522                 options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
523             }
524         }
525 
526         return options;
527     }
528 
getParameterValue(const uint32_t parameterId) const529     float getParameterValue(const uint32_t parameterId) const noexcept override
530     {
531         CARLA_SAFE_ASSERT_RETURN(fParamBuffers != nullptr,         0.0f);
532         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f);
533 
534         // bad plugins might have set output values out of bounds
535         if (pData->param.data[parameterId].type == PARAMETER_OUTPUT)
536             return pData->param.ranges[parameterId].getFixedValue(fParamBuffers[parameterId]);
537 
538         // not output, should be fine
539         return fParamBuffers[parameterId];
540     }
541 
getParameterScalePointValue(const uint32_t parameterId,const uint32_t scalePointId) const542     float getParameterScalePointValue(const uint32_t parameterId, const uint32_t scalePointId) const noexcept override
543     {
544         CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor != nullptr,        0.0f);
545         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, 0.0f);
546 
547         const int32_t rindex(pData->param.data[parameterId].rindex);
548         CARLA_SAFE_ASSERT_RETURN(rindex >= 0,                                              0.0f);
549         CARLA_SAFE_ASSERT_RETURN(rindex < static_cast<int32_t>(fRdfDescriptor->PortCount), 0.0f);
550 
551         const LADSPA_RDF_Port& port(fRdfDescriptor->Ports[rindex]);
552         CARLA_SAFE_ASSERT_RETURN(scalePointId < port.ScalePointCount, 0.0f);
553 
554         const LADSPA_RDF_ScalePoint& scalePoint(port.ScalePoints[scalePointId]);
555         return pData->param.ranges[parameterId].getFixedValue(scalePoint.Value);
556     }
557 
getLabel(char * const strBuf) const558     bool getLabel(char* const strBuf) const noexcept override
559     {
560         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
561         CARLA_SAFE_ASSERT_RETURN(fDescriptor->Label != nullptr, false);
562 
563         std::strncpy(strBuf, fDescriptor->Label, STR_MAX);
564         return true;
565     }
566 
getMaker(char * const strBuf) const567     bool getMaker(char* const strBuf) const noexcept override
568     {
569         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
570         CARLA_SAFE_ASSERT_RETURN(fDescriptor->Maker != nullptr, false);
571 
572         if (fRdfDescriptor != nullptr && fRdfDescriptor->Creator != nullptr)
573             std::strncpy(strBuf, fRdfDescriptor->Creator, STR_MAX);
574         else
575             std::strncpy(strBuf, fDescriptor->Maker, STR_MAX);
576 
577         return true;
578     }
579 
getCopyright(char * const strBuf) const580     bool getCopyright(char* const strBuf) const noexcept override
581     {
582         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
583         CARLA_SAFE_ASSERT_RETURN(fDescriptor->Copyright != nullptr, false);
584 
585         std::strncpy(strBuf, fDescriptor->Copyright, STR_MAX);
586         return true;
587     }
588 
getRealName(char * const strBuf) const589     bool getRealName(char* const strBuf) const noexcept override
590     {
591         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
592         CARLA_SAFE_ASSERT_RETURN(fDescriptor->Name != nullptr, false);
593 
594         if (fRdfDescriptor != nullptr && fRdfDescriptor->Title != nullptr)
595             std::strncpy(strBuf, fRdfDescriptor->Title, STR_MAX);
596         else
597             std::strncpy(strBuf, fDescriptor->Name, STR_MAX);
598 
599         return true;
600     }
601 
getParameterName(const uint32_t parameterId,char * const strBuf) const602     bool getParameterName(const uint32_t parameterId, char* const strBuf) const noexcept override
603     {
604         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr, false);
605         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
606 
607         const int32_t rindex(pData->param.data[parameterId].rindex);
608         CARLA_SAFE_ASSERT_RETURN(rindex >= 0, false);
609         CARLA_SAFE_ASSERT_RETURN(rindex < static_cast<int32_t>(fDescriptor->PortCount), false);
610         CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortNames[rindex] != nullptr, false);
611 
612         if (! getSeparatedParameterNameOrUnit(fDescriptor->PortNames[rindex], strBuf, true))
613             std::strncpy(strBuf, fDescriptor->PortNames[rindex], STR_MAX);
614 
615         return true;
616     }
617 
getParameterUnit(const uint32_t parameterId,char * const strBuf) const618     bool getParameterUnit(const uint32_t parameterId, char* const strBuf) const noexcept override
619     {
620         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
621 
622         const int32_t rindex(pData->param.data[parameterId].rindex);
623         CARLA_SAFE_ASSERT_RETURN(rindex >= 0, false);
624 
625         if (fRdfDescriptor != nullptr && rindex < static_cast<int32_t>(fRdfDescriptor->PortCount))
626         {
627             const LADSPA_RDF_Port& port(fRdfDescriptor->Ports[rindex]);
628 
629             if (LADSPA_RDF_PORT_HAS_UNIT(port.Hints))
630             {
631                 switch (port.Unit)
632                 {
633                 case LADSPA_RDF_UNIT_DB:
634                     std::strncpy(strBuf, "dB", STR_MAX);
635                     return true;
636                 case LADSPA_RDF_UNIT_COEF:
637                     std::strncpy(strBuf, "(coef)", STR_MAX);
638                     return true;
639                 case LADSPA_RDF_UNIT_HZ:
640                     std::strncpy(strBuf, "Hz", STR_MAX);
641                     return true;
642                 case LADSPA_RDF_UNIT_S:
643                     std::strncpy(strBuf, "s", STR_MAX);
644                     return true;
645                 case LADSPA_RDF_UNIT_MS:
646                     std::strncpy(strBuf, "ms", STR_MAX);
647                     return true;
648                 case LADSPA_RDF_UNIT_MIN:
649                     std::strncpy(strBuf, "min", STR_MAX);
650                     return true;
651                 }
652             }
653         }
654 
655         CARLA_SAFE_ASSERT_RETURN(rindex < static_cast<int32_t>(fDescriptor->PortCount), false);
656         CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortNames[rindex] != nullptr, false);
657 
658         return getSeparatedParameterNameOrUnit(fDescriptor->PortNames[rindex], strBuf, false);
659     }
660 
getParameterSymbol(const uint32_t parameterId,char * const strBuf) const661     bool getParameterSymbol(const uint32_t parameterId, char* const strBuf) const noexcept override
662     {
663         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
664 
665         if (fRdfDescriptor == nullptr)
666             return false;
667 
668         const int32_t rindex(pData->param.data[parameterId].rindex);
669         CARLA_SAFE_ASSERT_RETURN(rindex >= 0, false);
670 
671         if (rindex >= static_cast<int32_t>(fRdfDescriptor->PortCount))
672             return false;
673 
674         const LADSPA_RDF_Port& port(fRdfDescriptor->Ports[rindex]);
675 
676         if (! LADSPA_RDF_PORT_HAS_LABEL(port.Hints))
677             return false;
678 
679         CARLA_SAFE_ASSERT_RETURN(port.Label != nullptr, false);
680 
681         std::strncpy(strBuf, port.Label, STR_MAX);
682         return true;
683     }
684 
getParameterScalePointLabel(const uint32_t parameterId,const uint32_t scalePointId,char * const strBuf) const685     bool getParameterScalePointLabel(const uint32_t parameterId, const uint32_t scalePointId, char* const strBuf) const noexcept override
686     {
687         CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor != nullptr, false);
688         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count, false);
689 
690         const int32_t rindex(pData->param.data[parameterId].rindex);
691         CARLA_SAFE_ASSERT_RETURN(rindex >= 0, false);
692         CARLA_SAFE_ASSERT_RETURN(rindex < static_cast<int32_t>(fRdfDescriptor->PortCount), false);
693 
694         const LADSPA_RDF_Port& port(fRdfDescriptor->Ports[rindex]);
695         CARLA_SAFE_ASSERT_RETURN(scalePointId < port.ScalePointCount, false);
696 
697         const LADSPA_RDF_ScalePoint& scalePoint(port.ScalePoints[scalePointId]);
698         CARLA_SAFE_ASSERT_RETURN(scalePoint.Label != nullptr, false);
699 
700         std::strncpy(strBuf, scalePoint.Label, STR_MAX);
701         return true;
702     }
703 
704     // -------------------------------------------------------------------
705     // Set data (state)
706 
707     // nothing
708 
709     // -------------------------------------------------------------------
710     // Set data (internal stuff)
711 
setId(const uint newId)712     void setId(const uint newId) noexcept override
713     {
714         CarlaPlugin::setId(newId);
715 
716         // UI osc-url uses Id, so we need to close it when it changes
717         // FIXME - must be RT safe
718         showCustomUI(false);
719     }
720 
721     // -------------------------------------------------------------------
722     // Set data (plugin-specific stuff)
723 
setParameterValue(const uint32_t parameterId,const float value,const bool sendGui,const bool sendOsc,const bool sendCallback)724     void setParameterValue(const uint32_t parameterId, const float value, const bool sendGui, const bool sendOsc, const bool sendCallback) noexcept override
725     {
726         CARLA_SAFE_ASSERT_RETURN(fParamBuffers != nullptr,);
727         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
728 
729         const float fixedValue(pData->param.getFixedValue(parameterId, value));
730         fParamBuffers[parameterId] = fixedValue;
731 
732         CarlaPlugin::setParameterValue(parameterId, fixedValue, sendGui, sendOsc, sendCallback);
733     }
734 
setParameterValueRT(const uint32_t parameterId,const float value,const bool sendCallbackLater)735     void setParameterValueRT(const uint32_t parameterId, const float value, const bool sendCallbackLater) noexcept override
736     {
737         CARLA_SAFE_ASSERT_RETURN(fParamBuffers != nullptr,);
738         CARLA_SAFE_ASSERT_RETURN(parameterId < pData->param.count,);
739 
740         const float fixedValue(pData->param.getFixedValue(parameterId, value));
741         fParamBuffers[parameterId] = fixedValue;
742 
743         CarlaPlugin::setParameterValueRT(parameterId, fixedValue, sendCallbackLater);
744     }
745 
setCustomData(const char * const type,const char * const key,const char * const value,const bool sendGui)746     void setCustomData(const char* const type, const char* const key, const char* const value, const bool sendGui) override
747     {
748         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
749         CARLA_SAFE_ASSERT_RETURN(type != nullptr && type[0] != '\0',);
750         CARLA_SAFE_ASSERT_RETURN(key != nullptr && key[0] != '\0',);
751         CARLA_SAFE_ASSERT_RETURN(value != nullptr,);
752         carla_debug("CarlaPluginLADSPADSSI::setCustomData(%s, %s, %s, %s)", type, key, value, bool2str(sendGui));
753 
754         if (std::strcmp(type, CUSTOM_DATA_TYPE_PROPERTY) == 0)
755             return CarlaPlugin::setCustomData(type, key, value, sendGui);
756 
757         if (std::strcmp(type, CUSTOM_DATA_TYPE_STRING) != 0)
758             return carla_stderr2("CarlaPluginLADSPADSSI::setCustomData(\"%s\", \"%s\", \"%s\", %s) - type is not string",
759                                  type, key, value, bool2str(sendGui));
760 
761         if (fDssiDescriptor->configure != nullptr && fHandles.count() > 0)
762         {
763             for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
764             {
765                 LADSPA_Handle const handle(it.getValue(nullptr));
766                 CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
767 
768                 try {
769                     fDssiDescriptor->configure(handle, key, value);
770                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI setCustomData");
771             }
772         }
773 
774 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
775         if (sendGui && fOscData.target != nullptr)
776             osc_send_configure(fOscData, key, value);
777 #endif
778 
779         if (std::strcmp(key, "reloadprograms") == 0 || std::strcmp(key, "load") == 0 || std::strncmp(key, "patches", 7) == 0)
780         {
781             const ScopedSingleProcessLocker spl(this, true);
782             reloadPrograms(false);
783         }
784 
785         CarlaPlugin::setCustomData(type, key, value, sendGui);
786     }
787 
setChunkData(const void * const data,const std::size_t dataSize)788     void setChunkData(const void* const data, const std::size_t dataSize) override
789     {
790         CARLA_SAFE_ASSERT_RETURN(fUsesCustomData,);
791         CARLA_SAFE_ASSERT_RETURN(pData->options & PLUGIN_OPTION_USE_CHUNKS,);
792         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
793         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor->set_custom_data != nullptr,);
794         CARLA_SAFE_ASSERT_RETURN(data != nullptr,);
795         CARLA_SAFE_ASSERT_RETURN(dataSize > 0,);
796 
797         if (fHandles.count() > 0)
798         {
799             const ScopedSingleProcessLocker spl(this, true);
800 
801             for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
802             {
803                 LADSPA_Handle const handle(it.getValue(nullptr));
804                 CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
805 
806                 try {
807                     fDssiDescriptor->set_custom_data(handle, const_cast<void*>(data), static_cast<ulong>(dataSize));
808                 } CARLA_SAFE_EXCEPTION("CarlaPluginLADSPADSSI::setChunkData");
809             }
810         }
811 
812         pData->updateParameterValues(this, true, true, false);
813     }
814 
setMidiProgram(const int32_t index,const bool sendGui,const bool sendOsc,const bool sendCallback,const bool doingInit)815     void setMidiProgram(const int32_t index, const bool sendGui, const bool sendOsc, const bool sendCallback, const bool doingInit) noexcept override
816     {
817         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
818         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor->select_program != nullptr,);
819         CARLA_SAFE_ASSERT_RETURN(index >= -1 && index < static_cast<int32_t>(pData->midiprog.count),);
820         CARLA_SAFE_ASSERT_RETURN(sendGui || sendOsc || sendCallback || doingInit,);
821 
822         if (index >= 0 && fHandles.count() > 0)
823         {
824             const ScopedSingleProcessLocker spl(this, (sendGui || sendOsc || sendCallback));
825 
826             setMidiProgramInDSSI(static_cast<uint32_t>(index));
827         }
828 
829         CarlaPlugin::setMidiProgram(index, sendGui, sendOsc, sendCallback, doingInit);
830     }
831 
setMidiProgramRT(const uint32_t uindex,const bool sendCallbackLater)832     void setMidiProgramRT(const uint32_t uindex, const bool sendCallbackLater) noexcept override
833     {
834         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor != nullptr,);
835         CARLA_SAFE_ASSERT_RETURN(fDssiDescriptor->select_program != nullptr,);
836         CARLA_SAFE_ASSERT_RETURN(uindex < pData->midiprog.count,);
837 
838         setMidiProgramInDSSI(uindex);
839 
840         CarlaPlugin::setMidiProgramRT(uindex, sendCallbackLater);
841     }
842 
setMidiProgramInDSSI(const uint32_t uindex)843     void setMidiProgramInDSSI(const uint32_t uindex) noexcept
844     {
845         const uint32_t bank(pData->midiprog.data[uindex].bank);
846         const uint32_t program(pData->midiprog.data[uindex].program);
847 
848         for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
849         {
850             LADSPA_Handle const handle(it.getValue(nullptr));
851             CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
852 
853             try {
854                 fDssiDescriptor->select_program(handle, bank, program);
855             } CARLA_SAFE_EXCEPTION("LADSPA/DSSI setMidiProgram")
856         }
857     }
858 
859 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
860     // -------------------------------------------------------------------
861     // Set ui stuff
862 
setCustomUITitle(const char * title)863     void setCustomUITitle(const char* title) noexcept override
864     {
865         fThreadUI.setUITitle(title);
866         CarlaPlugin::setCustomUITitle(title);
867     }
868 
showCustomUI(const bool yesNo)869     void showCustomUI(const bool yesNo) override
870     {
871         if (yesNo)
872         {
873             fOscData.clear();
874             fThreadUI.startThread();
875         }
876         else
877         {
878 #ifndef BUILD_BRIDGE
879             pData->transientTryCounter = 0;
880 #endif
881 
882             if (fOscData.target != nullptr)
883             {
884                 osc_send_hide(fOscData);
885                 osc_send_quit(fOscData);
886                 fOscData.clear();
887             }
888 
889             fThreadUI.stopThread(static_cast<int>(pData->engine->getOptions().uiBridgesTimeout * 2));
890         }
891     }
892 #endif
893 
894     // -------------------------------------------------------------------
895     // Plugin state
896 
reload()897     void reload() override
898     {
899         CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr,);
900         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
901         CARLA_SAFE_ASSERT_RETURN(fHandles.count() > 0,);
902         carla_debug("CarlaPluginLADSPADSSI::reload() - start");
903 
904         const EngineProcessMode processMode(pData->engine->getProccessMode());
905 
906         // Safely disable plugin for reload
907         const ScopedDisabler sd(this);
908 
909         if (pData->active)
910             deactivate();
911 
912         clearBuffers();
913 
914         const float sampleRate(static_cast<float>(pData->engine->getSampleRate()));
915         const uint32_t portCount(getSafePortCount());
916 
917         uint32_t aIns, aOuts, mIns, params;
918         aIns = aOuts = mIns = params = 0;
919 
920         bool forcedStereoIn, forcedStereoOut;
921         forcedStereoIn = forcedStereoOut = false;
922 
923         bool needsCtrlIn, needsCtrlOut;
924         needsCtrlIn = needsCtrlOut = false;
925 
926         for (uint32_t i=0; i < portCount; ++i)
927         {
928             const LADSPA_PortDescriptor portType(fDescriptor->PortDescriptors[i]);
929 
930             if (LADSPA_IS_PORT_AUDIO(portType))
931             {
932                 if (LADSPA_IS_PORT_INPUT(portType))
933                     aIns += 1;
934                 else if (LADSPA_IS_PORT_OUTPUT(portType))
935                     aOuts += 1;
936             }
937             else if (LADSPA_IS_PORT_CONTROL(portType))
938                 params += 1;
939         }
940 
941         if (pData->options & PLUGIN_OPTION_FORCE_STEREO)
942         {
943             if ((aIns == 1 || aOuts == 1) && fHandles.count() == 1 && addInstance())
944             {
945                 if (aIns == 1)
946                 {
947                     aIns = 2;
948                     forcedStereoIn = true;
949                 }
950                 if (aOuts == 1)
951                 {
952                     aOuts = 2;
953                     forcedStereoOut = true;
954                 }
955             }
956         }
957 
958         if (fDssiDescriptor != nullptr && fDssiDescriptor->run_synth != nullptr)
959         {
960             mIns = 1;
961             needsCtrlIn = true;
962         }
963 
964         if (aIns > 0)
965         {
966             pData->audioIn.createNew(aIns);
967             fAudioInBuffers = new float*[aIns];
968 
969             for (uint32_t i=0; i < aIns; ++i)
970                 fAudioInBuffers[i] = nullptr;
971         }
972 
973         if (aOuts > 0)
974         {
975             pData->audioOut.createNew(aOuts);
976             fAudioOutBuffers = new float*[aOuts];
977             needsCtrlIn = true;
978 
979             for (uint32_t i=0; i < aOuts; ++i)
980                 fAudioOutBuffers[i] = nullptr;
981         }
982 
983         if (params > 0)
984         {
985             pData->param.createNew(params, true);
986 
987             fParamBuffers = new float[params];
988             carla_zeroFloats(fParamBuffers, params);
989         }
990 
991         const uint portNameSize(pData->engine->getMaxPortNameSize());
992         CarlaString portName;
993 
994         for (uint32_t i=0, iAudioIn=0, iAudioOut=0, iCtrl=0; i < portCount; ++i)
995         {
996             const LADSPA_PortDescriptor portType      = fDescriptor->PortDescriptors[i];
997             const LADSPA_PortRangeHint portRangeHints = fDescriptor->PortRangeHints[i];
998             const bool hasPortRDF = (fRdfDescriptor != nullptr && i < fRdfDescriptor->PortCount);
999 
1000             if (LADSPA_IS_PORT_AUDIO(portType))
1001             {
1002                 portName.clear();
1003 
1004                 if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1005                 {
1006                     portName  = pData->name;
1007                     portName += ":";
1008                 }
1009 
1010                 if (fDescriptor->PortNames[i] != nullptr && fDescriptor->PortNames[i][0] != '\0')
1011                 {
1012                     portName += fDescriptor->PortNames[i];
1013                 }
1014                 else
1015                 {
1016                     if (LADSPA_IS_PORT_INPUT(portType))
1017                     {
1018                         if (aIns > 1)
1019                         {
1020                             portName += "audio-in_";
1021                             portName += CarlaString(iAudioIn+1);
1022                         }
1023                         else
1024                             portName += "audio-in";
1025                     }
1026                     else
1027                     {
1028                         if (aOuts > 1)
1029                         {
1030                             portName += "audio-out_";
1031                             portName += CarlaString(iAudioOut+1);
1032                         }
1033                         else
1034                             portName += "audio-out";
1035                     }
1036                 }
1037 
1038                 portName.truncate(portNameSize);
1039 
1040                 if (LADSPA_IS_PORT_INPUT(portType))
1041                 {
1042                     const uint32_t j = iAudioIn++;
1043                     pData->audioIn.ports[j].port   = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, j);
1044                     pData->audioIn.ports[j].rindex = i;
1045 
1046                     if (forcedStereoIn)
1047                     {
1048                         portName += "_2";
1049                         pData->audioIn.ports[1].port   = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, true, 1);
1050                         pData->audioIn.ports[1].rindex = i;
1051                     }
1052                 }
1053                 else if (LADSPA_IS_PORT_OUTPUT(portType))
1054                 {
1055                     const uint32_t j = iAudioOut++;
1056                     pData->audioOut.ports[j].port   = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, j);
1057                     pData->audioOut.ports[j].rindex = i;
1058 
1059                     if (forcedStereoOut)
1060                     {
1061                         portName += "_2";
1062                         pData->audioOut.ports[1].port   = (CarlaEngineAudioPort*)pData->client->addPort(kEnginePortTypeAudio, portName, false, 1);
1063                         pData->audioOut.ports[1].rindex = i;
1064                     }
1065                 }
1066                 else
1067                     carla_stderr2("WARNING - Got a broken Port (Audio, but not input or output)");
1068             }
1069             else if (LADSPA_IS_PORT_CONTROL(portType))
1070             {
1071                 const uint32_t j = iCtrl++;
1072                 pData->param.data[j].index  = static_cast<int32_t>(j);
1073                 pData->param.data[j].rindex = static_cast<int32_t>(i);
1074 
1075                 const char* const paramName(fDescriptor->PortNames[i] != nullptr ? fDescriptor->PortNames[i] : "unknown");
1076 
1077                 float min, max, def, step, stepSmall, stepLarge;
1078 
1079                 // min value
1080                 if (LADSPA_IS_HINT_BOUNDED_BELOW(portRangeHints.HintDescriptor))
1081                     min = portRangeHints.LowerBound;
1082                 else
1083                     min = 0.0f;
1084 
1085                 // max value
1086                 if (LADSPA_IS_HINT_BOUNDED_ABOVE(portRangeHints.HintDescriptor))
1087                     max = portRangeHints.UpperBound;
1088                 else
1089                     max = 1.0f;
1090 
1091                 if (LADSPA_IS_HINT_SAMPLE_RATE(portRangeHints.HintDescriptor))
1092                 {
1093                     min *= sampleRate;
1094                     max *= sampleRate;
1095                     pData->param.data[j].hints |= PARAMETER_USES_SAMPLERATE;
1096                 }
1097 
1098                 if (min >= max)
1099                 {
1100                     carla_stderr2("WARNING - Broken plugin parameter '%s': min >= max", paramName);
1101                     max = min + 0.1f;
1102                 }
1103 
1104                 // default value
1105                 if (hasPortRDF && LADSPA_RDF_PORT_HAS_DEFAULT(fRdfDescriptor->Ports[i].Hints))
1106                     def = fRdfDescriptor->Ports[i].Default;
1107                 else
1108                     def = get_default_ladspa_port_value(portRangeHints.HintDescriptor, min, max);
1109 
1110                 if (def < min)
1111                     def = min;
1112                 else if (def > max)
1113                     def = max;
1114 
1115                 if (LADSPA_IS_HINT_TOGGLED(portRangeHints.HintDescriptor))
1116                 {
1117                     step = max - min;
1118                     stepSmall = step;
1119                     stepLarge = step;
1120                     pData->param.data[j].hints |= PARAMETER_IS_BOOLEAN;
1121                 }
1122                 else if (LADSPA_IS_HINT_INTEGER(portRangeHints.HintDescriptor))
1123                 {
1124                     step = 1.0f;
1125                     stepSmall = 1.0f;
1126                     stepLarge = 10.0f;
1127                     pData->param.data[j].hints |= PARAMETER_IS_INTEGER;
1128                 }
1129                 else
1130                 {
1131                     const float range = max - min;
1132                     step = range/100.0f;
1133                     stepSmall = range/1000.0f;
1134                     stepLarge = range/10.0f;
1135                 }
1136 
1137                 if (LADSPA_IS_PORT_INPUT(portType))
1138                 {
1139                     pData->param.data[j].type   = PARAMETER_INPUT;
1140                     pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
1141                     pData->param.data[j].hints |= PARAMETER_IS_AUTOMABLE;
1142                     pData->param.data[j].hints |= PARAMETER_CAN_BE_CV_CONTROLLED;
1143                     needsCtrlIn = true;
1144 
1145                     // MIDI CC value
1146                     if (fDssiDescriptor != nullptr && fDssiDescriptor->get_midi_controller_for_port != nullptr)
1147                     {
1148                         const int ctrl = fDssiDescriptor->get_midi_controller_for_port(fHandles.getFirst(nullptr), i);
1149                         if (DSSI_CONTROLLER_IS_SET(ctrl) && DSSI_IS_CC(ctrl))
1150                         {
1151                             const int16_t cc = DSSI_CC_NUMBER(ctrl);
1152                             if (cc < MAX_MIDI_CONTROL && ! MIDI_IS_CONTROL_BANK_SELECT(cc))
1153                                 pData->param.data[j].mappedControlIndex = cc;
1154                         }
1155                     }
1156                 }
1157                 else if (LADSPA_IS_PORT_OUTPUT(portType))
1158                 {
1159                     pData->param.data[j].type = PARAMETER_OUTPUT;
1160 
1161                     if (std::strcmp(paramName, "latency") == 0 || std::strcmp(paramName, "_latency") == 0)
1162                     {
1163                         min = 0.0f;
1164                         max = sampleRate;
1165                         def = 0.0f;
1166                         step = 1.0f;
1167                         stepSmall = 1.0f;
1168                         stepLarge = 1.0f;
1169                         pData->param.special[j] = PARAMETER_SPECIAL_LATENCY;
1170                         CARLA_SAFE_ASSERT_INT2(fLatencyIndex == static_cast<int32_t>(j), fLatencyIndex, j);
1171                     }
1172                     else
1173                     {
1174                         pData->param.data[j].hints |= PARAMETER_IS_ENABLED;
1175                         pData->param.data[j].hints |= PARAMETER_IS_AUTOMABLE;
1176                         needsCtrlOut = true;
1177                     }
1178                 }
1179                 else
1180                 {
1181                     carla_stderr2("WARNING - Got a broken Port (Control, but not input or output)");
1182                 }
1183 
1184                 // extra parameter hints
1185                 if (LADSPA_IS_HINT_LOGARITHMIC(portRangeHints.HintDescriptor))
1186                     pData->param.data[j].hints |= PARAMETER_IS_LOGARITHMIC;
1187 
1188                 // check for scalepoints, require at least 2 to make it useful
1189                 if (hasPortRDF && fRdfDescriptor->Ports[i].ScalePointCount >= 2)
1190                     pData->param.data[j].hints |= PARAMETER_USES_SCALEPOINTS;
1191 
1192                 pData->param.ranges[j].min = min;
1193                 pData->param.ranges[j].max = max;
1194                 pData->param.ranges[j].def = def;
1195                 pData->param.ranges[j].step = step;
1196                 pData->param.ranges[j].stepSmall = stepSmall;
1197                 pData->param.ranges[j].stepLarge = stepLarge;
1198 
1199                 // Start parameters in their default values
1200                 fParamBuffers[j] = def;
1201 
1202                 for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
1203                 {
1204                     LADSPA_Handle const handle(it.getValue(nullptr));
1205                     CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
1206 
1207                     try {
1208                         fDescriptor->connect_port(handle, i, &fParamBuffers[j]);
1209                     } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (parameter)");
1210                 }
1211             }
1212             else
1213             {
1214                 // Not Audio or Control
1215                 carla_stderr2("ERROR - Got a broken Port (neither Audio or Control)");
1216 
1217                 for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
1218                 {
1219                     LADSPA_Handle const handle(it.getValue(nullptr));
1220                     CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
1221 
1222                     try {
1223                         fDescriptor->connect_port(handle, i, nullptr);
1224                     } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (null)");
1225                 }
1226             }
1227         }
1228 
1229         if (needsCtrlIn)
1230         {
1231             portName.clear();
1232 
1233             if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1234             {
1235                 portName  = pData->name;
1236                 portName += ":";
1237             }
1238 
1239             portName += "events-in";
1240             portName.truncate(portNameSize);
1241 
1242             pData->event.portIn = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, true, 0);
1243 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1244             pData->event.cvSourcePorts = pData->client->createCVSourcePorts();
1245 #endif
1246         }
1247 
1248         if (needsCtrlOut)
1249         {
1250             portName.clear();
1251 
1252             if (processMode == ENGINE_PROCESS_MODE_SINGLE_CLIENT)
1253             {
1254                 portName  = pData->name;
1255                 portName += ":";
1256             }
1257 
1258             portName += "events-out";
1259             portName.truncate(portNameSize);
1260 
1261             pData->event.portOut = (CarlaEngineEventPort*)pData->client->addPort(kEnginePortTypeEvent, portName, false, 0);
1262         }
1263 
1264         if (forcedStereoIn || forcedStereoOut)
1265             pData->options |= PLUGIN_OPTION_FORCE_STEREO;
1266         else
1267             pData->options &= ~PLUGIN_OPTION_FORCE_STEREO;
1268 
1269         // plugin hints
1270         pData->hints = 0x0;
1271 
1272         if (LADSPA_IS_HARD_RT_CAPABLE(fDescriptor->Properties))
1273             pData->hints |= PLUGIN_IS_RTSAFE;
1274 
1275 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
1276         if (fUiFilename != nullptr)
1277             pData->hints |= PLUGIN_HAS_CUSTOM_UI;
1278 #endif
1279 
1280 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1281         if (aOuts > 0 && (aIns == aOuts || aIns == 1))
1282             pData->hints |= PLUGIN_CAN_DRYWET;
1283 
1284         if (aOuts > 0)
1285             pData->hints |= PLUGIN_CAN_VOLUME;
1286 
1287         if (aOuts >= 2 && aOuts % 2 == 0)
1288             pData->hints |= PLUGIN_CAN_BALANCE;
1289 #endif
1290 
1291         // extra plugin hints
1292         pData->extraHints = 0x0;
1293 
1294         if (mIns > 0)
1295             pData->extraHints |= PLUGIN_EXTRA_HINT_HAS_MIDI_IN;
1296 
1297         // check initial latency
1298         findInitialLatencyValue(aIns, aOuts);
1299 
1300         fForcedStereoIn  = forcedStereoIn;
1301         fForcedStereoOut = forcedStereoOut;
1302 
1303         bufferSizeChanged(pData->engine->getBufferSize());
1304         reloadPrograms(true);
1305 
1306         if (pData->active)
1307             activate();
1308 
1309         carla_debug("CarlaPluginLADSPADSSI::reload() - end");
1310     }
1311 
findInitialLatencyValue(const uint32_t aIns,const uint32_t aOuts) const1312     void findInitialLatencyValue(const uint32_t aIns, const uint32_t aOuts) const
1313     {
1314         if (fLatencyIndex < 0 || fHandles.count() == 0)
1315             return;
1316 
1317         // we need to pre-run the plugin so it can update its latency control-port
1318         const LADSPA_Handle handle(fHandles.getFirst(nullptr));
1319         CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1320 
1321         float tmpIn [(aIns > 0)  ? aIns  : 1][2];
1322         float tmpOut[(aOuts > 0) ? aOuts : 1][2];
1323 
1324         for (uint32_t j=0; j < aIns; ++j)
1325         {
1326             tmpIn[j][0] = 0.0f;
1327             tmpIn[j][1] = 0.0f;
1328 
1329             try {
1330                 fDescriptor->connect_port(handle, pData->audioIn.ports[j].rindex, tmpIn[j]);
1331             } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (latency input)");
1332         }
1333 
1334         for (uint32_t j=0; j < aOuts; ++j)
1335         {
1336             tmpOut[j][0] = 0.0f;
1337             tmpOut[j][1] = 0.0f;
1338 
1339             try {
1340                 fDescriptor->connect_port(handle, pData->audioOut.ports[j].rindex, tmpOut[j]);
1341             } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (latency output)");
1342         }
1343 
1344         if (fDescriptor->activate != nullptr)
1345         {
1346             try {
1347                 fDescriptor->activate(handle);
1348             } CARLA_SAFE_EXCEPTION("LADSPA/DSSI latency activate");
1349         }
1350 
1351         try {
1352             fDescriptor->run(handle, 2);
1353         } CARLA_SAFE_EXCEPTION("LADSPA/DSSI latency run");
1354 
1355         if (fDescriptor->deactivate != nullptr)
1356         {
1357             try {
1358                 fDescriptor->deactivate(handle);
1359             } CARLA_SAFE_EXCEPTION("LADSPA/DSSI latency deactivate");
1360         }
1361 
1362         // done, let's get the value
1363         if (const uint32_t latency = getLatencyInFrames())
1364         {
1365             pData->client->setLatency(latency);
1366 #ifndef BUILD_BRIDGE
1367             pData->latency.recreateBuffers(std::max(aIns, aOuts), latency);
1368 #endif
1369         }
1370     }
1371 
reloadPrograms(const bool doInit)1372     void reloadPrograms(const bool doInit) override
1373     {
1374         carla_debug("CarlaPluginLADSPADSSI::reloadPrograms(%s)", bool2str(doInit));
1375 
1376         const LADSPA_Handle handle(fHandles.getFirst(nullptr));
1377         CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1378 
1379         const uint32_t oldCount = pData->midiprog.count;
1380         const int32_t  current  = pData->midiprog.current;
1381 
1382         // Delete old programs
1383         pData->midiprog.clear();
1384 
1385         // nothing to do for simple LADSPA plugins (do we want to bother with lrdf presets?)
1386         if (fDssiDescriptor == nullptr)
1387             return;
1388 
1389         // Query new programs
1390         uint32_t newCount = 0;
1391         if (fDssiDescriptor->get_program != nullptr && fDssiDescriptor->select_program != nullptr)
1392         {
1393             for (; fDssiDescriptor->get_program(handle, newCount) != nullptr;)
1394                 ++newCount;
1395         }
1396 
1397         if (newCount > 0)
1398         {
1399             pData->midiprog.createNew(newCount);
1400 
1401             // Update data
1402             for (uint32_t i=0; i < newCount; ++i)
1403             {
1404                 const DSSI_Program_Descriptor* const pdesc(fDssiDescriptor->get_program(handle, i));
1405                 CARLA_SAFE_ASSERT_CONTINUE(pdesc != nullptr);
1406                 CARLA_SAFE_ASSERT(pdesc->Name != nullptr);
1407 
1408                 pData->midiprog.data[i].bank    = static_cast<uint32_t>(pdesc->Bank);
1409                 pData->midiprog.data[i].program = static_cast<uint32_t>(pdesc->Program);
1410                 pData->midiprog.data[i].name    = carla_strdup(pdesc->Name);
1411             }
1412         }
1413 
1414         if (doInit)
1415         {
1416             if (newCount > 0)
1417                 setMidiProgram(0, false, false, false, true);
1418         }
1419         else
1420         {
1421             // Check if current program is invalid
1422             bool programChanged = false;
1423 
1424             if (newCount == oldCount+1)
1425             {
1426                 // one midi program added, probably created by user
1427                 pData->midiprog.current = static_cast<int32_t>(oldCount);
1428                 programChanged = true;
1429             }
1430             else if (current < 0 && newCount > 0)
1431             {
1432                 // programs exist now, but not before
1433                 pData->midiprog.current = 0;
1434                 programChanged = true;
1435             }
1436             else if (current >= 0 && newCount == 0)
1437             {
1438                 // programs existed before, but not anymore
1439                 pData->midiprog.current = -1;
1440                 programChanged = true;
1441             }
1442             else if (current >= static_cast<int32_t>(newCount))
1443             {
1444                 // current midi program > count
1445                 pData->midiprog.current = 0;
1446                 programChanged = true;
1447             }
1448             else
1449             {
1450                 // no change
1451                 pData->midiprog.current = current;
1452             }
1453 
1454             if (programChanged)
1455                 setMidiProgram(pData->midiprog.current, true, true, true, false);
1456 
1457             pData->engine->callback(true, true, ENGINE_CALLBACK_RELOAD_PROGRAMS, pData->id, 0, 0, 0, 0.0f, nullptr);
1458         }
1459     }
1460 
1461     // -------------------------------------------------------------------
1462     // Plugin processing
1463 
activate()1464     void activate() noexcept override
1465     {
1466         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
1467 
1468         if (fDescriptor->activate != nullptr)
1469         {
1470             for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
1471             {
1472                 LADSPA_Handle const handle(it.getValue(nullptr));
1473                 CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
1474 
1475                 try {
1476                     fDescriptor->activate(handle);
1477                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI activate");
1478             }
1479         }
1480     }
1481 
deactivate()1482     void deactivate() noexcept override
1483     {
1484         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
1485 
1486         if (fDescriptor->deactivate != nullptr)
1487         {
1488             for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
1489             {
1490                 LADSPA_Handle const handle(it.getValue(nullptr));
1491                 CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
1492 
1493                 try {
1494                     fDescriptor->deactivate(handle);
1495                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI deactivate");
1496             }
1497         }
1498     }
1499 
process(const float * const * const audioIn,float ** const audioOut,const float * const * const cvIn,float **,const uint32_t frames)1500     void process(const float* const* const audioIn, float** const audioOut,
1501                  const float* const* const cvIn, float**,
1502                  const uint32_t frames) override
1503     {
1504         // --------------------------------------------------------------------------------------------------------
1505         // Check if active
1506 
1507         if (! pData->active)
1508         {
1509             // disable any output sound
1510             for (uint32_t i=0; i < pData->audioOut.count; ++i)
1511                 carla_zeroFloats(audioOut[i], frames);
1512             return;
1513         }
1514 
1515         ulong midiEventCount = 0;
1516         carla_zeroStructs(fMidiEvents, kPluginMaxMidiEvents);
1517 
1518         // --------------------------------------------------------------------------------------------------------
1519         // Check if needs reset
1520 
1521         if (pData->needsReset)
1522         {
1523             if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
1524             {
1525                 midiEventCount = MAX_MIDI_CHANNELS*2;
1526 
1527                 for (uchar i=0, k=MAX_MIDI_CHANNELS; i < MAX_MIDI_CHANNELS; ++i)
1528                 {
1529                     fMidiEvents[i].type = SND_SEQ_EVENT_CONTROLLER;
1530                     fMidiEvents[i].data.control.channel = i;
1531                     fMidiEvents[i].data.control.param   = MIDI_CONTROL_ALL_NOTES_OFF;
1532 
1533                     fMidiEvents[k+i].type = SND_SEQ_EVENT_CONTROLLER;
1534                     fMidiEvents[k+i].data.control.channel = i;
1535                     fMidiEvents[k+i].data.control.param   = MIDI_CONTROL_ALL_SOUND_OFF;
1536                 }
1537             }
1538             else if (pData->ctrlChannel >= 0 && pData->ctrlChannel < MAX_MIDI_CHANNELS)
1539             {
1540                 midiEventCount = MAX_MIDI_NOTE;
1541 
1542                 for (uchar i=0; i < MAX_MIDI_NOTE; ++i)
1543                 {
1544                     fMidiEvents[i].type = SND_SEQ_EVENT_NOTEOFF;
1545                     fMidiEvents[i].data.note.channel = static_cast<uchar>(pData->ctrlChannel);
1546                     fMidiEvents[i].data.note.note    = i;
1547                 }
1548             }
1549 
1550             pData->needsReset = false;
1551         }
1552 
1553         // --------------------------------------------------------------------------------------------------------
1554         // Event Input and Processing
1555 
1556         if (pData->event.portIn != nullptr)
1557         {
1558             // ----------------------------------------------------------------------------------------------------
1559             // MIDI Input (External)
1560 
1561             if (pData->extNotes.mutex.tryLock())
1562             {
1563                 ExternalMidiNote note = { 0, 0, 0 };
1564 
1565                 for (; midiEventCount < kPluginMaxMidiEvents && ! pData->extNotes.data.isEmpty();)
1566                 {
1567                     note = pData->extNotes.data.getFirst(note, true);
1568                     CARLA_SAFE_ASSERT_CONTINUE(note.channel >= 0 && note.channel < MAX_MIDI_CHANNELS);
1569 
1570                     snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
1571 
1572                     seqEvent.type               = (note.velo > 0) ? SND_SEQ_EVENT_NOTEON : SND_SEQ_EVENT_NOTEOFF;
1573                     seqEvent.data.note.channel  = static_cast<uchar>(note.channel);
1574                     seqEvent.data.note.note     = note.note;
1575                     seqEvent.data.note.velocity = note.velo;
1576                 }
1577 
1578                 pData->extNotes.mutex.unlock();
1579 
1580             } // End of MIDI Input (External)
1581 
1582             // ----------------------------------------------------------------------------------------------------
1583             // Event Input (System)
1584 
1585 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1586             bool allNotesOffSent = false;
1587 #endif
1588             const bool isSampleAccurate = (pData->options & PLUGIN_OPTION_FIXED_BUFFERS) == 0;
1589 
1590             uint32_t startTime  = 0;
1591             uint32_t timeOffset = 0;
1592             uint32_t nextBankId;
1593 
1594             if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
1595                 nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
1596             else
1597                 nextBankId = 0;
1598 
1599 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1600             if (cvIn != nullptr && pData->event.cvSourcePorts != nullptr)
1601                 pData->event.cvSourcePorts->initPortBuffers(cvIn, frames, isSampleAccurate, pData->event.portIn);
1602 #endif
1603 
1604             for (uint32_t i=0, numEvents=pData->event.portIn->getEventCount(); i < numEvents; ++i)
1605             {
1606                 EngineEvent& event(pData->event.portIn->getEvent(i));
1607 
1608                 uint32_t eventTime = event.time;
1609                 CARLA_SAFE_ASSERT_UINT2_CONTINUE(eventTime < frames, eventTime, frames);
1610 
1611                 if (eventTime < timeOffset)
1612                 {
1613                     carla_stderr2("Timing error, eventTime:%u < timeOffset:%u for '%s'",
1614                                   eventTime, timeOffset, pData->name);
1615                     eventTime = timeOffset;
1616                 }
1617 
1618                 if (isSampleAccurate && eventTime > timeOffset)
1619                 {
1620                     if (processSingle(audioIn, audioOut, eventTime - timeOffset, timeOffset, midiEventCount))
1621                     {
1622                         startTime  = 0;
1623                         timeOffset = eventTime;
1624                         midiEventCount = 0;
1625 
1626                         if (pData->midiprog.current >= 0 && pData->midiprog.count > 0)
1627                             nextBankId = pData->midiprog.data[pData->midiprog.current].bank;
1628                         else
1629                             nextBankId = 0;
1630                     }
1631                     else
1632                         startTime += timeOffset;
1633                 }
1634 
1635                 switch (event.type)
1636                 {
1637                 case kEngineEventTypeNull:
1638                     break;
1639 
1640                 case kEngineEventTypeControl: {
1641                     EngineControlEvent& ctrlEvent(event.ctrl);
1642 
1643                     switch (ctrlEvent.type)
1644                     {
1645                     case kEngineControlEventTypeNull:
1646                         break;
1647 
1648                     case kEngineControlEventTypeParameter: {
1649                         float value;
1650 
1651 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1652                         // non-midi
1653                         if (event.channel == kEngineEventNonMidiChannel)
1654                         {
1655                             const uint32_t k = ctrlEvent.param;
1656                             CARLA_SAFE_ASSERT_CONTINUE(k < pData->param.count);
1657 
1658                             ctrlEvent.handled = true;
1659                             value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
1660                             setParameterValueRT(k, value, true);
1661                             continue;
1662                         }
1663 
1664                         // Control backend stuff
1665                         if (event.channel == pData->ctrlChannel)
1666                         {
1667                             if (MIDI_IS_CONTROL_BREATH_CONTROLLER(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_DRYWET) != 0)
1668                             {
1669                                 ctrlEvent.handled = true;
1670                                 value = ctrlEvent.normalizedValue;
1671                                 setDryWetRT(value, true);
1672                             }
1673                             else if (MIDI_IS_CONTROL_CHANNEL_VOLUME(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_VOLUME) != 0)
1674                             {
1675                                 ctrlEvent.handled = true;
1676                                 value = ctrlEvent.normalizedValue*127.0f/100.0f;
1677                                 setVolumeRT(value, true);
1678                             }
1679                             else if (MIDI_IS_CONTROL_BALANCE(ctrlEvent.param) && (pData->hints & PLUGIN_CAN_BALANCE) != 0)
1680                             {
1681                                 float left, right;
1682                                 value = ctrlEvent.normalizedValue/0.5f - 1.0f;
1683 
1684                                 if (value < 0.0f)
1685                                 {
1686                                     left  = -1.0f;
1687                                     right = (value*2.0f)+1.0f;
1688                                 }
1689                                 else if (value > 0.0f)
1690                                 {
1691                                     left  = (value*2.0f)-1.0f;
1692                                     right = 1.0f;
1693                                 }
1694                                 else
1695                                 {
1696                                     left  = -1.0f;
1697                                     right = 1.0f;
1698                                 }
1699 
1700                                 ctrlEvent.handled = true;
1701                                 setBalanceLeftRT(left, true);
1702                                 setBalanceRightRT(right, true);
1703                             }
1704                         }
1705 #endif
1706                         // Control plugin parameters
1707                         for (uint32_t k=0; k < pData->param.count; ++k)
1708                         {
1709                             if (pData->param.data[k].midiChannel != event.channel)
1710                                 continue;
1711                             if (pData->param.data[k].mappedControlIndex != ctrlEvent.param)
1712                                 continue;
1713                             if (pData->param.data[k].type != PARAMETER_INPUT)
1714                                 continue;
1715                             if ((pData->param.data[k].hints & PARAMETER_IS_AUTOMABLE) == 0)
1716                                 continue;
1717 
1718                             ctrlEvent.handled = true;
1719                             value = pData->param.getFinalUnnormalizedValue(k, ctrlEvent.normalizedValue);
1720                             setParameterValueRT(k, value, true);
1721                         }
1722 
1723                         if ((pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES) != 0 && ctrlEvent.param < MAX_MIDI_VALUE)
1724                         {
1725                             if (midiEventCount >= kPluginMaxMidiEvents)
1726                                 continue;
1727 
1728                             snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
1729 
1730                             seqEvent.time.tick = isSampleAccurate ? startTime : eventTime;
1731 
1732                             seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
1733                             seqEvent.data.control.channel = event.channel;
1734                             seqEvent.data.control.param   = ctrlEvent.param;
1735                             seqEvent.data.control.value   = int8_t(ctrlEvent.normalizedValue*127.0f);
1736                         }
1737 
1738 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1739                         if (! ctrlEvent.handled)
1740                             checkForMidiLearn(event);
1741 #endif
1742                         break;
1743                     } // case kEngineControlEventTypeParameter
1744 
1745                     case kEngineControlEventTypeMidiBank:
1746                         if (event.channel == pData->ctrlChannel && (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0)
1747                             nextBankId = ctrlEvent.param;
1748                         break;
1749 
1750                     case kEngineControlEventTypeMidiProgram:
1751                         if (event.channel == pData->ctrlChannel && (pData->options & PLUGIN_OPTION_MAP_PROGRAM_CHANGES) != 0)
1752                         {
1753                             const uint32_t nextProgramId = ctrlEvent.param;
1754 
1755                             for (uint32_t k=0; k < pData->midiprog.count; ++k)
1756                             {
1757                                 if (pData->midiprog.data[k].bank == nextBankId && pData->midiprog.data[k].program == nextProgramId)
1758                                 {
1759                                     setMidiProgramRT(k, true);
1760                                     break;
1761                                 }
1762                             }
1763                         }
1764                         break;
1765 
1766                     case kEngineControlEventTypeAllSoundOff:
1767                         if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
1768                         {
1769                             if (midiEventCount >= kPluginMaxMidiEvents)
1770                                 continue;
1771 
1772                             snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
1773 
1774                             seqEvent.time.tick = isSampleAccurate ? startTime : eventTime;
1775 
1776                             seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
1777                             seqEvent.data.control.channel = event.channel;
1778                             seqEvent.data.control.param   = MIDI_CONTROL_ALL_SOUND_OFF;
1779                         }
1780                         break;
1781 
1782                     case kEngineControlEventTypeAllNotesOff:
1783                         if (pData->options & PLUGIN_OPTION_SEND_ALL_SOUND_OFF)
1784                         {
1785 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
1786                             if (event.channel == pData->ctrlChannel && ! allNotesOffSent)
1787                             {
1788                                 allNotesOffSent = true;
1789                                 postponeRtAllNotesOff();
1790                             }
1791 #endif
1792 
1793                             if (midiEventCount >= kPluginMaxMidiEvents)
1794                                 continue;
1795 
1796                             snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
1797 
1798                             seqEvent.time.tick = isSampleAccurate ? startTime : eventTime;
1799 
1800                             seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
1801                             seqEvent.data.control.channel = event.channel;
1802                             seqEvent.data.control.param   = MIDI_CONTROL_ALL_NOTES_OFF;
1803                         }
1804                         break;
1805                     } // switch (ctrlEvent.type)
1806                     break;
1807                 } // case kEngineEventTypeControl
1808 
1809                 case kEngineEventTypeMidi: {
1810                     if (midiEventCount >= kPluginMaxMidiEvents)
1811                         continue;
1812 
1813                     const EngineMidiEvent& midiEvent(event.midi);
1814 
1815                     if (midiEvent.size > EngineMidiEvent::kDataSize)
1816                         continue;
1817 
1818                     uint8_t status = uint8_t(MIDI_GET_STATUS_FROM_DATA(midiEvent.data));
1819 
1820                     // Fix bad note-off (per DSSI spec)
1821                     if (status == MIDI_STATUS_NOTE_ON && midiEvent.data[2] == 0)
1822                         status = MIDI_STATUS_NOTE_OFF;
1823 
1824                     snd_seq_event_t& seqEvent(fMidiEvents[midiEventCount++]);
1825 
1826                     seqEvent.time.tick = isSampleAccurate ? startTime : eventTime;
1827 
1828                     switch (status)
1829                     {
1830                     case MIDI_STATUS_NOTE_OFF:
1831                         if ((pData->options & PLUGIN_OPTION_SKIP_SENDING_NOTES) == 0x0)
1832                         {
1833                             const uint8_t note = midiEvent.data[1];
1834 
1835                             seqEvent.type = SND_SEQ_EVENT_NOTEOFF;
1836                             seqEvent.data.note.channel = event.channel;
1837                             seqEvent.data.note.note    = note;
1838 
1839                             pData->postponeNoteOffRtEvent(true, event.channel, note);
1840                         }
1841                         break;
1842 
1843                     case MIDI_STATUS_NOTE_ON:
1844                         if ((pData->options & PLUGIN_OPTION_SKIP_SENDING_NOTES) == 0x0)
1845                         {
1846                             const uint8_t note = midiEvent.data[1];
1847                             const uint8_t velo = midiEvent.data[2];
1848 
1849                             seqEvent.type = SND_SEQ_EVENT_NOTEON;
1850                             seqEvent.data.note.channel  = event.channel;
1851                             seqEvent.data.note.note     = note;
1852                             seqEvent.data.note.velocity = velo;
1853 
1854                             pData->postponeNoteOnRtEvent(true, event.channel, note, velo);
1855                         }
1856                         break;
1857 
1858                     case MIDI_STATUS_POLYPHONIC_AFTERTOUCH:
1859                         if (pData->options & PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH)
1860                         {
1861                             const uint8_t note     = midiEvent.data[1];
1862                             const uint8_t pressure = midiEvent.data[2];
1863 
1864                             seqEvent.type = SND_SEQ_EVENT_KEYPRESS;
1865                             seqEvent.data.note.channel  = event.channel;
1866                             seqEvent.data.note.note     = note;
1867                             seqEvent.data.note.velocity = pressure;
1868                         }
1869                         break;
1870 
1871                     case MIDI_STATUS_CONTROL_CHANGE:
1872                         if (pData->options & PLUGIN_OPTION_SEND_CONTROL_CHANGES)
1873                         {
1874                             const uint8_t control = midiEvent.data[1];
1875                             const uint8_t value   = midiEvent.data[2];
1876 
1877                             seqEvent.type = SND_SEQ_EVENT_CONTROLLER;
1878                             seqEvent.data.control.channel = event.channel;
1879                             seqEvent.data.control.param   = control;
1880                             seqEvent.data.control.value   = value;
1881                         }
1882                         break;
1883 
1884                     case MIDI_STATUS_CHANNEL_PRESSURE:
1885                         if (pData->options & PLUGIN_OPTION_SEND_CHANNEL_PRESSURE)
1886                         {
1887                             const uint8_t pressure = midiEvent.data[1];
1888 
1889                             seqEvent.type = SND_SEQ_EVENT_CHANPRESS;
1890                             seqEvent.data.control.channel = event.channel;
1891                             seqEvent.data.control.value   = pressure;
1892                         }
1893                         break;
1894 
1895                     case MIDI_STATUS_PITCH_WHEEL_CONTROL:
1896                         if (pData->options & PLUGIN_OPTION_SEND_PITCHBEND)
1897                         {
1898                             const uint8_t lsb = midiEvent.data[1];
1899                             const uint8_t msb = midiEvent.data[2];
1900 
1901                             seqEvent.type = SND_SEQ_EVENT_PITCHBEND;
1902                             seqEvent.data.control.channel = event.channel;
1903                             seqEvent.data.control.value   = ((msb << 7) | lsb) - 8192;
1904                         }
1905                         break;
1906 
1907                     default:
1908                         --midiEventCount;
1909                         break;
1910                     } // switch (status)
1911                 } break;
1912                 } // switch (event.type)
1913             }
1914 
1915             pData->postRtEvents.trySplice();
1916 
1917             if (frames > timeOffset)
1918                 processSingle(audioIn, audioOut, frames - timeOffset, timeOffset, midiEventCount);
1919 
1920         } // End of Event Input and Processing
1921 
1922         // --------------------------------------------------------------------------------------------------------
1923         // Plugin processing (no events)
1924 
1925         else
1926         {
1927             processSingle(audioIn, audioOut, frames, 0, midiEventCount);
1928 
1929         } // End of Plugin processing (no events)
1930 
1931         // --------------------------------------------------------------------------------------------------------
1932         // Control Output
1933 
1934         if (pData->event.portOut != nullptr)
1935         {
1936             uint8_t  channel;
1937             uint16_t param;
1938             float    value;
1939 
1940             for (uint32_t k=0; k < pData->param.count; ++k)
1941             {
1942                 if (pData->param.data[k].type != PARAMETER_OUTPUT)
1943                     continue;
1944 
1945                 pData->param.ranges[k].fixValue(fParamBuffers[k]);
1946 
1947                 if (pData->param.data[k].mappedControlIndex > 0)
1948                 {
1949                     channel = pData->param.data[k].midiChannel;
1950                     param   = static_cast<uint16_t>(pData->param.data[k].mappedControlIndex);
1951                     value   = pData->param.ranges[k].getNormalizedValue(fParamBuffers[k]);
1952                     pData->event.portOut->writeControlEvent(0, channel, kEngineControlEventTypeParameter,
1953                                                             param, -1, value);
1954                 }
1955             }
1956         } // End of Control Output
1957 
1958 #ifdef BUILD_BRIDGE_ALTERNATIVE_ARCH
1959         return;
1960 
1961         // unused
1962         (void)cvIn;
1963 #endif
1964     }
1965 
processSingle(const float * const * const audioIn,float ** const audioOut,const uint32_t frames,const uint32_t timeOffset,const ulong midiEventCount)1966     bool processSingle(const float* const* const audioIn, float** const audioOut, const uint32_t frames,
1967                        const uint32_t timeOffset, const ulong midiEventCount)
1968     {
1969         CARLA_SAFE_ASSERT_RETURN(frames > 0, false);
1970 
1971         if (pData->audioIn.count > 0)
1972         {
1973             CARLA_SAFE_ASSERT_RETURN(audioIn != nullptr, false);
1974         }
1975         if (pData->audioOut.count > 0)
1976         {
1977             CARLA_SAFE_ASSERT_RETURN(audioOut != nullptr, false);
1978         }
1979 
1980         // --------------------------------------------------------------------------------------------------------
1981         // Try lock, silence otherwise
1982 
1983 #ifndef STOAT_TEST_BUILD
1984         if (pData->engine->isOffline())
1985         {
1986             pData->singleMutex.lock();
1987         }
1988         else
1989 #endif
1990         if (! pData->singleMutex.tryLock())
1991         {
1992             for (uint32_t i=0; i < pData->audioOut.count; ++i)
1993             {
1994                 for (uint32_t k=0; k < frames; ++k)
1995                     audioOut[i][k+timeOffset] = 0.0f;
1996             }
1997 
1998             return false;
1999         }
2000 
2001         // --------------------------------------------------------------------------------------------------------
2002         // Set audio buffers
2003 
2004         const bool customMonoOut   = pData->audioOut.count == 2 && fForcedStereoOut && ! fForcedStereoIn;
2005         const bool customStereoOut = pData->audioOut.count == 2 && fForcedStereoIn  && ! fForcedStereoOut;
2006 
2007         if (! customMonoOut)
2008         {
2009             for (uint32_t i=0; i < pData->audioOut.count; ++i)
2010                 carla_zeroFloats(fAudioOutBuffers[i], frames);
2011         }
2012 
2013         for (uint32_t i=0; i < pData->audioIn.count; ++i)
2014             carla_copyFloats(fAudioInBuffers[i], audioIn[i]+timeOffset, frames);
2015 
2016         // --------------------------------------------------------------------------------------------------------
2017         // Run plugin
2018 
2019         uint instn = 0;
2020         for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next(), ++instn)
2021         {
2022             LADSPA_Handle const handle(it.getValue(nullptr));
2023             CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
2024 
2025             // ----------------------------------------------------------------------------------------------------
2026             // Mixdown for forced stereo
2027 
2028             if (customMonoOut)
2029                 carla_zeroFloats(fAudioOutBuffers[instn], frames);
2030 
2031             // ----------------------------------------------------------------------------------------------------
2032             // Run it
2033 
2034             if (fDssiDescriptor != nullptr && fDssiDescriptor->run_synth != nullptr)
2035             {
2036                 try {
2037                     fDssiDescriptor->run_synth(handle, frames, fMidiEvents, midiEventCount);
2038                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI run_synth");
2039             }
2040             else
2041             {
2042                 try {
2043                     fDescriptor->run(handle, frames);
2044                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI run");
2045             }
2046 
2047             // ----------------------------------------------------------------------------------------------------
2048             // Mixdown for forced stereo
2049 
2050             if (customMonoOut)
2051                 carla_multiply(fAudioOutBuffers[instn], 0.5f, frames);
2052             else if (customStereoOut)
2053                 carla_copyFloats(fExtraStereoBuffer[instn], fAudioOutBuffers[instn], frames);
2054         }
2055 
2056         if (customStereoOut)
2057         {
2058             carla_copyFloats(fAudioOutBuffers[0], fExtraStereoBuffer[0], frames);
2059             carla_copyFloats(fAudioOutBuffers[1], fExtraStereoBuffer[1], frames);
2060         }
2061 
2062 #ifndef BUILD_BRIDGE_ALTERNATIVE_ARCH
2063         // --------------------------------------------------------------------------------------------------------
2064         // Post-processing (dry/wet, volume and balance)
2065 
2066         {
2067             const bool doDryWet  = (pData->hints & PLUGIN_CAN_DRYWET) != 0 && carla_isNotEqual(pData->postProc.dryWet, 1.0f);
2068             const bool doBalance = (pData->hints & PLUGIN_CAN_BALANCE) != 0 && ! (carla_isEqual(pData->postProc.balanceLeft, -1.0f) && carla_isEqual(pData->postProc.balanceRight, 1.0f));
2069             const bool isMono    = (pData->audioIn.count == 1);
2070 
2071             bool isPair;
2072             float bufValue, oldBufLeft[doBalance ? frames : 1];
2073 
2074             for (uint32_t i=0; i < pData->audioOut.count; ++i)
2075             {
2076                 // Dry/Wet
2077                 if (doDryWet)
2078                 {
2079                     const uint32_t c = isMono ? 0 : i;
2080 
2081                     for (uint32_t k=0; k < frames; ++k)
2082                     {
2083 # ifndef BUILD_BRIDGE
2084                         if (k < pData->latency.frames && pData->latency.buffers != nullptr)
2085                             bufValue = pData->latency.buffers[c][k];
2086                         else if (pData->latency.frames < frames)
2087                             bufValue = fAudioInBuffers[c][k-pData->latency.frames];
2088                         else
2089 # endif
2090                             bufValue = fAudioInBuffers[c][k];
2091 
2092                         fAudioOutBuffers[i][k] = (fAudioOutBuffers[i][k] * pData->postProc.dryWet) + (bufValue * (1.0f - pData->postProc.dryWet));
2093                     }
2094                 }
2095 
2096                 // Balance
2097                 if (doBalance)
2098                 {
2099                     isPair = (i % 2 == 0);
2100 
2101                     if (isPair)
2102                     {
2103                         CARLA_ASSERT(i+1 < pData->audioOut.count);
2104                         carla_copyFloats(oldBufLeft, fAudioOutBuffers[i], frames);
2105                     }
2106 
2107                     float balRangeL = (pData->postProc.balanceLeft  + 1.0f)/2.0f;
2108                     float balRangeR = (pData->postProc.balanceRight + 1.0f)/2.0f;
2109 
2110                     for (uint32_t k=0; k < frames; ++k)
2111                     {
2112                         if (isPair)
2113                         {
2114                             // left
2115                             fAudioOutBuffers[i][k]  = oldBufLeft[k]            * (1.0f - balRangeL);
2116                             fAudioOutBuffers[i][k] += fAudioOutBuffers[i+1][k] * (1.0f - balRangeR);
2117                         }
2118                         else
2119                         {
2120                             // right
2121                             fAudioOutBuffers[i][k]  = fAudioOutBuffers[i][k] * balRangeR;
2122                             fAudioOutBuffers[i][k] += oldBufLeft[k]          * balRangeL;
2123                         }
2124                     }
2125                 }
2126 
2127                 // Volume (and buffer copy)
2128                 {
2129                     for (uint32_t k=0; k < frames; ++k)
2130                         audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k] * pData->postProc.volume;
2131                 }
2132             }
2133 
2134         } // End of Post-processing
2135 
2136 # ifndef BUILD_BRIDGE
2137         // --------------------------------------------------------------------------------------------------------
2138         // Save latency values for next callback
2139 
2140         if (pData->latency.frames != 0 && pData->latency.buffers != nullptr)
2141         {
2142             CARLA_SAFE_ASSERT(timeOffset == 0);
2143             const uint32_t latframes = pData->latency.frames;
2144 
2145             if (latframes <= frames)
2146             {
2147                 for (uint32_t i=0; i < pData->audioIn.count; ++i)
2148                     carla_copyFloats(pData->latency.buffers[i], audioIn[i]+(frames-latframes), latframes);
2149             }
2150             else
2151             {
2152                 const uint32_t diff = latframes - frames;
2153 
2154                 for (uint32_t i=0, k; i<pData->audioIn.count; ++i)
2155                 {
2156                     // push back buffer by 'frames'
2157                     for (k=0; k < diff; ++k)
2158                         pData->latency.buffers[i][k] = pData->latency.buffers[i][k+frames];
2159 
2160                     // put current input at the end
2161                     for (uint32_t j=0; k < latframes; ++j, ++k)
2162                         pData->latency.buffers[i][k] = audioIn[i][j];
2163                 }
2164             }
2165         }
2166 # endif
2167 #else // BUILD_BRIDGE_ALTERNATIVE_ARCH
2168         for (uint32_t i=0; i < pData->audioOut.count; ++i)
2169         {
2170             for (uint32_t k=0; k < frames; ++k)
2171                 audioOut[i][k+timeOffset] = fAudioOutBuffers[i][k];
2172         }
2173 #endif
2174 
2175         // --------------------------------------------------------------------------------------------------------
2176 
2177         pData->singleMutex.unlock();
2178         return true;
2179     }
2180 
bufferSizeChanged(const uint32_t newBufferSize)2181     void bufferSizeChanged(const uint32_t newBufferSize) override
2182     {
2183         CARLA_ASSERT_INT(newBufferSize > 0, newBufferSize);
2184         carla_debug("CarlaPluginLADSPADSSI::bufferSizeChanged(%i) - start", newBufferSize);
2185 
2186         for (uint32_t i=0; i < pData->audioIn.count; ++i)
2187         {
2188             if (fAudioInBuffers[i] != nullptr)
2189                 delete[] fAudioInBuffers[i];
2190 
2191             fAudioInBuffers[i] = new float[newBufferSize];
2192             carla_zeroFloats(fAudioInBuffers[i], newBufferSize);
2193         }
2194 
2195         for (uint32_t i=0; i < pData->audioOut.count; ++i)
2196         {
2197             if (fAudioOutBuffers[i] != nullptr)
2198                 delete[] fAudioOutBuffers[i];
2199 
2200             fAudioOutBuffers[i] = new float[newBufferSize];
2201             carla_zeroFloats(fAudioOutBuffers[i], newBufferSize);
2202         }
2203 
2204         if (fExtraStereoBuffer[0] != nullptr)
2205         {
2206             delete[] fExtraStereoBuffer[0];
2207             fExtraStereoBuffer[0] = nullptr;
2208         }
2209 
2210         if (fExtraStereoBuffer[1] != nullptr)
2211         {
2212             delete[] fExtraStereoBuffer[1];
2213             fExtraStereoBuffer[1] = nullptr;
2214         }
2215 
2216         if (fForcedStereoIn && pData->audioOut.count == 2)
2217         {
2218             fExtraStereoBuffer[0] = new float[newBufferSize];
2219             fExtraStereoBuffer[1] = new float[newBufferSize];
2220             carla_zeroFloats(fExtraStereoBuffer[0], newBufferSize);
2221             carla_zeroFloats(fExtraStereoBuffer[1], newBufferSize);
2222         }
2223 
2224         reconnectAudioPorts();
2225 
2226         carla_debug("CarlaPluginLADSPADSSI::bufferSizeChanged(%i) - end", newBufferSize);
2227     }
2228 
sampleRateChanged(const double newSampleRate)2229     void sampleRateChanged(const double newSampleRate) override
2230     {
2231         CARLA_ASSERT_INT(newSampleRate > 0.0, newSampleRate);
2232         carla_debug("CarlaPluginLADSPADSSI::sampleRateChanged(%g) - start", newSampleRate);
2233 
2234         // TODO - handle UI stuff
2235 
2236         if (pData->active)
2237             deactivate();
2238 
2239         const std::size_t instanceCount(fHandles.count());
2240 
2241         if (fDescriptor->cleanup != nullptr)
2242         {
2243             for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
2244             {
2245                 LADSPA_Handle const handle(it.getValue(nullptr));
2246                 CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
2247 
2248                 try {
2249                     fDescriptor->cleanup(handle);
2250                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI cleanup");
2251             }
2252         }
2253 
2254         fHandles.clear();
2255 
2256         for (std::size_t i=0; i<instanceCount; ++i)
2257             addInstance();
2258 
2259         reconnectAudioPorts();
2260 
2261         if (pData->active)
2262             activate();
2263 
2264         carla_debug("CarlaPluginLADSPADSSI::sampleRateChanged(%g) - end", newSampleRate);
2265     }
2266 
reconnectAudioPorts() const2267     void reconnectAudioPorts() const noexcept
2268     {
2269         if (fForcedStereoIn)
2270         {
2271             if (LADSPA_Handle const handle = fHandles.getFirst(nullptr))
2272             {
2273                 try {
2274                     fDescriptor->connect_port(handle, pData->audioIn.ports[0].rindex, fAudioInBuffers[0]);
2275                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (forced stereo input, first)");
2276             }
2277 
2278             if (LADSPA_Handle const handle = fHandles.getLast(nullptr))
2279             {
2280                 try {
2281                     fDescriptor->connect_port(handle, pData->audioIn.ports[1].rindex, fAudioInBuffers[1]);
2282                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (forced stereo input, last)");
2283             }
2284         }
2285         else
2286         {
2287             for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
2288             {
2289                 LADSPA_Handle const handle(it.getValue(nullptr));
2290                 CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
2291 
2292                 for (uint32_t i=0; i < pData->audioIn.count; ++i)
2293                 {
2294                     try {
2295                         fDescriptor->connect_port(handle, pData->audioIn.ports[i].rindex, fAudioInBuffers[i]);
2296                     } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (audio input)");
2297                 }
2298             }
2299         }
2300 
2301         if (fForcedStereoOut)
2302         {
2303             if (LADSPA_Handle const handle = fHandles.getFirst(nullptr))
2304             {
2305                 try {
2306                     fDescriptor->connect_port(handle, pData->audioOut.ports[0].rindex, fAudioOutBuffers[0]);
2307                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (forced stereo output, first)");
2308             }
2309 
2310             if (LADSPA_Handle const handle = fHandles.getLast(nullptr))
2311             {
2312                 try {
2313                     fDescriptor->connect_port(handle, pData->audioOut.ports[1].rindex, fAudioOutBuffers[1]);
2314                 } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (forced stereo output, last)");
2315             }
2316         }
2317         else
2318         {
2319             for (LinkedList<LADSPA_Handle>::Itenerator it = fHandles.begin2(); it.valid(); it.next())
2320             {
2321                 LADSPA_Handle const handle(it.getValue(nullptr));
2322                 CARLA_SAFE_ASSERT_CONTINUE(handle != nullptr);
2323 
2324                 for (uint32_t i=0; i < pData->audioOut.count; ++i)
2325                 {
2326                     try {
2327                         fDescriptor->connect_port(handle, pData->audioOut.ports[i].rindex, fAudioOutBuffers[i]);
2328                     } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port (audio output)");
2329                 }
2330             }
2331         }
2332     }
2333 
2334     // -------------------------------------------------------------------
2335     // Plugin buffers
2336 
clearBuffers()2337     void clearBuffers() noexcept override
2338     {
2339         carla_debug("CarlaPluginLADSPADSSI::clearBuffers() - start");
2340 
2341         if (fAudioInBuffers != nullptr)
2342         {
2343             for (uint32_t i=0; i < pData->audioIn.count; ++i)
2344             {
2345                 if (fAudioInBuffers[i] != nullptr)
2346                 {
2347                     delete[] fAudioInBuffers[i];
2348                     fAudioInBuffers[i] = nullptr;
2349                 }
2350             }
2351 
2352             delete[] fAudioInBuffers;
2353             fAudioInBuffers = nullptr;
2354         }
2355 
2356         if (fAudioOutBuffers != nullptr)
2357         {
2358             for (uint32_t i=0; i < pData->audioOut.count; ++i)
2359             {
2360                 if (fAudioOutBuffers[i] != nullptr)
2361                 {
2362                     delete[] fAudioOutBuffers[i];
2363                     fAudioOutBuffers[i] = nullptr;
2364                 }
2365             }
2366 
2367             delete[] fAudioOutBuffers;
2368             fAudioOutBuffers = nullptr;
2369         }
2370 
2371         if (fExtraStereoBuffer[0] != nullptr)
2372         {
2373             delete[] fExtraStereoBuffer[0];
2374             fExtraStereoBuffer[0] = nullptr;
2375         }
2376 
2377         if (fExtraStereoBuffer[1] != nullptr)
2378         {
2379             delete[] fExtraStereoBuffer[1];
2380             fExtraStereoBuffer[1] = nullptr;
2381         }
2382 
2383         if (fParamBuffers != nullptr)
2384         {
2385             delete[] fParamBuffers;
2386             fParamBuffers = nullptr;
2387         }
2388 
2389         CarlaPlugin::clearBuffers();
2390 
2391         carla_debug("CarlaPluginLADSPADSSI::clearBuffers() - end");
2392     }
2393 
2394 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
2395     // -------------------------------------------------------------------
2396     // OSC stuff
2397 
handleOscMessage(const char * const method,const int argc,const void * const argvx,const char * const types,const lo_message msg)2398     void handleOscMessage(const char* const method, const int argc, const void* const argvx, const char* const types, const lo_message msg) override
2399     {
2400         const lo_address source(lo_message_get_source(msg));
2401         CARLA_SAFE_ASSERT_RETURN(source != nullptr,);
2402 
2403         // protocol for DSSI UIs *must* be UDP
2404         CARLA_SAFE_ASSERT_RETURN(lo_address_get_protocol(source) == LO_UDP,);
2405 
2406         if (fOscData.source == nullptr)
2407         {
2408             // if no UI is registered yet only "configure" and "update" messages are valid
2409             CARLA_SAFE_ASSERT_RETURN(std::strcmp(method, "configure") == 0 || std::strcmp(method, "update") == 0,)
2410         }
2411         else
2412         {
2413             // make sure message source is the DSSI UI
2414             const char* const msghost = lo_address_get_hostname(source);
2415             const char* const msgport = lo_address_get_port(source);
2416 
2417             const char* const ourhost = lo_address_get_hostname(fOscData.source);
2418             const char* const ourport = lo_address_get_port(fOscData.source);
2419 
2420             CARLA_SAFE_ASSERT_RETURN(std::strcmp(msghost, ourhost) == 0,);
2421             CARLA_SAFE_ASSERT_RETURN(std::strcmp(msgport, ourport) == 0,);
2422         }
2423 
2424         const lo_arg* const* const argv(static_cast<const lo_arg* const*>(argvx));
2425 
2426         if (std::strcmp(method, "configure") == 0)
2427             return handleOscMessageConfigure(argc, argv, types);
2428         if (std::strcmp(method, "control") == 0)
2429             return handleOscMessageControl(argc, argv, types);
2430         if (std::strcmp(method, "program") == 0)
2431             return handleOscMessageProgram(argc, argv, types);
2432         if (std::strcmp(method, "midi") == 0)
2433             return handleOscMessageMIDI(argc, argv, types);
2434         if (std::strcmp(method, "update") == 0)
2435             return handleOscMessageUpdate(argc, argv, types, lo_message_get_source(msg));
2436         if (std::strcmp(method, "exiting") == 0)
2437             return handleOscMessageExiting();
2438 
2439         carla_stdout("CarlaPluginLADSPADSSI::handleOscMessage() - unknown method '%s'", method);
2440     }
2441 
handleOscMessageConfigure(const int argc,const lo_arg * const * const argv,const char * const types)2442     void handleOscMessageConfigure(const int argc, const lo_arg* const* const argv, const char* const types)
2443     {
2444         carla_debug("CarlaPluginLADSPADSSI::handleMsgConfigure()");
2445         CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(2, "ss");
2446 
2447         const char* const key   = (const char*)&argv[0]->s;
2448         const char* const value = (const char*)&argv[1]->s;
2449 
2450         setCustomData(CUSTOM_DATA_TYPE_STRING, key, value, false);
2451     }
2452 
handleOscMessageControl(const int argc,const lo_arg * const * const argv,const char * const types)2453     void handleOscMessageControl(const int argc, const lo_arg* const* const argv, const char* const types)
2454     {
2455         carla_debug("CarlaPluginLADSPADSSI::handleMsgControl()");
2456         CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(2, "if");
2457 
2458         const int32_t rindex = argv[0]->i;
2459         const float   value  = argv[1]->f;
2460 
2461         setParameterValueByRealIndex(rindex, value, false, true, true);
2462     }
2463 
handleOscMessageProgram(const int argc,const lo_arg * const * const argv,const char * const types)2464     void handleOscMessageProgram(const int argc, const lo_arg* const* const argv, const char* const types)
2465     {
2466         carla_debug("CarlaPluginLADSPADSSI::handleMsgProgram()");
2467         CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(2, "ii");
2468 
2469         const int32_t bank    = argv[0]->i;
2470         const int32_t program = argv[1]->i;
2471 
2472         CARLA_SAFE_ASSERT_RETURN(bank >= 0,);
2473         CARLA_SAFE_ASSERT_RETURN(program >= 0,);
2474 
2475         setMidiProgramById(static_cast<uint32_t>(bank), static_cast<uint32_t>(program), false, true, true);
2476     }
2477 
handleOscMessageMIDI(const int argc,const lo_arg * const * const argv,const char * const types)2478     void handleOscMessageMIDI(const int argc, const lo_arg* const* const argv, const char* const types)
2479     {
2480         carla_debug("CarlaPluginLADSPADSSI::handleMsgMidi()");
2481         CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(1, "m");
2482 
2483         if (getMidiInCount() == 0)
2484         {
2485             carla_stderr("CarlaPluginLADSPADSSI::handleMsgMidi() - received midi when plugin has no midi inputs");
2486             return;
2487         }
2488 
2489         const uint8_t* const data = argv[0]->m;
2490         uint8_t status  = data[1];
2491         uint8_t channel = status & 0x0F;
2492 
2493         // Fix bad note-off
2494         if (MIDI_IS_STATUS_NOTE_ON(status) && data[3] == 0)
2495             status = MIDI_STATUS_NOTE_OFF;
2496 
2497         if (MIDI_IS_STATUS_NOTE_OFF(status))
2498         {
2499             const uint8_t note = data[2];
2500 
2501             CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2502 
2503             sendMidiSingleNote(channel, note, 0, false, true, true);
2504         }
2505         else if (MIDI_IS_STATUS_NOTE_ON(status))
2506         {
2507             const uint8_t note = data[2];
2508             const uint8_t velo = data[3];
2509 
2510             CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2511             CARLA_SAFE_ASSERT_RETURN(velo < MAX_MIDI_VALUE,);
2512 
2513             sendMidiSingleNote(channel, note, velo, false, true, true);
2514         }
2515     }
2516 
handleOscMessageUpdate(const int argc,const lo_arg * const * const argv,const char * const types,const lo_address source)2517     void handleOscMessageUpdate(const int argc, const lo_arg* const* const argv, const char* const types, const lo_address source)
2518     {
2519         carla_debug("CarlaPluginLADSPADSSI::handleMsgUpdate()");
2520         CARLA_PLUGIN_DSSI_OSC_CHECK_OSC_TYPES(1, "s");
2521 
2522         const char* const url = (const char*)&argv[0]->s;
2523 
2524         // FIXME - remove debug prints later
2525         carla_stdout("CarlaPluginLADSPADSSI::updateOscData(%p, \"%s\")", source, url);
2526 
2527         fOscData.clear();
2528 
2529         const int proto = lo_address_get_protocol(source);
2530 
2531         {
2532             const char* host = lo_address_get_hostname(source);
2533             const char* port = lo_address_get_port(source);
2534             fOscData.source = lo_address_new_with_proto(proto, host, port);
2535 
2536             carla_stdout("CarlaPlugin::updateOscData() - source: host \"%s\", port \"%s\"", host, port);
2537         }
2538 
2539         {
2540             char* host = lo_url_get_hostname(url);
2541             char* port = lo_url_get_port(url);
2542             fOscData.path   = carla_strdup_free(lo_url_get_path(url));
2543             fOscData.target = lo_address_new_with_proto(proto, host, port);
2544             carla_stdout("CarlaPlugin::updateOscData() - target: host \"%s\", port \"%s\", path \"%s\"", host, port, fOscData.path);
2545 
2546             std::free(host);
2547             std::free(port);
2548         }
2549 
2550         osc_send_sample_rate(fOscData, static_cast<float>(pData->engine->getSampleRate()));
2551 
2552         for (LinkedList<CustomData>::Itenerator it = pData->custom.begin2(); it.valid(); it.next())
2553         {
2554             const CustomData& customData(it.getValue(kCustomDataFallback));
2555             CARLA_SAFE_ASSERT_CONTINUE(customData.isValid());
2556 
2557             if (std::strcmp(customData.type, CUSTOM_DATA_TYPE_STRING) == 0)
2558                 osc_send_configure(fOscData, customData.key, customData.value);
2559         }
2560 
2561         if (pData->prog.current >= 0)
2562             osc_send_program(fOscData, static_cast<uint32_t>(pData->prog.current));
2563 
2564         if (pData->midiprog.current >= 0)
2565         {
2566             const MidiProgramData& curMidiProg(pData->midiprog.getCurrent());
2567             osc_send_program(fOscData, curMidiProg.bank, curMidiProg.program);
2568         }
2569 
2570         for (uint32_t i=0; i < pData->param.count; ++i)
2571             osc_send_control(fOscData, pData->param.data[i].rindex, getParameterValue(i));
2572 
2573 #ifndef BUILD_BRIDGE
2574         if (pData->engine->getOptions().frontendWinId != 0)
2575             pData->transientTryCounter = 1;
2576 #endif
2577 
2578         carla_stdout("CarlaPluginLADSPADSSI::updateOscData() - done");
2579     }
2580 
handleOscMessageExiting()2581     void handleOscMessageExiting()
2582     {
2583         carla_debug("CarlaPluginLADSPADSSI::handleMsgExiting()");
2584 
2585         // hide UI
2586         showCustomUI(false);
2587 
2588         // tell frontend
2589         pData->engine->callback(true, true,
2590                                 ENGINE_CALLBACK_UI_STATE_CHANGED,
2591                                 pData->id,
2592                                 0,
2593                                 0, 0, 0.0f, nullptr);
2594     }
2595 
2596     // -------------------------------------------------------------------
2597     // Post-poned UI Stuff
2598 
uiParameterChange(const uint32_t index,const float value)2599     void uiParameterChange(const uint32_t index, const float value) noexcept override
2600     {
2601         CARLA_SAFE_ASSERT_RETURN(index < pData->param.count,);
2602 
2603         if (fOscData.target == nullptr)
2604             return;
2605 
2606         osc_send_control(fOscData, pData->param.data[index].rindex, value);
2607     }
2608 
uiMidiProgramChange(const uint32_t index)2609     void uiMidiProgramChange(const uint32_t index) noexcept override
2610     {
2611         CARLA_SAFE_ASSERT_RETURN(index < pData->midiprog.count,);
2612 
2613         if (fOscData.target == nullptr)
2614             return;
2615 
2616         osc_send_program(fOscData, pData->midiprog.data[index].bank, pData->midiprog.data[index].program);
2617     }
2618 
uiNoteOn(const uint8_t channel,const uint8_t note,const uint8_t velo)2619     void uiNoteOn(const uint8_t channel, const uint8_t note, const uint8_t velo) noexcept override
2620     {
2621         CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2622         CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2623         CARLA_SAFE_ASSERT_RETURN(velo > 0 && velo < MAX_MIDI_VALUE,);
2624 
2625         if (fOscData.target == nullptr)
2626             return;
2627 
2628 #if 0
2629         uint8_t midiData[4];
2630         midiData[0] = 0;
2631         midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
2632         midiData[2] = note;
2633         midiData[3] = velo;
2634 
2635         osc_send_midi(fOscData, midiData);
2636 #endif
2637     }
2638 
uiNoteOff(const uint8_t channel,const uint8_t note)2639     void uiNoteOff(const uint8_t channel, const uint8_t note) noexcept override
2640     {
2641         CARLA_SAFE_ASSERT_RETURN(channel < MAX_MIDI_CHANNELS,);
2642         CARLA_SAFE_ASSERT_RETURN(note < MAX_MIDI_NOTE,);
2643 
2644         if (fOscData.target == nullptr)
2645             return;
2646 
2647 #if 0
2648         uint8_t midiData[4];
2649         midiData[0] = 0;
2650         midiData[1] = uint8_t(MIDI_STATUS_NOTE_ON | (channel & MIDI_CHANNEL_BIT));
2651         midiData[2] = note;
2652         midiData[3] = 0;
2653 
2654         osc_send_midi(fOscData, midiData);
2655 #endif
2656     }
2657 #endif // HAVE_LIBLO && !BUILD_BRIDGE
2658 
2659     // -------------------------------------------------------------------
2660 
getNativeDescriptor() const2661     const void* getNativeDescriptor() const noexcept override
2662     {
2663         return fDssiDescriptor != nullptr
2664                ? (const void*)fDssiDescriptor
2665                : (const void*)fDescriptor;
2666     }
2667 
getExtraStuff() const2668     const void* getExtraStuff() const noexcept override
2669     {
2670         if (fDssiDescriptor != nullptr)
2671         {
2672 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
2673             return fUiFilename;
2674 #else
2675             return nullptr;
2676 #endif
2677         }
2678         return fRdfDescriptor;
2679     }
2680 
2681 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
getUiBridgeProcessId() const2682     uintptr_t getUiBridgeProcessId() const noexcept override
2683     {
2684         return fThreadUI.getProcessId();
2685     }
2686 #endif
2687 
2688     // -------------------------------------------------------------------
2689 
initLADSPA(const CarlaPluginPtr plugin,const char * const filename,const char * name,const char * const label,const uint options,const LADSPA_RDF_Descriptor * const rdfDescriptor)2690     bool initLADSPA(const CarlaPluginPtr plugin,
2691                     const char* const filename, const char* name, const char* const label, const uint options,
2692                     const LADSPA_RDF_Descriptor* const rdfDescriptor)
2693     {
2694         CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
2695 
2696         // ---------------------------------------------------------------
2697         // first checks
2698 
2699         if (pData->client != nullptr)
2700         {
2701             pData->engine->setLastError("Plugin client is already registered");
2702             return false;
2703         }
2704 
2705         if (filename == nullptr || filename[0] == '\0')
2706         {
2707             pData->engine->setLastError("null filename");
2708             return false;
2709         }
2710 
2711         // ---------------------------------------------------------------
2712         // open DLL
2713 
2714         if (! pData->libOpen(filename))
2715         {
2716             pData->engine->setLastError(pData->libError(filename));
2717             return false;
2718         }
2719 
2720         // ---------------------------------------------------------------
2721         // get DLL main entry
2722 
2723         const LADSPA_Descriptor_Function descFn = pData->libSymbol<LADSPA_Descriptor_Function>("ladspa_descriptor");
2724 
2725         if (descFn == nullptr)
2726         {
2727             pData->engine->setLastError("Could not find the LASDPA Descriptor in the plugin library");
2728             return false;
2729         }
2730 
2731         // ---------------------------------------------------------------
2732         // get descriptor that matches label
2733 
2734         // if label is null, get first valid plugin
2735         const bool nullLabel = (label == nullptr || label[0] == '\0');
2736 
2737         for (ulong d=0;; ++d)
2738         {
2739             try {
2740                 fDescriptor = descFn(d);
2741             }
2742             catch(...) {
2743                 carla_stderr2("Caught exception when trying to get LADSPA descriptor");
2744                 fDescriptor = nullptr;
2745                 break;
2746             }
2747 
2748             if (fDescriptor == nullptr)
2749                 break;
2750 
2751             if (fDescriptor->Label == nullptr || fDescriptor->Label[0] == '\0')
2752             {
2753                 carla_stderr2("WARNING - Got an invalid label, will not use this plugin");
2754                 fDescriptor = nullptr;
2755                 break;
2756             }
2757             if (fDescriptor->run == nullptr)
2758             {
2759                 carla_stderr2("WARNING - Plugin has no run, cannot use it");
2760                 fDescriptor = nullptr;
2761                 break;
2762             }
2763 
2764             if (nullLabel || std::strcmp(fDescriptor->Label, label) == 0)
2765                 break;
2766         }
2767 
2768         if (fDescriptor == nullptr)
2769         {
2770             pData->engine->setLastError("Could not find the requested plugin label in the plugin library");
2771             return false;
2772         }
2773 
2774         return init2(plugin, filename, name, options, rdfDescriptor);
2775     }
2776 
initDSSI(const CarlaPluginPtr plugin,const char * const filename,const char * name,const char * const label,const uint options)2777     bool initDSSI(const CarlaPluginPtr plugin,
2778                   const char* const filename, const char* name, const char* const label, const uint options)
2779     {
2780         CARLA_SAFE_ASSERT_RETURN(pData->engine != nullptr, false);
2781 
2782         // ---------------------------------------------------------------
2783         // first checks
2784 
2785         if (pData->client != nullptr)
2786         {
2787             pData->engine->setLastError("Plugin client is already registered");
2788             return false;
2789         }
2790 
2791         if (filename == nullptr || filename[0] == '\0')
2792         {
2793             pData->engine->setLastError("null filename");
2794             return false;
2795         }
2796 
2797         // ---------------------------------------------------------------
2798         // open DLL
2799 
2800         if (! pData->libOpen(filename))
2801         {
2802             pData->engine->setLastError(pData->libError(filename));
2803             return false;
2804         }
2805 
2806         // ---------------------------------------------------------------
2807         // get DLL main entry
2808 
2809         const DSSI_Descriptor_Function descFn = pData->libSymbol<DSSI_Descriptor_Function>("dssi_descriptor");
2810 
2811         if (descFn == nullptr)
2812         {
2813             pData->engine->setLastError("Could not find the DSSI Descriptor in the plugin library");
2814             return false;
2815         }
2816 
2817         // ---------------------------------------------------------------
2818         // get descriptor that matches label
2819 
2820         // if label is null, get first valid plugin
2821         const bool nullLabel = (label == nullptr || label[0] == '\0');
2822 
2823         for (ulong d=0;; ++d)
2824         {
2825             try {
2826                 fDssiDescriptor = descFn(d);
2827             }
2828             catch(...) {
2829                 carla_stderr2("Caught exception when trying to get DSSI descriptor");
2830                 fDescriptor     = nullptr;
2831                 fDssiDescriptor = nullptr;
2832                 break;
2833             }
2834 
2835             if (fDssiDescriptor == nullptr)
2836                 break;
2837 
2838             fDescriptor = fDssiDescriptor->LADSPA_Plugin;
2839 
2840             if (fDescriptor == nullptr)
2841             {
2842                 carla_stderr2("WARNING - Missing LADSPA interface, will not use this plugin");
2843                 fDssiDescriptor = nullptr;
2844                 break;
2845             }
2846             if (fDescriptor->Label == nullptr || fDescriptor->Label[0] == '\0')
2847             {
2848                 carla_stderr2("WARNING - Got an invalid label, will not use this plugin");
2849                 fDescriptor     = nullptr;
2850                 fDssiDescriptor = nullptr;
2851                 break;
2852             }
2853             if (fDescriptor->run == nullptr)
2854             {
2855                 carla_stderr2("WARNING - Plugin has no run, cannot use it");
2856                 fDescriptor     = nullptr;
2857                 fDssiDescriptor = nullptr;
2858                 break;
2859             }
2860 
2861             if (nullLabel || std::strcmp(fDescriptor->Label, label) == 0)
2862                 break;
2863         }
2864 
2865         if (fDescriptor == nullptr || fDssiDescriptor == nullptr)
2866         {
2867             pData->engine->setLastError("Could not find the requested plugin label in the plugin library");
2868             return false;
2869         }
2870 
2871         // ---------------------------------------------------------------
2872         // check if uses global instance
2873 
2874         if (fDssiDescriptor->run_synth == nullptr && fDssiDescriptor->run_multiple_synths != nullptr)
2875         {
2876             pData->engine->setLastError("This plugin requires run_multiple_synths which is not supported");
2877             return false;
2878         }
2879 
2880         return init2(plugin, filename, name, options, nullptr);
2881     }
2882 
init2(const CarlaPluginPtr plugin,const char * const filename,const char * name,const uint options,const LADSPA_RDF_Descriptor * const rdfDescriptor)2883     bool init2(const CarlaPluginPtr plugin,
2884                const char* const filename, const char* name, const uint options,
2885                const LADSPA_RDF_Descriptor* const rdfDescriptor)
2886     {
2887         // ---------------------------------------------------------------
2888         // check for fixed buffer size requirement
2889 
2890         fNeedsFixedBuffers = CarlaString(filename).contains("dssi-vst", true);
2891 
2892         if (fNeedsFixedBuffers && ! pData->engine->usesConstantBufferSize())
2893         {
2894             pData->engine->setLastError("Cannot use this plugin under the current engine.\n"
2895                                         "The plugin requires a fixed block size which is not possible right now.");
2896             return false;
2897         }
2898 
2899         // ---------------------------------------------------------------
2900         // get info
2901 
2902         if (is_ladspa_rdf_descriptor_valid(rdfDescriptor, fDescriptor))
2903             fRdfDescriptor = ladspa_rdf_dup(rdfDescriptor);
2904 
2905         if (name == nullptr || name[0] == '\0')
2906         {
2907             /**/ if (fRdfDescriptor != nullptr && fRdfDescriptor->Title != nullptr && fRdfDescriptor->Title[0] != '\0')
2908                 name = fRdfDescriptor->Title;
2909             else if (fDescriptor->Name != nullptr && fDescriptor->Name[0] != '\0')
2910                 name = fDescriptor->Name;
2911             else
2912                 name = fDescriptor->Label;
2913         }
2914 
2915         pData->name = pData->engine->getUniquePluginName(name);
2916         pData->filename = carla_strdup(filename);
2917 
2918         // ---------------------------------------------------------------
2919         // register client
2920 
2921         pData->client = pData->engine->addClient(plugin);
2922 
2923         if (pData->client == nullptr || ! pData->client->isOk())
2924         {
2925             pData->engine->setLastError("Failed to register plugin client");
2926             return false;
2927         }
2928 
2929         // ---------------------------------------------------------------
2930         // initialize plugin
2931 
2932         if (! addInstance())
2933             return false;
2934 
2935         // ---------------------------------------------------------------
2936         // find latency port index
2937 
2938         for (uint32_t i=0, iCtrl=0, count=getSafePortCount(); i<count; ++i)
2939         {
2940             const int portType(fDescriptor->PortDescriptors[i]);
2941 
2942             if (! LADSPA_IS_PORT_CONTROL(portType))
2943                 continue;
2944 
2945             const uint32_t index(iCtrl++);
2946 
2947             if (! LADSPA_IS_PORT_OUTPUT(portType))
2948                 continue;
2949 
2950             const char* const portName(fDescriptor->PortNames[i]);
2951             CARLA_SAFE_ASSERT_BREAK(portName != nullptr);
2952 
2953             if (std::strcmp(portName, "latency")  == 0 ||
2954                 std::strcmp(portName, "_latency") == 0)
2955             {
2956                 fLatencyIndex = static_cast<int32_t>(index);
2957                 break;
2958             }
2959         }
2960 
2961         // ---------------------------------------------------------------
2962         // check for custom data extension
2963 
2964         if (fDssiDescriptor != nullptr && fDssiDescriptor->configure != nullptr)
2965         {
2966             if (char* const error = fDssiDescriptor->configure(fHandles.getFirst(nullptr), DSSI_CUSTOMDATA_EXTENSION_KEY, ""))
2967             {
2968                 if (std::strcmp(error, "true") == 0 && fDssiDescriptor->get_custom_data != nullptr
2969                                                     && fDssiDescriptor->set_custom_data != nullptr)
2970                     fUsesCustomData = true;
2971 
2972                 std::free(error);
2973             }
2974         }
2975 
2976         // ---------------------------------------------------------------
2977         // get engine options
2978 
2979         const EngineOptions& opts(pData->engine->getOptions());
2980 
2981 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
2982         // ---------------------------------------------------------------
2983         // check for gui
2984 
2985         if (opts.oscEnabled && opts.oscPortUDP >= 0)
2986         {
2987             if (const char* const guiFilename = find_dssi_ui(filename, fDescriptor->Label))
2988             {
2989                 fUiFilename = guiFilename;
2990 
2991                 CarlaString uiTitle;
2992 
2993                 if (pData->uiTitle.isNotEmpty())
2994                 {
2995                     uiTitle = pData->uiTitle;
2996                 }
2997                 else
2998                 {
2999                     uiTitle  = pData->name;
3000                     uiTitle += " (GUI)";
3001                 }
3002 
3003                 fThreadUI.setData(guiFilename, fDescriptor->Label, uiTitle);
3004             }
3005         }
3006 #endif
3007 
3008         // ---------------------------------------------------------------
3009         // set options
3010 
3011         pData->options = 0x0;
3012 
3013         /**/ if (fLatencyIndex >= 0 || fNeedsFixedBuffers)
3014             pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
3015         else if (options & PLUGIN_OPTION_FIXED_BUFFERS)
3016             pData->options |= PLUGIN_OPTION_FIXED_BUFFERS;
3017 
3018         /**/ if (opts.forceStereo)
3019             pData->options |= PLUGIN_OPTION_FORCE_STEREO;
3020         else if (options & PLUGIN_OPTION_FORCE_STEREO)
3021             pData->options |= PLUGIN_OPTION_FORCE_STEREO;
3022 
3023         if (fDssiDescriptor != nullptr)
3024         {
3025             if (fDssiDescriptor->get_program != nullptr && fDssiDescriptor->select_program != nullptr)
3026                 if (isPluginOptionEnabled(options, PLUGIN_OPTION_MAP_PROGRAM_CHANGES))
3027                     pData->options |= PLUGIN_OPTION_MAP_PROGRAM_CHANGES;
3028 
3029             if (fUsesCustomData)
3030                 if (isPluginOptionEnabled(options, PLUGIN_OPTION_USE_CHUNKS))
3031                     pData->options |= PLUGIN_OPTION_USE_CHUNKS;
3032 
3033             if (fDssiDescriptor->run_synth != nullptr)
3034             {
3035                 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CONTROL_CHANGES))
3036                     pData->options |= PLUGIN_OPTION_SEND_CONTROL_CHANGES;
3037                 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_CHANNEL_PRESSURE))
3038                     pData->options |= PLUGIN_OPTION_SEND_CHANNEL_PRESSURE;
3039                 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH))
3040                     pData->options |= PLUGIN_OPTION_SEND_NOTE_AFTERTOUCH;
3041                 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_PITCHBEND))
3042                     pData->options |= PLUGIN_OPTION_SEND_PITCHBEND;
3043                 if (isPluginOptionEnabled(options, PLUGIN_OPTION_SEND_ALL_SOUND_OFF))
3044                     pData->options |= PLUGIN_OPTION_SEND_ALL_SOUND_OFF;
3045                 if (isPluginOptionInverseEnabled(options, PLUGIN_OPTION_SKIP_SENDING_NOTES))
3046                     pData->options |= PLUGIN_OPTION_SKIP_SENDING_NOTES;
3047             }
3048         }
3049 
3050         return true;
3051     }
3052 
3053     // -------------------------------------------------------------------
3054 
3055 private:
3056     LinkedList<LADSPA_Handle>    fHandles;
3057     const LADSPA_Descriptor*     fDescriptor;
3058     const DSSI_Descriptor*       fDssiDescriptor;
3059     const LADSPA_RDF_Descriptor* fRdfDescriptor;
3060 
3061     float** fAudioInBuffers;
3062     float** fAudioOutBuffers;
3063     float*  fExtraStereoBuffer[2]; // used only if forcedStereoIn and audioOut == 2
3064     float*  fParamBuffers;
3065 
3066     snd_seq_event_t fMidiEvents[kPluginMaxMidiEvents];
3067 
3068     int32_t fLatencyIndex; // -1 if invalid
3069     bool    fForcedStereoIn;
3070     bool    fForcedStereoOut;
3071     bool    fNeedsFixedBuffers;
3072     bool    fUsesCustomData;
3073 
3074 #if defined(HAVE_LIBLO) && !defined(BUILD_BRIDGE)
3075     CarlaOscData      fOscData;
3076     CarlaThreadDSSIUI fThreadUI;
3077     const char*       fUiFilename;
3078 #endif
3079 
3080     // -------------------------------------------------------------------
3081 
addInstance()3082     bool addInstance()
3083     {
3084         LADSPA_Handle handle;
3085 
3086         try {
3087             handle = fDescriptor->instantiate(fDescriptor, static_cast<ulong>(pData->engine->getSampleRate()));
3088         } CARLA_SAFE_EXCEPTION_RETURN_ERR("LADSPA/DSSI instantiate", "Plugin failed to initialize");
3089 
3090         for (uint32_t i=0, count=pData->param.count; i<count; ++i)
3091         {
3092             const int32_t rindex(pData->param.data[i].rindex);
3093             CARLA_SAFE_ASSERT_CONTINUE(rindex >= 0);
3094 
3095             try {
3096                 fDescriptor->connect_port(handle, static_cast<ulong>(rindex), &fParamBuffers[i]);
3097             } CARLA_SAFE_EXCEPTION("LADSPA/DSSI connect_port");
3098         }
3099 
3100         if (fHandles.append(handle))
3101             return true;
3102 
3103         try {
3104             fDescriptor->cleanup(handle);
3105         } CARLA_SAFE_EXCEPTION("LADSPA/DSSI cleanup");
3106 
3107         pData->engine->setLastError("Out of memory");
3108         return false;
3109     }
3110 
getSafePortCount() const3111     uint32_t getSafePortCount() const noexcept
3112     {
3113         if (fDescriptor->PortCount == 0)
3114             return 0;
3115 
3116         CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortDescriptors != nullptr, 0);
3117         CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortRangeHints != nullptr, 0);
3118         CARLA_SAFE_ASSERT_RETURN(fDescriptor->PortNames != nullptr, 0);
3119 
3120         return static_cast<uint32_t>(fDescriptor->PortCount);
3121     }
3122 
getSeparatedParameterNameOrUnit(const char * const paramName,char * const strBuf,const bool wantName) const3123     bool getSeparatedParameterNameOrUnit(const char* const paramName, char* const strBuf, const bool wantName) const noexcept
3124     {
3125         if (_getSeparatedParameterNameOrUnitImpl(paramName, strBuf, wantName, true))
3126             return true;
3127         if (_getSeparatedParameterNameOrUnitImpl(paramName, strBuf, wantName, false))
3128             return true;
3129         return false;
3130     }
3131 
_getSeparatedParameterNameOrUnitImpl(const char * const paramName,char * const strBuf,const bool wantName,const bool useBracket)3132     static bool _getSeparatedParameterNameOrUnitImpl(const char* const paramName, char* const strBuf,
3133                                                      const bool wantName, const bool useBracket) noexcept
3134     {
3135         const char* const sepBracketStart = std::strstr(paramName, useBracket ? " [" : " (");
3136 
3137         if (sepBracketStart == nullptr)
3138             return false;
3139 
3140         const char* const sepBracketEnd = std::strstr(sepBracketStart, useBracket ? "]" : ")");
3141 
3142         if (sepBracketEnd == nullptr)
3143             return false;
3144 
3145         const std::size_t unitSize = static_cast<std::size_t>(sepBracketEnd-sepBracketStart-2);
3146 
3147         if (unitSize > 7) // very unlikely to have such big unit
3148             return false;
3149 
3150         const std::size_t sepIndex = std::strlen(paramName)-unitSize-3;
3151 
3152         // just in case
3153         if (sepIndex > STR_MAX-3)
3154             return false;
3155 
3156         if (wantName)
3157         {
3158             std::strncpy(strBuf, paramName, sepIndex);
3159             strBuf[sepIndex] = '\0';
3160         }
3161         else
3162         {
3163             std::strncpy(strBuf, paramName+(sepIndex+2), unitSize);
3164             strBuf[unitSize] = '\0';
3165         }
3166 
3167         return true;
3168     }
3169 
3170     // -------------------------------------------------------------------
3171 
3172     CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaPluginLADSPADSSI)
3173 };
3174 
3175 // -------------------------------------------------------------------------------------------------------------------
3176 
newLADSPA(const Initializer & init,const LADSPA_RDF_Descriptor * const rdfDescriptor)3177 CarlaPluginPtr CarlaPlugin::newLADSPA(const Initializer& init, const LADSPA_RDF_Descriptor* const rdfDescriptor)
3178 {
3179     carla_debug("CarlaPlugin::newLADSPA({%p, \"%s\", \"%s\", \"%s\", " P_INT64 ", %x}, %p)",
3180                 init.engine, init.filename, init.name, init.label, init.uniqueId, init.options, rdfDescriptor);
3181 
3182     std::shared_ptr<CarlaPluginLADSPADSSI> plugin(new CarlaPluginLADSPADSSI(init.engine, init.id));
3183 
3184     if (! plugin->initLADSPA(plugin, init.filename, init.name, init.label, init.options, rdfDescriptor))
3185         return nullptr;
3186 
3187     return plugin;
3188 }
3189 
newDSSI(const Initializer & init)3190 CarlaPluginPtr CarlaPlugin::newDSSI(const Initializer& init)
3191 {
3192     carla_debug("CarlaPlugin::newDSSI({%p, \"%s\", \"%s\", \"%s\", " P_INT64 ", %x})",
3193                 init.engine, init.filename, init.name, init.label, init.uniqueId, init.options);
3194 
3195     std::shared_ptr<CarlaPluginLADSPADSSI> plugin(new CarlaPluginLADSPADSSI(init.engine, init.id));
3196 
3197     if (! plugin->initDSSI(plugin, init.filename, init.name, init.label, init.options))
3198         return nullptr;
3199 
3200     return plugin;
3201 }
3202 
3203 // -------------------------------------------------------------------------------------------------------------------
3204 
3205 CARLA_BACKEND_END_NAMESPACE
3206