1 /*
2  * Carla Bridge UI
3  * Copyright (C) 2011-2019 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 "CarlaBridgeFormat.hpp"
19 #include "CarlaBridgeToolkit.hpp"
20 
21 #include "CarlaLibUtils.hpp"
22 #include "CarlaLv2Utils.hpp"
23 #include "CarlaMIDI.h"
24 #include "LinkedList.hpp"
25 
26 #include "water/files/File.h"
27 
28 #ifdef CARLA_OS_MAC
29 # include "CarlaMacUtils.hpp"
30 #endif
31 
32 #include <string>
33 #include <vector>
34 
35 #define URI_CARLA_ATOM_WORKER_IN   "http://kxstudio.sf.net/ns/carla/atomWorkerIn"
36 #define URI_CARLA_ATOM_WORKER_RESP "http://kxstudio.sf.net/ns/carla/atomWorkerResp"
37 #define URI_CARLA_PARAMETER_CHANGE "http://kxstudio.sf.net/ns/carla/parameterChange"
38 
39 using water::File;
40 
41 CARLA_BRIDGE_UI_START_NAMESPACE
42 
43 // --------------------------------------------------------------------------------------------------------------------
44 
45 static double gInitialSampleRate = 44100.0;
46 static const char* const kNullWindowTitle = "TestUI";
47 static const uint32_t kNullWindowTitleSize = 6;
48 static const char* const kUnmapFallback = "urn:null";
49 
50 // LV2 URI Map Ids
51 enum CarlaLv2URIDs {
52     kUridNull = 0,
53     kUridAtomBlank,
54     kUridAtomBool,
55     kUridAtomChunk,
56     kUridAtomDouble,
57     kUridAtomEvent,
58     kUridAtomFloat,
59     kUridAtomInt,
60     kUridAtomLiteral,
61     kUridAtomLong,
62     kUridAtomNumber,
63     kUridAtomObject,
64     kUridAtomPath,
65     kUridAtomProperty,
66     kUridAtomResource,
67     kUridAtomSequence,
68     kUridAtomSound,
69     kUridAtomString,
70     kUridAtomTuple,
71     kUridAtomURI,
72     kUridAtomURID,
73     kUridAtomVector,
74     kUridAtomTransferAtom,
75     kUridAtomTransferEvent,
76     kUridBufMaxLength,
77     kUridBufMinLength,
78     kUridBufNominalLength,
79     kUridBufSequenceSize,
80     kUridLogError,
81     kUridLogNote,
82     kUridLogTrace,
83     kUridLogWarning,
84     kUridPatchSet,
85     kUridPatchProperty,
86     kUridPatchSubject,
87     kUridPatchValue,
88     // time base type
89     kUridTimePosition,
90      // time values
91     kUridTimeBar,
92     kUridTimeBarBeat,
93     kUridTimeBeat,
94     kUridTimeBeatUnit,
95     kUridTimeBeatsPerBar,
96     kUridTimeBeatsPerMinute,
97     kUridTimeFrame,
98     kUridTimeFramesPerSecond,
99     kUridTimeSpeed,
100     kUridTimeTicksPerBeat,
101     kUridMidiEvent,
102     kUridParamSampleRate,
103     // ui stuff
104     kUridBackgroundColor,
105     kUridForegroundColor,
106     kUridScaleFactor,
107     kUridWindowTitle,
108     // custom carla props
109     kUridCarlaAtomWorkerIn,
110     kUridCarlaAtomWorkerResp,
111     kUridCarlaParameterChange,
112     kUridCarlaTransientWindowId,
113     // count
114     kUridCount
115 };
116 
117 // LV2 Feature Ids
118 enum CarlaLv2Features {
119     // DSP features
120     kFeatureIdLogs = 0,
121     kFeatureIdOptions,
122     kFeatureIdPrograms,
123     kFeatureIdStateFreePath,
124     kFeatureIdStateMakePath,
125     kFeatureIdStateMapPath,
126     kFeatureIdUriMap,
127     kFeatureIdUridMap,
128     kFeatureIdUridUnmap,
129     kFeatureIdUiIdleInterface,
130     kFeatureIdUiFixedSize,
131     kFeatureIdUiMakeResident,
132     kFeatureIdUiMakeResident2,
133     kFeatureIdUiNoUserResize,
134     kFeatureIdUiParent,
135     kFeatureIdUiPortMap,
136     kFeatureIdUiPortSubscribe,
137     kFeatureIdUiRequestValue,
138     kFeatureIdUiResize,
139     kFeatureIdUiTouch,
140     kFeatureCount
141 };
142 
143 // --------------------------------------------------------------------------------------------------------------------
144 
145 struct Lv2PluginOptions {
146     enum OptIndex {
147         SampleRate,
148         TransientWinId,
149         BackgroundColor,
150         ForegroundColor,
151         ScaleFactor,
152         WindowTitle,
153         Null,
154         Count
155     };
156 
157     float sampleRate;
158     int64_t transientWinId;
159     uint32_t bgColor;
160     uint32_t fgColor;
161     float uiScale;
162     LV2_Options_Option opts[Count];
163 
Lv2PluginOptionsLv2PluginOptions164     Lv2PluginOptions() noexcept
165         : sampleRate(static_cast<float>(gInitialSampleRate)),
166           transientWinId(0),
167           bgColor(0x000000ff),
168           fgColor(0xffffffff),
169           uiScale(1.0f)
170     {
171         LV2_Options_Option& optSampleRate(opts[SampleRate]);
172         optSampleRate.context = LV2_OPTIONS_INSTANCE;
173         optSampleRate.subject = 0;
174         optSampleRate.key     = kUridParamSampleRate;
175         optSampleRate.size    = sizeof(float);
176         optSampleRate.type    = kUridAtomFloat;
177         optSampleRate.value   = &sampleRate;
178 
179         LV2_Options_Option& optBackgroundColor(opts[BackgroundColor]);
180         optBackgroundColor.context = LV2_OPTIONS_INSTANCE;
181         optBackgroundColor.subject = 0;
182         optBackgroundColor.key     = kUridBackgroundColor;
183         optBackgroundColor.size    = sizeof(int32_t);
184         optBackgroundColor.type    = kUridAtomInt;
185         optBackgroundColor.value   = &bgColor;
186 
187         LV2_Options_Option& optForegroundColor(opts[ForegroundColor]);
188         optForegroundColor.context = LV2_OPTIONS_INSTANCE;
189         optForegroundColor.subject = 0;
190         optForegroundColor.key     = kUridForegroundColor;
191         optForegroundColor.size    = sizeof(int32_t);
192         optForegroundColor.type    = kUridAtomInt;
193         optForegroundColor.value   = &fgColor;
194 
195         LV2_Options_Option& optScaleFactor(opts[ScaleFactor]);
196         optScaleFactor.context = LV2_OPTIONS_INSTANCE;
197         optScaleFactor.subject = 0;
198         optScaleFactor.key     = kUridScaleFactor;
199         optScaleFactor.size    = sizeof(float);
200         optScaleFactor.type    = kUridAtomFloat;
201         optScaleFactor.value   = &uiScale;
202 
203         LV2_Options_Option& optTransientWinId(opts[TransientWinId]);
204         optTransientWinId.context = LV2_OPTIONS_INSTANCE;
205         optTransientWinId.subject = 0;
206         optTransientWinId.key     = kUridCarlaTransientWindowId;
207         optTransientWinId.size    = sizeof(int64_t);
208         optTransientWinId.type    = kUridAtomLong;
209         optTransientWinId.value   = &transientWinId;
210 
211         LV2_Options_Option& optWindowTitle(opts[WindowTitle]);
212         optWindowTitle.context = LV2_OPTIONS_INSTANCE;
213         optWindowTitle.subject = 0;
214         optWindowTitle.key     = kUridWindowTitle;
215         optWindowTitle.size    = kNullWindowTitleSize;
216         optWindowTitle.type    = kUridAtomString;
217         optWindowTitle.value   = kNullWindowTitle;
218 
219         LV2_Options_Option& optNull(opts[Null]);
220         optNull.context = LV2_OPTIONS_INSTANCE;
221         optNull.subject = 0;
222         optNull.key     = kUridNull;
223         optNull.size    = 0;
224         optNull.type    = kUridNull;
225         optNull.value   = nullptr;
226     }
227 };
228 
229 // -------------------------------------------------------------------------------------------------------------------
230 
initAtomForge(LV2_Atom_Forge & atomForge)231 static void initAtomForge(LV2_Atom_Forge& atomForge) noexcept
232 {
233     carla_zeroStruct(atomForge);
234 
235     atomForge.Bool     = kUridAtomBool;
236     atomForge.Chunk    = kUridAtomChunk;
237     atomForge.Double   = kUridAtomDouble;
238     atomForge.Float    = kUridAtomFloat;
239     atomForge.Int      = kUridAtomInt;
240     atomForge.Literal  = kUridAtomLiteral;
241     atomForge.Long     = kUridAtomLong;
242     atomForge.Object   = kUridAtomObject;
243     atomForge.Path     = kUridAtomPath;
244     atomForge.Property = kUridAtomProperty;
245     atomForge.Sequence = kUridAtomSequence;
246     atomForge.String   = kUridAtomString;
247     atomForge.Tuple    = kUridAtomTuple;
248     atomForge.URI      = kUridAtomURI;
249     atomForge.URID     = kUridAtomURID;
250     atomForge.Vector   = kUridAtomVector;
251 
252 #if defined(__clang__)
253 # pragma clang diagnostic push
254 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
255 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
256 # pragma GCC diagnostic push
257 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
258 #endif
259     atomForge.Blank    = kUridAtomBlank;
260     atomForge.Resource = kUridAtomResource;
261 #if defined(__clang__)
262 # pragma clang diagnostic pop
263 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
264 # pragma GCC diagnostic pop
265 #endif
266 }
267 
268 // --------------------------------------------------------------------------------------------------------------------
269 
270 class CarlaLv2Client : public CarlaBridgeFormat
271 {
272 public:
CarlaLv2Client()273     CarlaLv2Client()
274         : CarlaBridgeFormat(),
275           fHandle(nullptr),
276           fWidget(nullptr),
277           fDescriptor(nullptr),
278           fRdfDescriptor(nullptr),
279           fRdfUiDescriptor(nullptr),
280           fControlDesignatedPort(0),
281           fLv2Options(),
282           fUiOptions(),
283           fCustomURIDs(kUridCount, std::string("urn:null")),
284           fExt()
285     {
286         CARLA_SAFE_ASSERT(fCustomURIDs.size() == kUridCount);
287 
288         carla_zeroPointers(fFeatures, kFeatureCount+1);
289 
290         // ------------------------------------------------------------------------------------------------------------
291         // initialize features (part 1)
292 
293         LV2_Log_Log* const logFt = new LV2_Log_Log;
294         logFt->handle            = this;
295         logFt->printf            = carla_lv2_log_printf;
296         logFt->vprintf           = carla_lv2_log_vprintf;
297 
298         LV2_State_Free_Path* const stateFreePathFt = new LV2_State_Free_Path;
299         stateFreePathFt->handle                    = this;
300         stateFreePathFt->free_path                 = carla_lv2_state_free_path;
301 
302         LV2_State_Make_Path* const stateMakePathFt = new LV2_State_Make_Path;
303         stateMakePathFt->handle                    = this;
304         stateMakePathFt->path                      = carla_lv2_state_make_path_tmp;
305 
306         LV2_State_Map_Path* const stateMapPathFt = new LV2_State_Map_Path;
307         stateMapPathFt->handle                   = this;
308         stateMapPathFt->abstract_path            = carla_lv2_state_map_abstract_path_tmp;
309         stateMapPathFt->absolute_path            = carla_lv2_state_map_absolute_path_tmp;
310 
311         LV2_Programs_Host* const programsFt = new LV2_Programs_Host;
312         programsFt->handle                  = this;
313         programsFt->program_changed         = carla_lv2_program_changed;
314 
315         LV2_URI_Map_Feature* const uriMapFt = new LV2_URI_Map_Feature;
316         uriMapFt->callback_data             = this;
317         uriMapFt->uri_to_id                 = carla_lv2_uri_to_id;
318 
319         LV2_URID_Map* const uridMapFt = new LV2_URID_Map;
320         uridMapFt->handle             = this;
321         uridMapFt->map                = carla_lv2_urid_map;
322 
323         LV2_URID_Unmap* const uridUnmapFt = new LV2_URID_Unmap;
324         uridUnmapFt->handle               = this;
325         uridUnmapFt->unmap                = carla_lv2_urid_unmap;
326 
327         LV2UI_Port_Map* const uiPortMapFt = new LV2UI_Port_Map;
328         uiPortMapFt->handle               = this;
329         uiPortMapFt->port_index           = carla_lv2_ui_port_map;
330 
331         LV2UI_Request_Value* const uiRequestValueFt = new LV2UI_Request_Value;
332         uiRequestValueFt->handle                    = this;
333         uiRequestValueFt->request                   = carla_lv2_ui_request_value;
334 
335         LV2UI_Resize* const uiResizeFt    = new LV2UI_Resize;
336         uiResizeFt->handle                = this;
337         uiResizeFt->ui_resize             = carla_lv2_ui_resize;
338 
339         // ------------------------------------------------------------------------------------------------------------
340         // initialize features (part 2)
341 
342         for (uint32_t i=0; i < kFeatureCount; ++i)
343             fFeatures[i] = new LV2_Feature;
344 
345         fFeatures[kFeatureIdLogs]->URI       = LV2_LOG__log;
346         fFeatures[kFeatureIdLogs]->data      = logFt;
347 
348         fFeatures[kFeatureIdOptions]->URI    = LV2_OPTIONS__options;
349         fFeatures[kFeatureIdOptions]->data   = fLv2Options.opts;
350 
351         fFeatures[kFeatureIdPrograms]->URI   = LV2_PROGRAMS__Host;
352         fFeatures[kFeatureIdPrograms]->data  = programsFt;
353 
354         fFeatures[kFeatureIdStateFreePath]->URI  = LV2_STATE__freePath;
355         fFeatures[kFeatureIdStateFreePath]->data = stateFreePathFt;
356 
357         fFeatures[kFeatureIdStateMakePath]->URI  = LV2_STATE__makePath;
358         fFeatures[kFeatureIdStateMakePath]->data = stateMakePathFt;
359 
360         fFeatures[kFeatureIdStateMapPath]->URI   = LV2_STATE__mapPath;
361         fFeatures[kFeatureIdStateMapPath]->data  = stateMapPathFt;
362 
363         fFeatures[kFeatureIdUriMap]->URI     = LV2_URI_MAP_URI;
364         fFeatures[kFeatureIdUriMap]->data    = uriMapFt;
365 
366         fFeatures[kFeatureIdUridMap]->URI    = LV2_URID__map;
367         fFeatures[kFeatureIdUridMap]->data   = uridMapFt;
368 
369         fFeatures[kFeatureIdUridUnmap]->URI  = LV2_URID__unmap;
370         fFeatures[kFeatureIdUridUnmap]->data = uridUnmapFt;
371 
372         fFeatures[kFeatureIdUiIdleInterface]->URI  = LV2_UI__idleInterface;
373         fFeatures[kFeatureIdUiIdleInterface]->data = nullptr;
374 
375         fFeatures[kFeatureIdUiFixedSize]->URI      = LV2_UI__fixedSize;
376         fFeatures[kFeatureIdUiFixedSize]->data     = nullptr;
377 
378         fFeatures[kFeatureIdUiMakeResident]->URI   = LV2_UI__makeResident;
379         fFeatures[kFeatureIdUiMakeResident]->data  = nullptr;
380 
381         fFeatures[kFeatureIdUiMakeResident2]->URI  = LV2_UI__makeSONameResident;
382         fFeatures[kFeatureIdUiMakeResident2]->data = nullptr;
383 
384         fFeatures[kFeatureIdUiNoUserResize]->URI   = LV2_UI__noUserResize;
385         fFeatures[kFeatureIdUiNoUserResize]->data  = nullptr;
386 
387         fFeatures[kFeatureIdUiParent]->URI         = LV2_UI__parent;
388         fFeatures[kFeatureIdUiParent]->data        = nullptr;
389 
390         fFeatures[kFeatureIdUiPortMap]->URI        = LV2_UI__portMap;
391         fFeatures[kFeatureIdUiPortMap]->data       = uiPortMapFt;
392 
393         fFeatures[kFeatureIdUiPortSubscribe]->URI  = LV2_UI__portSubscribe;
394         fFeatures[kFeatureIdUiPortSubscribe]->data = nullptr;
395 
396         fFeatures[kFeatureIdUiRequestValue]->URI  = LV2_UI__requestValue;
397         fFeatures[kFeatureIdUiRequestValue]->data = uiRequestValueFt;
398 
399         fFeatures[kFeatureIdUiResize]->URI  = LV2_UI__resize;
400         fFeatures[kFeatureIdUiResize]->data = uiResizeFt;
401 
402         fFeatures[kFeatureIdUiTouch]->URI   = LV2_UI__touch;
403         fFeatures[kFeatureIdUiTouch]->data  = nullptr;
404     }
405 
~CarlaLv2Client()406     ~CarlaLv2Client() override
407     {
408         if (fHandle != nullptr && fDescriptor != nullptr && fDescriptor->cleanup != nullptr)
409         {
410             fDescriptor->cleanup(fHandle);
411             fHandle = nullptr;
412         }
413 
414         if (fRdfDescriptor != nullptr)
415         {
416             delete fRdfDescriptor;
417             fRdfDescriptor = nullptr;
418         }
419 
420         fRdfUiDescriptor = nullptr;
421 
422         delete (LV2_Log_Log*)fFeatures[kFeatureIdLogs]->data;
423         delete (LV2_State_Free_Path*)fFeatures[kFeatureIdStateFreePath]->data;
424         delete (LV2_State_Make_Path*)fFeatures[kFeatureIdStateMakePath]->data;
425         delete (LV2_State_Map_Path*)fFeatures[kFeatureIdStateMapPath]->data;
426         delete (LV2_Programs_Host*)fFeatures[kFeatureIdPrograms]->data;
427         delete (LV2_URI_Map_Feature*)fFeatures[kFeatureIdUriMap]->data;
428         delete (LV2_URID_Map*)fFeatures[kFeatureIdUridMap]->data;
429         delete (LV2_URID_Unmap*)fFeatures[kFeatureIdUridUnmap]->data;
430         delete (LV2UI_Port_Map*)fFeatures[kFeatureIdUiPortMap]->data;
431         delete (LV2UI_Request_Value*)fFeatures[kFeatureIdUiRequestValue]->data;
432         delete (LV2UI_Resize*)fFeatures[kFeatureIdUiResize]->data;
433 
434         for (uint32_t i=0; i < kFeatureCount; ++i)
435         {
436             if (fFeatures[i] != nullptr)
437             {
438                 delete fFeatures[i];
439                 fFeatures[i] = nullptr;
440             }
441         }
442     }
443 
444     // ----------------------------------------------------------------------------------------------------------------
445     // UI initialization
446 
init(const int argc,const char * argv[])447     bool init(const int argc, const char* argv[]) override
448     {
449         const char* pluginURI = argv[1];
450         const char* uiURI     = argc > 2 ? argv[2] : nullptr;
451 
452         // ------------------------------------------------------------------------------------------------------------
453         // load plugin
454 
455         Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
456         lv2World.initIfNeeded(std::getenv("LV2_PATH"));
457 
458 #if 0
459         Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, uiBundle));
460         CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(), false);
461 
462         CarlaString sBundle(bundleNode.as_uri());
463 
464         if (! sBundle.endsWith("/"))
465            sBundle += "/";
466 
467         lv2World.load_bundle(sBundle);
468 #endif
469 
470         // ------------------------------------------------------------------------------------------------------------
471         // get plugin from lv2_rdf (lilv)
472 
473         fRdfDescriptor = lv2_rdf_new(pluginURI, false);
474         CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor != nullptr, false);
475 
476         // ------------------------------------------------------------------------------------------------------------
477         // find requested UI
478 
479         if (uiURI == nullptr)
480         {
481             CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor->UICount > 0, false);
482 
483             fRdfUiDescriptor = &fRdfDescriptor->UIs[0];
484             uiURI = fRdfUiDescriptor->URI;
485         }
486         else
487         {
488             for (uint32_t i=0; i < fRdfDescriptor->UICount; ++i)
489             {
490                 if (std::strcmp(fRdfDescriptor->UIs[i].URI, uiURI) == 0)
491                 {
492                     fRdfUiDescriptor = &fRdfDescriptor->UIs[i];
493                     break;
494                 }
495             }
496         }
497 
498         CARLA_SAFE_ASSERT_RETURN(fRdfUiDescriptor != nullptr, false);
499 
500         // ------------------------------------------------------------------------------------------------------------
501         // check if not resizable
502 
503         for (uint32_t i=0; i < fRdfUiDescriptor->FeatureCount; ++i)
504         {
505             if (std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__fixedSize   ) == 0 ||
506                 std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__noUserResize) == 0)
507             {
508                 fUiOptions.isResizable = false;
509                 break;
510             }
511         }
512 
513         // ------------------------------------------------------------------------------------------------------------
514         // init UI
515 
516         if (! CarlaBridgeFormat::init(argc, argv))
517             return false;
518 
519         // ------------------------------------------------------------------------------------------------------------
520         // open DLL
521 
522 #ifdef CARLA_OS_MAC
523         // Binary might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
524         CarlaBackend::removeFileFromQuarantine(fRdfUiDescriptor->Binary);
525 #endif
526 
527         if (! libOpen(fRdfUiDescriptor->Binary))
528         {
529             carla_stderr("Failed to load UI binary, error was:\n%s", libError());
530             return false;
531         }
532 
533         // ------------------------------------------------------------------------------------------------------------
534         // get DLL main entry
535 
536         const LV2UI_DescriptorFunction ui_descFn = (LV2UI_DescriptorFunction)libSymbol("lv2ui_descriptor");
537 
538         if (ui_descFn == nullptr)
539             return false;
540 
541         // ------------------------------------------------------------------------------------------------------------
542         // get descriptor that matches URI
543 
544         for (uint32_t i=0; (fDescriptor = ui_descFn(i++)) != nullptr;)
545         {
546             if (std::strcmp(fDescriptor->URI, uiURI) == 0)
547                 break;
548         }
549 
550         if (fDescriptor == nullptr)
551         {
552             carla_stderr("Failed to find UI descriptor");
553             return false;
554         }
555 
556         // ------------------------------------------------------------------------------------------------------------
557         // initialize UI
558 
559 #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
560         fFeatures[kFeatureIdUiParent]->data = fToolkit->getContainerId();
561 #endif
562 
563         fHandle = fDescriptor->instantiate(fDescriptor, fRdfDescriptor->URI, fRdfUiDescriptor->Bundle,
564                                            carla_lv2_ui_write_function, this, &fWidget, fFeatures);
565         CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
566 
567 #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
568         if (fWidget != nullptr)
569             fToolkit->setChildWindow(fWidget);
570 #endif
571 
572         // ------------------------------------------------------------------------------------------------------------
573         // check for known extensions
574 
575         if (fDescriptor->extension_data != nullptr)
576         {
577             fExt.options  = (const LV2_Options_Interface*)fDescriptor->extension_data(LV2_OPTIONS__interface);
578             fExt.programs = (const LV2_Programs_UI_Interface*)fDescriptor->extension_data(LV2_PROGRAMS__UIInterface);
579             fExt.idle     = (const LV2UI_Idle_Interface*)fDescriptor->extension_data(LV2_UI__idleInterface);
580             fExt.resize   = (const LV2UI_Resize*)fDescriptor->extension_data(LV2_UI__resize);
581 
582             // check if invalid
583             if (fExt.programs != nullptr && fExt.programs->select_program == nullptr)
584                 fExt.programs = nullptr;
585             if (fExt.idle != nullptr && fExt.idle->idle == nullptr)
586                 fExt.idle = nullptr;
587             if (fExt.resize != nullptr && fExt.resize->ui_resize == nullptr)
588                 fExt.resize = nullptr;
589         }
590 
591         for (uint32_t i=0; i<fRdfDescriptor->PortCount; ++i)
592         {
593             if (LV2_IS_PORT_DESIGNATION_CONTROL(fRdfDescriptor->Ports[i].Designation))
594             {
595                 fControlDesignatedPort = i;
596                 break;
597             }
598         }
599 
600         return true;
601     }
602 
idleUI()603     void idleUI() override
604     {
605 #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
606         if (fHandle != nullptr && fExt.idle != nullptr && fExt.idle->idle(fHandle) != 0)
607         {
608             if (isPipeRunning() && ! fQuitReceived)
609                 writeExitingMessageAndWait();
610         }
611 #endif
612     }
613 
614     // ----------------------------------------------------------------------------------------------------------------
615     // UI management
616 
getWidget() const617     void* getWidget() const noexcept override
618     {
619         return fWidget;
620     }
621 
getOptions() const622     const Options& getOptions() const noexcept override
623     {
624         return fUiOptions;
625     }
626 
627     // ----------------------------------------------------------------------------------------------------------------
628     // DSP Callbacks
629 
dspParameterChanged(const uint32_t index,const float value)630     void dspParameterChanged(const uint32_t index, const float value) override
631     {
632         CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
633         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
634 
635         if (fDescriptor->port_event == nullptr)
636             return;
637 
638         fDescriptor->port_event(fHandle, index, sizeof(float), kUridNull, &value);
639     }
640 
dspParameterChanged(const char * const uri,const float value)641     void dspParameterChanged(const char* const uri, const float value) override
642     {
643         CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
644         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
645 
646         if (fDescriptor->port_event == nullptr)
647             return;
648 
649         uint32_t parameterId = UINT32_MAX;
650 
651         for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
652         {
653             const LV2_RDF_Parameter& rdfParam(fRdfDescriptor->Parameters[i]);
654 
655             if (std::strcmp(rdfParam.URI, uri) == 0)
656             {
657                 parameterId = i;
658                 break;
659             }
660         }
661 
662         if (parameterId == UINT32_MAX)
663             return;
664 
665         uint8_t atomBuf[256];
666         LV2_Atom_Forge atomForge;
667         initAtomForge(atomForge);
668         lv2_atom_forge_set_buffer(&atomForge, atomBuf, sizeof(atomBuf));
669 
670         LV2_Atom_Forge_Frame forgeFrame;
671         lv2_atom_forge_object(&atomForge, &forgeFrame, kUridNull, kUridPatchSet);
672 
673         lv2_atom_forge_key(&atomForge, kUridCarlaParameterChange);
674         lv2_atom_forge_bool(&atomForge, true);
675 
676         lv2_atom_forge_key(&atomForge, kUridPatchProperty);
677         lv2_atom_forge_urid(&atomForge, getCustomURID(uri));
678 
679         lv2_atom_forge_key(&atomForge, kUridPatchValue);
680 
681         switch (fRdfDescriptor->Parameters[parameterId].Type)
682         {
683         case LV2_PARAMETER_TYPE_BOOL:
684             lv2_atom_forge_bool(&atomForge, value > 0.5f);
685             break;
686         case LV2_PARAMETER_TYPE_INT:
687             lv2_atom_forge_int(&atomForge, static_cast<int32_t>(value + 0.5f));
688             break;
689         case LV2_PARAMETER_TYPE_LONG:
690             lv2_atom_forge_long(&atomForge, static_cast<int64_t>(value + 0.5f));
691             break;
692         case LV2_PARAMETER_TYPE_FLOAT:
693             lv2_atom_forge_float(&atomForge, value);
694             break;
695         case LV2_PARAMETER_TYPE_DOUBLE:
696             lv2_atom_forge_double(&atomForge, value);
697             break;
698         default:
699             carla_stderr2("dspParameterChanged called for invalid parameter, abort!");
700             return;
701         }
702 
703         lv2_atom_forge_pop(&atomForge, &forgeFrame);
704 
705         LV2_Atom* const atom((LV2_Atom*)atomBuf);
706         CARLA_SAFE_ASSERT(atom->size < sizeof(atomBuf));
707 
708         fDescriptor->port_event(fHandle,
709                                 fControlDesignatedPort,
710                                 lv2_atom_total_size(atom),
711                                 kUridAtomTransferEvent,
712                                 atom);
713     }
714 
dspProgramChanged(const uint32_t index)715     void dspProgramChanged(const uint32_t index) override
716     {
717         carla_stderr2("dspProgramChanged(%i) - not handled", index);
718     }
719 
dspMidiProgramChanged(const uint32_t bank,const uint32_t program)720     void dspMidiProgramChanged(const uint32_t bank, const uint32_t program) override
721     {
722         CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
723 
724         if (fExt.programs == nullptr)
725             return;
726 
727         fExt.programs->select_program(fHandle, bank, program);
728     }
729 
dspStateChanged(const char * const,const char * const)730     void dspStateChanged(const char* const, const char* const) override
731     {
732     }
733 
dspNoteReceived(const bool onOff,const uint8_t channel,const uint8_t note,const uint8_t velocity)734     void dspNoteReceived(const bool onOff, const uint8_t channel, const uint8_t note, const uint8_t velocity) override
735     {
736         CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
737         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
738 
739         if (fDescriptor->port_event == nullptr)
740             return;
741 
742         LV2_Atom_MidiEvent midiEv;
743         midiEv.atom.type = kUridMidiEvent;
744         midiEv.atom.size = 3;
745         midiEv.data[0] = uint8_t((onOff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (channel & MIDI_CHANNEL_BIT));
746         midiEv.data[1] = note;
747         midiEv.data[2] = velocity;
748 
749         fDescriptor->port_event(fHandle, fControlDesignatedPort, lv2_atom_total_size(midiEv), kUridAtomTransferEvent, &midiEv);
750     }
751 
dspAtomReceived(const uint32_t portIndex,const LV2_Atom * const atom)752     void dspAtomReceived(const uint32_t portIndex, const LV2_Atom* const atom) override
753     {
754         CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
755         CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
756         CARLA_SAFE_ASSERT_RETURN(atom != nullptr,);
757 
758         if (fDescriptor->port_event == nullptr)
759             return;
760 
761         fDescriptor->port_event(fHandle, portIndex, lv2_atom_total_size(atom), kUridAtomTransferEvent, atom);
762     }
763 
dspURIDReceived(const LV2_URID urid,const char * const uri)764     void dspURIDReceived(const LV2_URID urid, const char* const uri) override
765     {
766         CARLA_SAFE_ASSERT_RETURN(urid == fCustomURIDs.size(),);
767         CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0',);
768 
769         fCustomURIDs.push_back(uri);
770     }
771 
uiOptionsChanged(const BridgeFormatOptions & opts)772     void uiOptionsChanged(const BridgeFormatOptions& opts) override
773     {
774         carla_debug("CarlaLv2Client::uiOptionsChanged()");
775 
776         // ------------------------------------------------------------------------------------------------------------
777         // sample rate
778 
779         const float sampleRatef = static_cast<float>(opts.sampleRate);
780 
781         if (carla_isNotEqual(fLv2Options.sampleRate, sampleRatef))
782         {
783             fLv2Options.sampleRate = sampleRatef;
784 
785             if (fExt.options != nullptr && fExt.options->set != nullptr)
786             {
787                 LV2_Options_Option options[2];
788                 carla_zeroStructs(options, 2);
789 
790                 LV2_Options_Option& optSampleRate(options[0]);
791                 optSampleRate.context = LV2_OPTIONS_INSTANCE;
792                 optSampleRate.subject = 0;
793                 optSampleRate.key     = kUridParamSampleRate;
794                 optSampleRate.size    = sizeof(float);
795                 optSampleRate.type    = kUridAtomFloat;
796                 optSampleRate.value   = &fLv2Options.sampleRate;
797 
798                 fExt.options->set(fHandle, options);
799             }
800         }
801 
802         // ------------------------------------------------------------------------------------------------------------
803         // ui colors and scale
804 
805         fLv2Options.bgColor = opts.bgColor;
806         fLv2Options.fgColor = opts.fgColor;
807         fLv2Options.uiScale = opts.uiScale;
808 
809         // ------------------------------------------------------------------------------------------------------------
810         // window title
811 
812         if (opts.windowTitle != nullptr)
813             fUiOptions.windowTitle = opts.windowTitle;
814         else
815             fUiOptions.windowTitle.clear();
816 
817         fLv2Options.opts[Lv2PluginOptions::WindowTitle].size  = static_cast<uint32_t>(fUiOptions.windowTitle.length());
818         fLv2Options.opts[Lv2PluginOptions::WindowTitle].value = fUiOptions.windowTitle.buffer();
819 
820         // ------------------------------------------------------------------------------------------------------------
821         // transient win id
822 
823         fLv2Options.transientWinId = static_cast<int64_t>(opts.transientWindowId);
824         fUiOptions.transientWindowId = opts.transientWindowId;
825 
826         // ------------------------------------------------------------------------------------------------------------
827         // other
828 
829         fUiOptions.isStandalone   = opts.isStandalone;
830         fUiOptions.useTheme       = opts.useTheme;
831         fUiOptions.useThemeColors = opts.useThemeColors;
832     }
833 
setScaleFactor(const double scaleFactor)834     void setScaleFactor(const double scaleFactor) override
835     {
836         fLv2Options.uiScale = static_cast<float>(scaleFactor);
837     }
838 
uiResized(const uint width,const uint height)839     void uiResized(const uint width, const uint height) override
840     {
841         if (fHandle != nullptr && fExt.resize != nullptr)
842             fExt.resize->ui_resize(fHandle, static_cast<int>(width), static_cast<int>(height));
843     }
844 
845     // ----------------------------------------------------------------------------------------------------------------
846 
getCustomURID(const char * const uri)847     LV2_URID getCustomURID(const char* const uri)
848     {
849         CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', kUridNull);
850         carla_debug("CarlaLv2Client::getCustomURID(\"%s\")", uri);
851 
852         const std::string    s_uri(uri);
853         const std::ptrdiff_t s_pos(std::find(fCustomURIDs.begin(), fCustomURIDs.end(), s_uri) - fCustomURIDs.begin());
854 
855         if (s_pos <= 0 || s_pos >= INT32_MAX)
856             return kUridNull;
857 
858         const LV2_URID urid     = static_cast<LV2_URID>(s_pos);
859         const LV2_URID uriCount = static_cast<LV2_URID>(fCustomURIDs.size());
860 
861         if (urid < uriCount)
862             return urid;
863 
864         CARLA_SAFE_ASSERT(urid == uriCount);
865 
866         fCustomURIDs.push_back(uri);
867 
868         if (isPipeRunning())
869             writeLv2UridMessage(urid, uri);
870 
871         return urid;
872     }
873 
getCustomURIDString(const LV2_URID urid) const874     const char* getCustomURIDString(const LV2_URID urid) const noexcept
875     {
876         CARLA_SAFE_ASSERT_RETURN(urid != kUridNull, kUnmapFallback);
877         CARLA_SAFE_ASSERT_RETURN(urid < fCustomURIDs.size(), kUnmapFallback);
878         carla_debug("CarlaLv2Client::getCustomURIDString(%i)", urid);
879 
880         return fCustomURIDs[urid].c_str();
881     }
882 
883     // ----------------------------------------------------------------------------------------------------------------
884 
handleProgramChanged(const int32_t index)885     void handleProgramChanged(const int32_t index)
886     {
887         if (isPipeRunning())
888             writeReloadProgramsMessage(index);
889     }
890 
handleUiPortMap(const char * const symbol)891     uint32_t handleUiPortMap(const char* const symbol)
892     {
893         CARLA_SAFE_ASSERT_RETURN(symbol != nullptr && symbol[0] != '\0', LV2UI_INVALID_PORT_INDEX);
894         carla_debug("CarlaLv2Client::handleUiPortMap(\"%s\")", symbol);
895 
896         for (uint32_t i=0; i < fRdfDescriptor->PortCount; ++i)
897         {
898             if (std::strcmp(fRdfDescriptor->Ports[i].Symbol, symbol) == 0)
899                 return i;
900         }
901 
902         return LV2UI_INVALID_PORT_INDEX;
903     }
904 
905     // ----------------------------------------------------------------------------------------------------------------
906 
handleStateMapToAbstractPath(const char * const absolutePath)907     char* handleStateMapToAbstractPath(const char* const absolutePath)
908     {
909         // may already be an abstract path
910         if (! File::isAbsolutePath(absolutePath))
911             return strdup(absolutePath);
912 
913         return strdup(File(absolutePath).getRelativePathFrom(File::getCurrentWorkingDirectory()).toRawUTF8());
914     }
915 
handleStateMapToAbsolutePath(const bool createDir,const char * const abstractPath)916     char* handleStateMapToAbsolutePath(const bool createDir, const char* const abstractPath)
917     {
918         File target;
919 
920         if (File::isAbsolutePath(abstractPath))
921         {
922             target = abstractPath;
923         }
924         else
925         {
926             target = File::getCurrentWorkingDirectory().getChildFile(abstractPath);
927         }
928 
929         if (createDir)
930         {
931             File dir(target.getParentDirectory());
932             if (! dir.exists())
933                 dir.createDirectory();
934         }
935 
936         return strdup(target.getFullPathName().toRawUTF8());
937     }
938 
939     // ----------------------------------------------------------------------------------------------------------------
940 
handleUiRequestValue(const LV2_URID key,const LV2_URID type,const LV2_Feature * const * features)941     LV2UI_Request_Value_Status handleUiRequestValue(const LV2_URID key,
942                                                     const LV2_URID type,
943                                                     const LV2_Feature* const* features)
944     {
945         CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
946         carla_debug("CarlaLv2Client::handleUIRequestValue(%u, %u, %p)", key, type, features);
947 
948         if (type != kUridAtomPath)
949             return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
950 
951         const char* const uri = getCustomURIDString(key);
952         CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri != kUnmapFallback, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
953 
954         // TODO check if a file browser is already open
955 
956         for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
957         {
958             if (fRdfDescriptor->Parameters[i].Type != LV2_PARAMETER_TYPE_PATH)
959                 continue;
960             if (std::strcmp(fRdfDescriptor->Parameters[i].URI, uri) != 0)
961                 continue;
962 
963             // TODO file browser filters, also label for title
964             if (isPipeRunning())
965             {
966                 char tmpBuf[0xff];
967 
968                 const CarlaMutexLocker cml(getPipeLock());
969 
970                 writeMessage("requestvalue\n", 13);
971 
972                 std::snprintf(tmpBuf, 0xff-1, "%u\n", key);
973                 tmpBuf[0xff-1] = '\0';
974                 writeMessage(tmpBuf);
975 
976                 std::snprintf(tmpBuf, 0xff-1, "%u\n", type);
977                 tmpBuf[0xff-1] = '\0';
978                 writeMessage(tmpBuf);
979             }
980 
981             return LV2UI_REQUEST_VALUE_SUCCESS;
982         }
983 
984         return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
985 
986         // may be unused
987         (void)features;
988     }
989 
handleUiResize(const int width,const int height)990     int handleUiResize(const int width, const int height)
991     {
992         CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, 1);
993         CARLA_SAFE_ASSERT_RETURN(width > 0, 1);
994         CARLA_SAFE_ASSERT_RETURN(height > 0, 1);
995         carla_debug("CarlaLv2Client::handleUiResize(%i, %i)", width, height);
996 
997         fToolkit->setSize(static_cast<uint>(width), static_cast<uint>(height));
998         return 0;
999     }
1000 
handleUiWrite(uint32_t rindex,uint32_t bufferSize,uint32_t format,const void * buffer)1001     void handleUiWrite(uint32_t rindex, uint32_t bufferSize, uint32_t format, const void* buffer)
1002     {
1003         CARLA_SAFE_ASSERT_RETURN(buffer != nullptr,);
1004         CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);
1005         carla_debug("CarlaLv2Client::handleUiWrite(%i, %i, %i, %p)", rindex, bufferSize, format, buffer);
1006 
1007         switch (format)
1008         {
1009         case kUridNull:
1010             CARLA_SAFE_ASSERT_RETURN(bufferSize == sizeof(float),);
1011 
1012             if (isPipeRunning())
1013             {
1014                 const float value(*(const float*)buffer);
1015                 writeControlMessage(rindex, value);
1016             }
1017             break;
1018 
1019         case kUridAtomTransferAtom:
1020         case kUridAtomTransferEvent:
1021             CARLA_SAFE_ASSERT_RETURN(bufferSize >= sizeof(LV2_Atom),);
1022 
1023             if (isPipeRunning())
1024             {
1025                 const LV2_Atom* const atom((const LV2_Atom*)buffer);
1026 
1027                 // plugins sometimes fail on this, not good...
1028                 const uint32_t totalSize = lv2_atom_total_size(atom);
1029                 const uint32_t paddedSize = lv2_atom_pad_size(totalSize);
1030 
1031                 if (bufferSize != totalSize && bufferSize != paddedSize)
1032                     carla_stderr2("Warning: LV2 UI sending atom with invalid size %u! size: %u, padded-size: %u",
1033                                   bufferSize, totalSize, paddedSize);
1034 
1035                 writeLv2AtomMessage(rindex, atom);
1036             }
1037             break;
1038 
1039         default:
1040             carla_stderr("CarlaLv2Client::handleUiWrite(%i, %i, %i:\"%s\", %p) - unknown format",
1041                          rindex, bufferSize, format, carla_lv2_urid_unmap(this, format), buffer);
1042             break;
1043         }
1044     }
1045 
1046     // ----------------------------------------------------------------------------------------------------------------
1047 
1048 private:
1049     LV2UI_Handle fHandle;
1050     LV2UI_Widget fWidget;
1051     LV2_Feature* fFeatures[kFeatureCount+1];
1052 
1053     const LV2UI_Descriptor*   fDescriptor;
1054     const LV2_RDF_Descriptor* fRdfDescriptor;
1055     const LV2_RDF_UI*         fRdfUiDescriptor;
1056     uint32_t                  fControlDesignatedPort;
1057     Lv2PluginOptions          fLv2Options;
1058 
1059     Options fUiOptions;
1060     std::vector<std::string> fCustomURIDs;
1061 
1062     struct Extensions {
1063         const LV2_Options_Interface* options;
1064         const LV2_Programs_UI_Interface* programs;
1065         const LV2UI_Idle_Interface* idle;
1066         const LV2UI_Resize* resize;
1067 
ExtensionsCarlaLv2Client::Extensions1068         Extensions()
1069             : options(nullptr),
1070               programs(nullptr),
1071               idle(nullptr),
1072               resize(nullptr) {}
1073     } fExt;
1074 
1075     // ----------------------------------------------------------------------------------------------------------------
1076     // Logs Feature
1077 
carla_lv2_log_printf(LV2_Log_Handle handle,LV2_URID type,const char * fmt,...)1078     static int carla_lv2_log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...)
1079     {
1080         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
1081         CARLA_SAFE_ASSERT_RETURN(type != kUridNull, 0);
1082         CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
1083 
1084 #ifndef DEBUG
1085         if (type == kUridLogTrace)
1086             return 0;
1087 #endif
1088 
1089         va_list args;
1090         va_start(args, fmt);
1091         const int ret(carla_lv2_log_vprintf(handle, type, fmt, args));
1092         va_end(args);
1093 
1094         return ret;
1095     }
1096 
carla_lv2_log_vprintf(LV2_Log_Handle handle,LV2_URID type,const char * fmt,va_list ap)1097     static int carla_lv2_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list ap)
1098     {
1099         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
1100         CARLA_SAFE_ASSERT_RETURN(type != kUridNull, 0);
1101         CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
1102 
1103         int ret = 0;
1104 
1105         switch (type)
1106         {
1107         case kUridLogError:
1108             std::fprintf(stderr, "\x1b[31m");
1109             ret = std::vfprintf(stderr, fmt, ap);
1110             std::fprintf(stderr, "\x1b[0m");
1111             break;
1112 
1113         case kUridLogNote:
1114             ret = std::vfprintf(stdout, fmt, ap);
1115             break;
1116 
1117         case kUridLogTrace:
1118 #ifdef DEBUG
1119             std::fprintf(stdout, "\x1b[30;1m");
1120             ret = std::vfprintf(stdout, fmt, ap);
1121             std::fprintf(stdout, "\x1b[0m");
1122 #endif
1123             break;
1124 
1125         case kUridLogWarning:
1126             ret = std::vfprintf(stderr, fmt, ap);
1127             break;
1128 
1129         default:
1130             break;
1131         }
1132 
1133         return ret;
1134     }
1135 
1136     // ----------------------------------------------------------------------------------------------------------------
1137     // Programs Feature
1138 
carla_lv2_program_changed(LV2_Programs_Handle handle,int32_t index)1139     static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index)
1140     {
1141         CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1142         carla_debug("carla_lv2_program_changed(%p, %i)", handle, index);
1143 
1144         ((CarlaLv2Client*)handle)->handleProgramChanged(index);
1145     }
1146 
1147     // ----------------------------------------------------------------------------------------------------------------
1148     // State Feature
1149 
carla_lv2_state_free_path(LV2_State_Free_Path_Handle handle,char * path)1150     static void carla_lv2_state_free_path(LV2_State_Free_Path_Handle handle, char* path)
1151     {
1152         CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1153         carla_debug("carla_lv2_state_free_path(%p, \"%s\")", handle, path);
1154 
1155         std::free(path);
1156     }
1157 
carla_lv2_state_make_path_tmp(LV2_State_Make_Path_Handle handle,const char * path)1158     static char* carla_lv2_state_make_path_tmp(LV2_State_Make_Path_Handle handle, const char* path)
1159     {
1160         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1161         CARLA_SAFE_ASSERT_RETURN(path != nullptr && path[0] != '\0', nullptr);
1162         carla_debug("carla_lv2_state_make_path_tmp(%p, \"%s\")", handle, path);
1163 
1164         return ((CarlaLv2Client*)handle)->handleStateMapToAbsolutePath(true, path);
1165     }
1166 
carla_lv2_state_map_abstract_path_tmp(LV2_State_Map_Path_Handle handle,const char * absolute_path)1167     static char* carla_lv2_state_map_abstract_path_tmp(LV2_State_Map_Path_Handle handle, const char* absolute_path)
1168     {
1169         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1170         CARLA_SAFE_ASSERT_RETURN(absolute_path != nullptr && absolute_path[0] != '\0', nullptr);
1171         carla_debug("carla_lv2_state_map_abstract_path_tmp(%p, \"%s\")", handle, absolute_path);
1172 
1173         return ((CarlaLv2Client*)handle)->handleStateMapToAbstractPath(absolute_path);
1174     }
1175 
carla_lv2_state_map_absolute_path_tmp(LV2_State_Map_Path_Handle handle,const char * abstract_path)1176     static char* carla_lv2_state_map_absolute_path_tmp(LV2_State_Map_Path_Handle handle, const char* abstract_path)
1177     {
1178         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1179         CARLA_SAFE_ASSERT_RETURN(abstract_path != nullptr && abstract_path[0] != '\0', nullptr);
1180         carla_debug("carla_lv2_state_map_absolute_path_tmp(%p, \"%s\")", handle, abstract_path);
1181 
1182         return ((CarlaLv2Client*)handle)->handleStateMapToAbsolutePath(false, abstract_path);
1183     }
1184 
1185     // ----------------------------------------------------------------------------------------------------------------
1186     // URI-Map Feature
1187 
carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data,const char * map,const char * uri)1188     static uint32_t carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char* map, const char* uri)
1189     {
1190         carla_debug("carla_lv2_uri_to_id(%p, \"%s\", \"%s\")", data, map, uri);
1191         return carla_lv2_urid_map((LV2_URID_Map_Handle*)data, uri);
1192 
1193         // unused
1194         (void)map;
1195     }
1196 
1197     // ----------------------------------------------------------------------------------------------------------------
1198     // URID Feature
1199 
carla_lv2_urid_map(LV2_URID_Map_Handle handle,const char * uri)1200     static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri)
1201     {
1202         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, kUridNull);
1203         CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', kUridNull);
1204         carla_debug("carla_lv2_urid_map(%p, \"%s\")", handle, uri);
1205 
1206         // Atom types
1207         if (std::strcmp(uri, LV2_ATOM__Blank) == 0)
1208             return kUridAtomBlank;
1209         if (std::strcmp(uri, LV2_ATOM__Bool) == 0)
1210             return kUridAtomBool;
1211         if (std::strcmp(uri, LV2_ATOM__Chunk) == 0)
1212             return kUridAtomChunk;
1213         if (std::strcmp(uri, LV2_ATOM__Double) == 0)
1214             return kUridAtomDouble;
1215         if (std::strcmp(uri, LV2_ATOM__Event) == 0)
1216             return kUridAtomEvent;
1217         if (std::strcmp(uri, LV2_ATOM__Float) == 0)
1218             return kUridAtomFloat;
1219         if (std::strcmp(uri, LV2_ATOM__Int) == 0)
1220             return kUridAtomInt;
1221         if (std::strcmp(uri, LV2_ATOM__Literal) == 0)
1222             return kUridAtomLiteral;
1223         if (std::strcmp(uri, LV2_ATOM__Long) == 0)
1224             return kUridAtomLong;
1225         if (std::strcmp(uri, LV2_ATOM__Number) == 0)
1226             return kUridAtomNumber;
1227         if (std::strcmp(uri, LV2_ATOM__Object) == 0)
1228             return kUridAtomObject;
1229         if (std::strcmp(uri, LV2_ATOM__Path) == 0)
1230             return kUridAtomPath;
1231         if (std::strcmp(uri, LV2_ATOM__Property) == 0)
1232             return kUridAtomProperty;
1233         if (std::strcmp(uri, LV2_ATOM__Resource) == 0)
1234             return kUridAtomResource;
1235         if (std::strcmp(uri, LV2_ATOM__Sequence) == 0)
1236             return kUridAtomSequence;
1237         if (std::strcmp(uri, LV2_ATOM__Sound) == 0)
1238             return kUridAtomSound;
1239         if (std::strcmp(uri, LV2_ATOM__String) == 0)
1240             return kUridAtomString;
1241         if (std::strcmp(uri, LV2_ATOM__Tuple) == 0)
1242             return kUridAtomTuple;
1243         if (std::strcmp(uri, LV2_ATOM__URI) == 0)
1244             return kUridAtomURI;
1245         if (std::strcmp(uri, LV2_ATOM__URID) == 0)
1246             return kUridAtomURID;
1247         if (std::strcmp(uri, LV2_ATOM__Vector) == 0)
1248             return kUridAtomVector;
1249         if (std::strcmp(uri, LV2_ATOM__atomTransfer) == 0)
1250             return kUridAtomTransferAtom;
1251         if (std::strcmp(uri, LV2_ATOM__eventTransfer) == 0)
1252             return kUridAtomTransferEvent;
1253 
1254         // BufSize types
1255         if (std::strcmp(uri, LV2_BUF_SIZE__maxBlockLength) == 0)
1256             return kUridBufMaxLength;
1257         if (std::strcmp(uri, LV2_BUF_SIZE__minBlockLength) == 0)
1258             return kUridBufMinLength;
1259         if (std::strcmp(uri, LV2_BUF_SIZE__nominalBlockLength) == 0)
1260             return kUridBufNominalLength;
1261         if (std::strcmp(uri, LV2_BUF_SIZE__sequenceSize) == 0)
1262             return kUridBufSequenceSize;
1263 
1264         // Log types
1265         if (std::strcmp(uri, LV2_LOG__Error) == 0)
1266             return kUridLogError;
1267         if (std::strcmp(uri, LV2_LOG__Note) == 0)
1268             return kUridLogNote;
1269         if (std::strcmp(uri, LV2_LOG__Trace) == 0)
1270             return kUridLogTrace;
1271         if (std::strcmp(uri, LV2_LOG__Warning) == 0)
1272             return kUridLogWarning;
1273 
1274         // Patch types
1275         if (std::strcmp(uri, LV2_PATCH__Set) == 0)
1276             return kUridPatchSet;
1277         if (std::strcmp(uri, LV2_PATCH__property) == 0)
1278             return kUridPatchProperty;
1279         if (std::strcmp(uri, LV2_PATCH__subject) == 0)
1280             return kUridPatchSubject;
1281         if (std::strcmp(uri, LV2_PATCH__value) == 0)
1282             return kUridPatchValue;
1283 
1284         // Time types
1285         if (std::strcmp(uri, LV2_TIME__Position) == 0)
1286             return kUridTimePosition;
1287         if (std::strcmp(uri, LV2_TIME__bar) == 0)
1288             return kUridTimeBar;
1289         if (std::strcmp(uri, LV2_TIME__barBeat) == 0)
1290             return kUridTimeBarBeat;
1291         if (std::strcmp(uri, LV2_TIME__beat) == 0)
1292             return kUridTimeBeat;
1293         if (std::strcmp(uri, LV2_TIME__beatUnit) == 0)
1294             return kUridTimeBeatUnit;
1295         if (std::strcmp(uri, LV2_TIME__beatsPerBar) == 0)
1296             return kUridTimeBeatsPerBar;
1297         if (std::strcmp(uri, LV2_TIME__beatsPerMinute) == 0)
1298             return kUridTimeBeatsPerMinute;
1299         if (std::strcmp(uri, LV2_TIME__frame) == 0)
1300             return kUridTimeFrame;
1301         if (std::strcmp(uri, LV2_TIME__framesPerSecond) == 0)
1302             return kUridTimeFramesPerSecond;
1303         if (std::strcmp(uri, LV2_TIME__speed) == 0)
1304             return kUridTimeSpeed;
1305         if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
1306             return kUridTimeTicksPerBeat;
1307 
1308         // Others
1309         if (std::strcmp(uri, LV2_MIDI__MidiEvent) == 0)
1310             return kUridMidiEvent;
1311         if (std::strcmp(uri, LV2_PARAMETERS__sampleRate) == 0)
1312             return kUridParamSampleRate;
1313         if (std::strcmp(uri, LV2_UI__backgroundColor) == 0)
1314             return kUridBackgroundColor;
1315         if (std::strcmp(uri, LV2_UI__foregroundColor) == 0)
1316             return kUridForegroundColor;
1317         if (std::strcmp(uri, LV2_UI__scaleFactor) == 0)
1318             return kUridScaleFactor;
1319         if (std::strcmp(uri, LV2_UI__windowTitle) == 0)
1320             return kUridWindowTitle;
1321 
1322         // Custom Carla types
1323         if (std::strcmp(uri, URI_CARLA_ATOM_WORKER_IN) == 0)
1324             return kUridCarlaAtomWorkerIn;
1325         if (std::strcmp(uri, URI_CARLA_ATOM_WORKER_RESP) == 0)
1326             return kUridCarlaAtomWorkerResp;
1327         if (std::strcmp(uri, URI_CARLA_PARAMETER_CHANGE) == 0)
1328             return kUridCarlaParameterChange;
1329         if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TransientWindowId) == 0)
1330             return kUridCarlaTransientWindowId;
1331 
1332         // Custom plugin types
1333         return ((CarlaLv2Client*)handle)->getCustomURID(uri);
1334     }
1335 
carla_lv2_urid_unmap(LV2_URID_Map_Handle handle,LV2_URID urid)1336     static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
1337     {
1338         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1339         CARLA_SAFE_ASSERT_RETURN(urid != kUridNull, nullptr);
1340         carla_debug("carla_lv2_urid_unmap(%p, %i)", handle, urid);
1341 
1342         switch (urid)
1343         {
1344         // Atom types
1345         case kUridAtomBlank:
1346             return LV2_ATOM__Blank;
1347         case kUridAtomBool:
1348             return LV2_ATOM__Bool;
1349         case kUridAtomChunk:
1350             return LV2_ATOM__Chunk;
1351         case kUridAtomDouble:
1352             return LV2_ATOM__Double;
1353         case kUridAtomEvent:
1354             return LV2_ATOM__Event;
1355         case kUridAtomFloat:
1356             return LV2_ATOM__Float;
1357         case kUridAtomInt:
1358             return LV2_ATOM__Int;
1359         case kUridAtomLiteral:
1360             return LV2_ATOM__Literal;
1361         case kUridAtomLong:
1362             return LV2_ATOM__Long;
1363         case kUridAtomNumber:
1364             return LV2_ATOM__Number;
1365         case kUridAtomObject:
1366             return LV2_ATOM__Object;
1367         case kUridAtomPath:
1368             return LV2_ATOM__Path;
1369         case kUridAtomProperty:
1370             return LV2_ATOM__Property;
1371         case kUridAtomResource:
1372             return LV2_ATOM__Resource;
1373         case kUridAtomSequence:
1374             return LV2_ATOM__Sequence;
1375         case kUridAtomSound:
1376             return LV2_ATOM__Sound;
1377         case kUridAtomString:
1378             return LV2_ATOM__String;
1379         case kUridAtomTuple:
1380             return LV2_ATOM__Tuple;
1381         case kUridAtomURI:
1382             return LV2_ATOM__URI;
1383         case kUridAtomURID:
1384             return LV2_ATOM__URID;
1385         case kUridAtomVector:
1386             return LV2_ATOM__Vector;
1387         case kUridAtomTransferAtom:
1388             return LV2_ATOM__atomTransfer;
1389         case kUridAtomTransferEvent:
1390             return LV2_ATOM__eventTransfer;
1391 
1392         // BufSize types
1393         case kUridBufMaxLength:
1394             return LV2_BUF_SIZE__maxBlockLength;
1395         case kUridBufMinLength:
1396             return LV2_BUF_SIZE__minBlockLength;
1397         case kUridBufNominalLength:
1398             return LV2_BUF_SIZE__nominalBlockLength;
1399         case kUridBufSequenceSize:
1400             return LV2_BUF_SIZE__sequenceSize;
1401 
1402         // Log types
1403         case kUridLogError:
1404             return LV2_LOG__Error;
1405         case kUridLogNote:
1406             return LV2_LOG__Note;
1407         case kUridLogTrace:
1408             return LV2_LOG__Trace;
1409         case kUridLogWarning:
1410             return LV2_LOG__Warning;
1411 
1412         // Patch types
1413         case kUridPatchSet:
1414             return LV2_PATCH__Set;
1415         case kUridPatchProperty:
1416             return LV2_PATCH__property;
1417         case kUridPatchSubject:
1418             return LV2_PATCH__subject;
1419         case kUridPatchValue:
1420             return LV2_PATCH__value;
1421 
1422         // Time types
1423         case kUridTimePosition:
1424             return LV2_TIME__Position;
1425         case kUridTimeBar:
1426             return LV2_TIME__bar;
1427         case kUridTimeBarBeat:
1428             return LV2_TIME__barBeat;
1429         case kUridTimeBeat:
1430             return LV2_TIME__beat;
1431         case kUridTimeBeatUnit:
1432             return LV2_TIME__beatUnit;
1433         case kUridTimeBeatsPerBar:
1434             return LV2_TIME__beatsPerBar;
1435         case kUridTimeBeatsPerMinute:
1436             return LV2_TIME__beatsPerMinute;
1437         case kUridTimeFrame:
1438             return LV2_TIME__frame;
1439         case kUridTimeFramesPerSecond:
1440             return LV2_TIME__framesPerSecond;
1441         case kUridTimeSpeed:
1442             return LV2_TIME__speed;
1443         case kUridTimeTicksPerBeat:
1444             return LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat;
1445 
1446         // Others
1447         case kUridMidiEvent:
1448             return LV2_MIDI__MidiEvent;
1449         case kUridParamSampleRate:
1450             return LV2_PARAMETERS__sampleRate;
1451         case kUridBackgroundColor:
1452             return LV2_UI__backgroundColor;
1453         case kUridForegroundColor:
1454             return LV2_UI__foregroundColor;
1455         case kUridScaleFactor:
1456             return LV2_UI__scaleFactor;
1457         case kUridWindowTitle:
1458             return LV2_UI__windowTitle;
1459 
1460         // Custom Carla types
1461         case kUridCarlaAtomWorkerIn:
1462             return URI_CARLA_ATOM_WORKER_IN;
1463         case kUridCarlaAtomWorkerResp:
1464             return URI_CARLA_ATOM_WORKER_RESP;
1465         case kUridCarlaParameterChange:
1466             return URI_CARLA_PARAMETER_CHANGE;
1467         case kUridCarlaTransientWindowId:
1468             return LV2_KXSTUDIO_PROPERTIES__TransientWindowId;
1469         }
1470 
1471         // Custom types
1472         return ((CarlaLv2Client*)handle)->getCustomURIDString(urid);
1473     }
1474 
1475     // ----------------------------------------------------------------------------------------------------------------
1476     // UI Port-Map Feature
1477 
carla_lv2_ui_port_map(LV2UI_Feature_Handle handle,const char * symbol)1478     static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol)
1479     {
1480         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, LV2UI_INVALID_PORT_INDEX);
1481         carla_debug("carla_lv2_ui_port_map(%p, \"%s\")", handle, symbol);
1482 
1483         return ((CarlaLv2Client*)handle)->handleUiPortMap(symbol);
1484     }
1485 
1486     // ----------------------------------------------------------------------------------------------------------------
1487     // UI Request Parameter Feature
1488 
carla_lv2_ui_request_value(LV2UI_Feature_Handle handle,LV2_URID key,LV2_URID type,const LV2_Feature * const * features)1489     static LV2UI_Request_Value_Status carla_lv2_ui_request_value(LV2UI_Feature_Handle handle,
1490                                                                  LV2_URID key,
1491                                                                  LV2_URID type,
1492                                                                  const LV2_Feature* const* features)
1493     {
1494         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
1495         carla_debug("carla_lv2_ui_request_value(%p, %u, %u, %p)", handle, key, type, features);
1496 
1497         return ((CarlaLv2Client*)handle)->handleUiRequestValue(key, type, features);
1498     }
1499 
1500     // ----------------------------------------------------------------------------------------------------------------
1501     // UI Resize Feature
1502 
carla_lv2_ui_resize(LV2UI_Feature_Handle handle,int width,int height)1503     static int carla_lv2_ui_resize(LV2UI_Feature_Handle handle, int width, int height)
1504     {
1505         CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 1);
1506         carla_debug("carla_lv2_ui_resize(%p, %i, %i)", handle, width, height);
1507 
1508         return ((CarlaLv2Client*)handle)->handleUiResize(width, height);
1509     }
1510 
1511     // ----------------------------------------------------------------------------------------------------------------
1512     // UI Extension
1513 
carla_lv2_ui_write_function(LV2UI_Controller controller,uint32_t port_index,uint32_t buffer_size,uint32_t format,const void * buffer)1514     static void carla_lv2_ui_write_function(LV2UI_Controller controller, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
1515     {
1516         CARLA_SAFE_ASSERT_RETURN(controller != nullptr,);
1517         carla_debug("carla_lv2_ui_write_function(%p, %i, %i, %i, %p)", controller, port_index, buffer_size, format, buffer);
1518 
1519         ((CarlaLv2Client*)controller)->handleUiWrite(port_index, buffer_size, format, buffer);
1520     }
1521 
1522     CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaLv2Client)
1523 };
1524 
1525 // --------------------------------------------------------------------------------------------------------------------
1526 
1527 CARLA_BRIDGE_UI_END_NAMESPACE
1528 
1529 // --------------------------------------------------------------------------------------------------------------------
1530 
main(int argc,const char * argv[])1531 int main(int argc, const char* argv[])
1532 {
1533     CARLA_BRIDGE_UI_USE_NAMESPACE
1534 
1535     if (argc < 2)
1536     {
1537         carla_stderr("usage: %s <plugin-uri> [ui-uri]", argv[0]);
1538         return 1;
1539     }
1540 
1541     const bool testingModeOnly = (argc != 7);
1542 
1543     // try to get sampleRate value
1544     if (const char* const sampleRateStr = std::getenv("CARLA_SAMPLE_RATE"))
1545     {
1546         const CarlaScopedLocale csl;
1547         gInitialSampleRate = std::atof(sampleRateStr);
1548     }
1549 
1550     // Init LV2 client
1551     CarlaLv2Client client;
1552 
1553     // Load UI
1554     int ret;
1555 
1556     if (client.init(argc, argv))
1557     {
1558         client.exec(testingModeOnly);
1559         ret = 0;
1560     }
1561     else
1562     {
1563         ret = 1;
1564     }
1565 
1566     return ret;
1567 }
1568 
1569 // --------------------------------------------------------------------------------------------------------------------
1570 
1571 #include "CarlaMacUtils.cpp"
1572 
1573 // --------------------------------------------------------------------------------------------------------------------
1574