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