VST3: fetch midi mappings all at once, use it for note/sound-off
[carla.git] / source / bridges-ui / CarlaBridgeFormatLV2.cpp
blob8637bec8c76e386520cc53e0dd1dcae883f2a59b
1 /*
2 * Carla Bridge UI
3 * Copyright (C) 2011-2022 Filipe Coelho <falktx@falktx.com>
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.
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.
15 * For a full copy of the GNU General Public License see the doc/GPL.txt file.
18 #include "CarlaBridgeFormat.hpp"
19 #include "CarlaBridgeToolkit.hpp"
21 #include "CarlaLibUtils.hpp"
22 #include "CarlaLv2Utils.hpp"
23 #include "CarlaMIDI.h"
24 #include "LinkedList.hpp"
26 #include "water/files/File.h"
28 #ifdef CARLA_OS_MAC
29 # include "CarlaMacUtils.hpp"
30 #endif
32 #include <string>
33 #include <vector>
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"
39 using water::File;
41 CARLA_BRIDGE_UI_START_NAMESPACE
43 // --------------------------------------------------------------------------------------------------------------------
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";
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 #ifndef CARLA_OS_MAC
107 kUridScaleFactor,
108 #endif
109 kUridWindowTitle,
110 // custom carla props
111 kUridCarlaAtomWorkerIn,
112 kUridCarlaAtomWorkerResp,
113 kUridCarlaParameterChange,
114 kUridCarlaTransientWindowId,
115 // count
116 kUridCount
119 // LV2 Feature Ids
120 enum CarlaLv2Features {
121 // DSP features
122 kFeatureIdLogs = 0,
123 kFeatureIdOptions,
124 kFeatureIdPrograms,
125 kFeatureIdStateFreePath,
126 kFeatureIdStateMakePath,
127 kFeatureIdStateMapPath,
128 kFeatureIdUriMap,
129 kFeatureIdUridMap,
130 kFeatureIdUridUnmap,
131 kFeatureIdUiIdleInterface,
132 kFeatureIdUiFixedSize,
133 kFeatureIdUiMakeResident,
134 kFeatureIdUiMakeResident2,
135 kFeatureIdUiNoUserResize,
136 kFeatureIdUiParent,
137 kFeatureIdUiPortMap,
138 kFeatureIdUiPortSubscribe,
139 kFeatureIdUiRequestValue,
140 kFeatureIdUiResize,
141 kFeatureIdUiTouch,
142 kFeatureCount
145 // --------------------------------------------------------------------------------------------------------------------
147 struct Lv2PluginOptions {
148 enum OptIndex {
149 SampleRate,
150 TransientWinId,
151 BackgroundColor,
152 ForegroundColor,
153 #ifndef CARLA_OS_MAC
154 ScaleFactor,
155 #endif
156 WindowTitle,
157 Null,
158 Count
161 float sampleRate;
162 int64_t transientWinId;
163 uint32_t bgColor;
164 uint32_t fgColor;
165 float uiScale;
166 LV2_Options_Option opts[Count];
168 Lv2PluginOptions() noexcept
169 : sampleRate(static_cast<float>(gInitialSampleRate)),
170 transientWinId(0),
171 bgColor(0x000000ff),
172 fgColor(0xffffffff),
173 uiScale(1.0f)
175 LV2_Options_Option& optSampleRate(opts[SampleRate]);
176 optSampleRate.context = LV2_OPTIONS_INSTANCE;
177 optSampleRate.subject = 0;
178 optSampleRate.key = kUridParamSampleRate;
179 optSampleRate.size = sizeof(float);
180 optSampleRate.type = kUridAtomFloat;
181 optSampleRate.value = &sampleRate;
183 LV2_Options_Option& optBackgroundColor(opts[BackgroundColor]);
184 optBackgroundColor.context = LV2_OPTIONS_INSTANCE;
185 optBackgroundColor.subject = 0;
186 optBackgroundColor.key = kUridBackgroundColor;
187 optBackgroundColor.size = sizeof(int32_t);
188 optBackgroundColor.type = kUridAtomInt;
189 optBackgroundColor.value = &bgColor;
191 LV2_Options_Option& optForegroundColor(opts[ForegroundColor]);
192 optForegroundColor.context = LV2_OPTIONS_INSTANCE;
193 optForegroundColor.subject = 0;
194 optForegroundColor.key = kUridForegroundColor;
195 optForegroundColor.size = sizeof(int32_t);
196 optForegroundColor.type = kUridAtomInt;
197 optForegroundColor.value = &fgColor;
199 #ifndef CARLA_OS_MAC
200 LV2_Options_Option& optScaleFactor(opts[ScaleFactor]);
201 optScaleFactor.context = LV2_OPTIONS_INSTANCE;
202 optScaleFactor.subject = 0;
203 optScaleFactor.key = kUridScaleFactor;
204 optScaleFactor.size = sizeof(float);
205 optScaleFactor.type = kUridAtomFloat;
206 optScaleFactor.value = &uiScale;
207 #endif
209 LV2_Options_Option& optTransientWinId(opts[TransientWinId]);
210 optTransientWinId.context = LV2_OPTIONS_INSTANCE;
211 optTransientWinId.subject = 0;
212 optTransientWinId.key = kUridCarlaTransientWindowId;
213 optTransientWinId.size = sizeof(int64_t);
214 optTransientWinId.type = kUridAtomLong;
215 optTransientWinId.value = &transientWinId;
217 LV2_Options_Option& optWindowTitle(opts[WindowTitle]);
218 optWindowTitle.context = LV2_OPTIONS_INSTANCE;
219 optWindowTitle.subject = 0;
220 optWindowTitle.key = kUridWindowTitle;
221 optWindowTitle.size = kNullWindowTitleSize;
222 optWindowTitle.type = kUridAtomString;
223 optWindowTitle.value = kNullWindowTitle;
225 LV2_Options_Option& optNull(opts[Null]);
226 optNull.context = LV2_OPTIONS_INSTANCE;
227 optNull.subject = 0;
228 optNull.key = kUridNull;
229 optNull.size = 0;
230 optNull.type = kUridNull;
231 optNull.value = nullptr;
235 // -------------------------------------------------------------------------------------------------------------------
237 static void initAtomForge(LV2_Atom_Forge& atomForge) noexcept
239 carla_zeroStruct(atomForge);
241 atomForge.Bool = kUridAtomBool;
242 atomForge.Chunk = kUridAtomChunk;
243 atomForge.Double = kUridAtomDouble;
244 atomForge.Float = kUridAtomFloat;
245 atomForge.Int = kUridAtomInt;
246 atomForge.Literal = kUridAtomLiteral;
247 atomForge.Long = kUridAtomLong;
248 atomForge.Object = kUridAtomObject;
249 atomForge.Path = kUridAtomPath;
250 atomForge.Property = kUridAtomProperty;
251 atomForge.Sequence = kUridAtomSequence;
252 atomForge.String = kUridAtomString;
253 atomForge.Tuple = kUridAtomTuple;
254 atomForge.URI = kUridAtomURI;
255 atomForge.URID = kUridAtomURID;
256 atomForge.Vector = kUridAtomVector;
258 #if defined(__clang__)
259 # pragma clang diagnostic push
260 # pragma clang diagnostic ignored "-Wdeprecated-declarations"
261 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
262 # pragma GCC diagnostic push
263 # pragma GCC diagnostic ignored "-Wdeprecated-declarations"
264 #endif
265 atomForge.Blank = kUridAtomBlank;
266 atomForge.Resource = kUridAtomResource;
267 #if defined(__clang__)
268 # pragma clang diagnostic pop
269 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
270 # pragma GCC diagnostic pop
271 #endif
274 // --------------------------------------------------------------------------------------------------------------------
276 class CarlaLv2Client : public CarlaBridgeFormat
278 public:
279 CarlaLv2Client()
280 : CarlaBridgeFormat(),
281 fHandle(nullptr),
282 fWidget(nullptr),
283 fDescriptor(nullptr),
284 fRdfDescriptor(nullptr),
285 fRdfUiDescriptor(nullptr),
286 fControlDesignatedPort(0),
287 fLv2Options(),
288 fUiOptions(),
289 fCustomURIDs(kUridCount, std::string("urn:null")),
290 fExt()
292 CARLA_SAFE_ASSERT(fCustomURIDs.size() == kUridCount);
294 carla_zeroPointers(fFeatures, kFeatureCount+1);
296 // ------------------------------------------------------------------------------------------------------------
297 // initialize features (part 1)
299 LV2_Log_Log* const logFt = new LV2_Log_Log;
300 logFt->handle = this;
301 logFt->printf = carla_lv2_log_printf;
302 logFt->vprintf = carla_lv2_log_vprintf;
304 LV2_State_Free_Path* const stateFreePathFt = new LV2_State_Free_Path;
305 stateFreePathFt->handle = this;
306 stateFreePathFt->free_path = carla_lv2_state_free_path;
308 LV2_State_Make_Path* const stateMakePathFt = new LV2_State_Make_Path;
309 stateMakePathFt->handle = this;
310 stateMakePathFt->path = carla_lv2_state_make_path_tmp;
312 LV2_State_Map_Path* const stateMapPathFt = new LV2_State_Map_Path;
313 stateMapPathFt->handle = this;
314 stateMapPathFt->abstract_path = carla_lv2_state_map_abstract_path_tmp;
315 stateMapPathFt->absolute_path = carla_lv2_state_map_absolute_path_tmp;
317 LV2_Programs_Host* const programsFt = new LV2_Programs_Host;
318 programsFt->handle = this;
319 programsFt->program_changed = carla_lv2_program_changed;
321 LV2_URI_Map_Feature* const uriMapFt = new LV2_URI_Map_Feature;
322 uriMapFt->callback_data = this;
323 uriMapFt->uri_to_id = carla_lv2_uri_to_id;
325 LV2_URID_Map* const uridMapFt = new LV2_URID_Map;
326 uridMapFt->handle = this;
327 uridMapFt->map = carla_lv2_urid_map;
329 LV2_URID_Unmap* const uridUnmapFt = new LV2_URID_Unmap;
330 uridUnmapFt->handle = this;
331 uridUnmapFt->unmap = carla_lv2_urid_unmap;
333 LV2UI_Port_Map* const uiPortMapFt = new LV2UI_Port_Map;
334 uiPortMapFt->handle = this;
335 uiPortMapFt->port_index = carla_lv2_ui_port_map;
337 LV2UI_Request_Value* const uiRequestValueFt = new LV2UI_Request_Value;
338 uiRequestValueFt->handle = this;
339 uiRequestValueFt->request = carla_lv2_ui_request_value;
341 LV2UI_Resize* const uiResizeFt = new LV2UI_Resize;
342 uiResizeFt->handle = this;
343 uiResizeFt->ui_resize = carla_lv2_ui_resize;
345 // ------------------------------------------------------------------------------------------------------------
346 // initialize features (part 2)
348 for (uint32_t i=0; i < kFeatureCount; ++i)
349 fFeatures[i] = new LV2_Feature;
351 fFeatures[kFeatureIdLogs]->URI = LV2_LOG__log;
352 fFeatures[kFeatureIdLogs]->data = logFt;
354 fFeatures[kFeatureIdOptions]->URI = LV2_OPTIONS__options;
355 fFeatures[kFeatureIdOptions]->data = fLv2Options.opts;
357 fFeatures[kFeatureIdPrograms]->URI = LV2_PROGRAMS__Host;
358 fFeatures[kFeatureIdPrograms]->data = programsFt;
360 fFeatures[kFeatureIdStateFreePath]->URI = LV2_STATE__freePath;
361 fFeatures[kFeatureIdStateFreePath]->data = stateFreePathFt;
363 fFeatures[kFeatureIdStateMakePath]->URI = LV2_STATE__makePath;
364 fFeatures[kFeatureIdStateMakePath]->data = stateMakePathFt;
366 fFeatures[kFeatureIdStateMapPath]->URI = LV2_STATE__mapPath;
367 fFeatures[kFeatureIdStateMapPath]->data = stateMapPathFt;
369 fFeatures[kFeatureIdUriMap]->URI = LV2_URI_MAP_URI;
370 fFeatures[kFeatureIdUriMap]->data = uriMapFt;
372 fFeatures[kFeatureIdUridMap]->URI = LV2_URID__map;
373 fFeatures[kFeatureIdUridMap]->data = uridMapFt;
375 fFeatures[kFeatureIdUridUnmap]->URI = LV2_URID__unmap;
376 fFeatures[kFeatureIdUridUnmap]->data = uridUnmapFt;
378 fFeatures[kFeatureIdUiIdleInterface]->URI = LV2_UI__idleInterface;
379 fFeatures[kFeatureIdUiIdleInterface]->data = nullptr;
381 fFeatures[kFeatureIdUiFixedSize]->URI = LV2_UI__fixedSize;
382 fFeatures[kFeatureIdUiFixedSize]->data = nullptr;
384 fFeatures[kFeatureIdUiMakeResident]->URI = LV2_UI__makeResident;
385 fFeatures[kFeatureIdUiMakeResident]->data = nullptr;
387 fFeatures[kFeatureIdUiMakeResident2]->URI = LV2_UI__makeSONameResident;
388 fFeatures[kFeatureIdUiMakeResident2]->data = nullptr;
390 fFeatures[kFeatureIdUiNoUserResize]->URI = LV2_UI__noUserResize;
391 fFeatures[kFeatureIdUiNoUserResize]->data = nullptr;
393 fFeatures[kFeatureIdUiParent]->URI = LV2_UI__parent;
394 fFeatures[kFeatureIdUiParent]->data = nullptr;
396 fFeatures[kFeatureIdUiPortMap]->URI = LV2_UI__portMap;
397 fFeatures[kFeatureIdUiPortMap]->data = uiPortMapFt;
399 fFeatures[kFeatureIdUiPortSubscribe]->URI = LV2_UI__portSubscribe;
400 fFeatures[kFeatureIdUiPortSubscribe]->data = nullptr;
402 fFeatures[kFeatureIdUiRequestValue]->URI = LV2_UI__requestValue;
403 fFeatures[kFeatureIdUiRequestValue]->data = uiRequestValueFt;
405 fFeatures[kFeatureIdUiResize]->URI = LV2_UI__resize;
406 fFeatures[kFeatureIdUiResize]->data = uiResizeFt;
408 fFeatures[kFeatureIdUiTouch]->URI = LV2_UI__touch;
409 fFeatures[kFeatureIdUiTouch]->data = nullptr;
412 ~CarlaLv2Client() override
414 if (fHandle != nullptr && fDescriptor != nullptr && fDescriptor->cleanup != nullptr)
416 fDescriptor->cleanup(fHandle);
417 fHandle = nullptr;
420 if (fRdfDescriptor != nullptr)
422 delete fRdfDescriptor;
423 fRdfDescriptor = nullptr;
426 fRdfUiDescriptor = nullptr;
428 delete (LV2_Log_Log*)fFeatures[kFeatureIdLogs]->data;
429 delete (LV2_State_Free_Path*)fFeatures[kFeatureIdStateFreePath]->data;
430 delete (LV2_State_Make_Path*)fFeatures[kFeatureIdStateMakePath]->data;
431 delete (LV2_State_Map_Path*)fFeatures[kFeatureIdStateMapPath]->data;
432 delete (LV2_Programs_Host*)fFeatures[kFeatureIdPrograms]->data;
433 delete (LV2_URI_Map_Feature*)fFeatures[kFeatureIdUriMap]->data;
434 delete (LV2_URID_Map*)fFeatures[kFeatureIdUridMap]->data;
435 delete (LV2_URID_Unmap*)fFeatures[kFeatureIdUridUnmap]->data;
436 delete (LV2UI_Port_Map*)fFeatures[kFeatureIdUiPortMap]->data;
437 delete (LV2UI_Request_Value*)fFeatures[kFeatureIdUiRequestValue]->data;
438 delete (LV2UI_Resize*)fFeatures[kFeatureIdUiResize]->data;
440 for (uint32_t i=0; i < kFeatureCount; ++i)
442 if (fFeatures[i] != nullptr)
444 delete fFeatures[i];
445 fFeatures[i] = nullptr;
450 // ----------------------------------------------------------------------------------------------------------------
451 // UI initialization
453 bool init(const int argc, const char* argv[]) override
455 const char* pluginURI = argv[1];
456 const char* uiURI = argc > 2 ? argv[2] : nullptr;
458 // ------------------------------------------------------------------------------------------------------------
459 // load plugin
461 Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
462 lv2World.initIfNeeded(std::getenv("LV2_PATH"));
464 #if 0
465 Lilv::Node bundleNode(lv2World.new_file_uri(nullptr, uiBundle));
466 CARLA_SAFE_ASSERT_RETURN(bundleNode.is_uri(), false);
468 CarlaString sBundle(bundleNode.as_uri());
470 if (! sBundle.endsWith("/"))
471 sBundle += "/";
473 lv2World.load_bundle(sBundle);
474 #endif
476 // ------------------------------------------------------------------------------------------------------------
477 // get plugin from lv2_rdf (lilv)
479 fRdfDescriptor = lv2_rdf_new(pluginURI, false);
480 CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor != nullptr, false);
482 // ------------------------------------------------------------------------------------------------------------
483 // find requested UI
485 if (uiURI == nullptr)
487 CARLA_SAFE_ASSERT_RETURN(fRdfDescriptor->UICount > 0, false);
489 fRdfUiDescriptor = &fRdfDescriptor->UIs[0];
490 uiURI = fRdfUiDescriptor->URI;
492 else
494 for (uint32_t i=0; i < fRdfDescriptor->UICount; ++i)
496 if (std::strcmp(fRdfDescriptor->UIs[i].URI, uiURI) == 0)
498 fRdfUiDescriptor = &fRdfDescriptor->UIs[i];
499 break;
504 CARLA_SAFE_ASSERT_RETURN(fRdfUiDescriptor != nullptr, false);
506 // ------------------------------------------------------------------------------------------------------------
507 // check if not resizable
509 for (uint32_t i=0; i < fRdfUiDescriptor->FeatureCount; ++i)
511 if (std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__fixedSize ) == 0 ||
512 std::strcmp(fRdfUiDescriptor->Features[i].URI, LV2_UI__noUserResize) == 0)
514 fUiOptions.isResizable = false;
515 break;
519 // ------------------------------------------------------------------------------------------------------------
520 // init UI
522 if (! CarlaBridgeFormat::init(argc, argv))
523 return false;
525 // ------------------------------------------------------------------------------------------------------------
526 // open DLL
528 #ifdef CARLA_OS_MAC
529 // Binary might be in quarentine due to Apple stupid notarization rules, let's remove that if possible
530 CARLA_BACKEND_NAMESPACE::removeFileFromQuarantine(fRdfUiDescriptor->Binary);
531 #endif
533 if (! libOpen(fRdfUiDescriptor->Binary))
535 carla_stderr("Failed to load UI binary, error was:\n%s", libError());
536 return false;
539 // ------------------------------------------------------------------------------------------------------------
540 // get DLL main entry
542 const LV2UI_DescriptorFunction ui_descFn = (LV2UI_DescriptorFunction)libSymbol("lv2ui_descriptor");
544 if (ui_descFn == nullptr)
545 return false;
547 // ------------------------------------------------------------------------------------------------------------
548 // get descriptor that matches URI
550 for (uint32_t i=0; (fDescriptor = ui_descFn(i++)) != nullptr;)
552 if (std::strcmp(fDescriptor->URI, uiURI) == 0)
553 break;
556 if (fDescriptor == nullptr)
558 carla_stderr("Failed to find UI descriptor");
559 return false;
562 // ------------------------------------------------------------------------------------------------------------
563 // initialize UI
565 #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
566 fFeatures[kFeatureIdUiParent]->data = fToolkit->getContainerId();
567 #endif
569 fHandle = fDescriptor->instantiate(fDescriptor, fRdfDescriptor->URI, fRdfUiDescriptor->Bundle,
570 carla_lv2_ui_write_function, this, &fWidget, fFeatures);
571 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr, false);
573 #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
574 if (fWidget != nullptr)
575 fToolkit->setChildWindow(fWidget);
576 #endif
578 // ------------------------------------------------------------------------------------------------------------
579 // check for known extensions
581 if (fDescriptor->extension_data != nullptr)
583 fExt.options = (const LV2_Options_Interface*)fDescriptor->extension_data(LV2_OPTIONS__interface);
584 fExt.programs = (const LV2_Programs_UI_Interface*)fDescriptor->extension_data(LV2_PROGRAMS__UIInterface);
585 fExt.idle = (const LV2UI_Idle_Interface*)fDescriptor->extension_data(LV2_UI__idleInterface);
586 fExt.resize = (const LV2UI_Resize*)fDescriptor->extension_data(LV2_UI__resize);
588 // check if invalid
589 if (fExt.programs != nullptr && fExt.programs->select_program == nullptr)
590 fExt.programs = nullptr;
591 if (fExt.idle != nullptr && fExt.idle->idle == nullptr)
592 fExt.idle = nullptr;
593 if (fExt.resize != nullptr && fExt.resize->ui_resize == nullptr)
594 fExt.resize = nullptr;
597 for (uint32_t i=0; i<fRdfDescriptor->PortCount; ++i)
599 if (LV2_IS_PORT_DESIGNATION_CONTROL(fRdfDescriptor->Ports[i].Designation))
601 fControlDesignatedPort = i;
602 break;
606 return true;
609 void idleUI() override
611 #if defined(BRIDGE_COCOA) || defined(BRIDGE_HWND) || defined(BRIDGE_X11)
612 if (fHandle != nullptr && fExt.idle != nullptr && fExt.idle->idle(fHandle) != 0)
614 if (isPipeRunning() && ! fQuitReceived)
615 writeExitingMessageAndWait();
617 #endif
620 // ----------------------------------------------------------------------------------------------------------------
621 // UI management
623 void* getWidget() const noexcept override
625 return fWidget;
628 const Options& getOptions() const noexcept override
630 return fUiOptions;
633 // ----------------------------------------------------------------------------------------------------------------
634 // DSP Callbacks
636 void dspParameterChanged(const uint32_t index, const float value) override
638 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
639 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
641 if (fDescriptor->port_event == nullptr)
642 return;
644 fDescriptor->port_event(fHandle, index, sizeof(float), kUridNull, &value);
647 void dspParameterChanged(const char* const uri, const float value) override
649 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
650 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
652 if (fDescriptor->port_event == nullptr)
653 return;
655 uint32_t parameterId = UINT32_MAX;
657 for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
659 const LV2_RDF_Parameter& rdfParam(fRdfDescriptor->Parameters[i]);
661 if (std::strcmp(rdfParam.URI, uri) == 0)
663 parameterId = i;
664 break;
668 if (parameterId == UINT32_MAX)
669 return;
671 uint8_t atomBuf[256];
672 LV2_Atom_Forge atomForge;
673 initAtomForge(atomForge);
674 lv2_atom_forge_set_buffer(&atomForge, atomBuf, sizeof(atomBuf));
676 LV2_Atom_Forge_Frame forgeFrame;
677 lv2_atom_forge_object(&atomForge, &forgeFrame, kUridNull, kUridPatchSet);
679 lv2_atom_forge_key(&atomForge, kUridCarlaParameterChange);
680 lv2_atom_forge_bool(&atomForge, true);
682 lv2_atom_forge_key(&atomForge, kUridPatchProperty);
683 lv2_atom_forge_urid(&atomForge, getCustomURID(uri));
685 lv2_atom_forge_key(&atomForge, kUridPatchValue);
687 switch (fRdfDescriptor->Parameters[parameterId].Type)
689 case LV2_PARAMETER_TYPE_BOOL:
690 lv2_atom_forge_bool(&atomForge, value > 0.5f);
691 break;
692 case LV2_PARAMETER_TYPE_INT:
693 lv2_atom_forge_int(&atomForge, static_cast<int32_t>(value + 0.5f));
694 break;
695 case LV2_PARAMETER_TYPE_LONG:
696 lv2_atom_forge_long(&atomForge, static_cast<int64_t>(value + 0.5f));
697 break;
698 case LV2_PARAMETER_TYPE_FLOAT:
699 lv2_atom_forge_float(&atomForge, value);
700 break;
701 case LV2_PARAMETER_TYPE_DOUBLE:
702 lv2_atom_forge_double(&atomForge, value);
703 break;
704 default:
705 carla_stderr2("dspParameterChanged called for invalid parameter, abort!");
706 return;
709 lv2_atom_forge_pop(&atomForge, &forgeFrame);
711 LV2_Atom* const atom((LV2_Atom*)atomBuf);
712 CARLA_SAFE_ASSERT(atom->size < sizeof(atomBuf));
714 fDescriptor->port_event(fHandle,
715 fControlDesignatedPort,
716 lv2_atom_total_size(atom),
717 kUridAtomTransferEvent,
718 atom);
721 void dspProgramChanged(const uint32_t index) override
723 carla_stderr2("dspProgramChanged(%i) - not handled", index);
726 void dspMidiProgramChanged(const uint32_t bank, const uint32_t program) override
728 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
730 if (fExt.programs == nullptr)
731 return;
733 fExt.programs->select_program(fHandle, bank, program);
736 void dspStateChanged(const char* const, const char* const) override
740 void dspNoteReceived(const bool onOff, const uint8_t channel, const uint8_t note, const uint8_t velocity) override
742 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,)
743 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
745 if (fDescriptor->port_event == nullptr)
746 return;
748 LV2_Atom_MidiEvent midiEv;
749 midiEv.atom.type = kUridMidiEvent;
750 midiEv.atom.size = 3;
751 midiEv.data[0] = uint8_t((onOff ? MIDI_STATUS_NOTE_ON : MIDI_STATUS_NOTE_OFF) | (channel & MIDI_CHANNEL_BIT));
752 midiEv.data[1] = note;
753 midiEv.data[2] = velocity;
755 fDescriptor->port_event(fHandle, fControlDesignatedPort, lv2_atom_total_size(midiEv), kUridAtomTransferEvent, &midiEv);
758 void dspAtomReceived(const uint32_t portIndex, const LV2_Atom* const atom) override
760 CARLA_SAFE_ASSERT_RETURN(fHandle != nullptr,);
761 CARLA_SAFE_ASSERT_RETURN(fDescriptor != nullptr,);
762 CARLA_SAFE_ASSERT_RETURN(atom != nullptr,);
764 if (fDescriptor->port_event == nullptr)
765 return;
767 fDescriptor->port_event(fHandle, portIndex, lv2_atom_total_size(atom), kUridAtomTransferEvent, atom);
770 void dspURIDReceived(const LV2_URID urid, const char* const uri) override
772 CARLA_SAFE_ASSERT_RETURN(urid == fCustomURIDs.size(),);
773 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0',);
775 fCustomURIDs.push_back(uri);
778 void uiOptionsChanged(const BridgeFormatOptions& opts) override
780 carla_debug("CarlaLv2Client::uiOptionsChanged()");
782 // ------------------------------------------------------------------------------------------------------------
783 // sample rate
785 const float sampleRatef = static_cast<float>(opts.sampleRate);
787 if (carla_isNotEqual(fLv2Options.sampleRate, sampleRatef))
789 fLv2Options.sampleRate = sampleRatef;
791 if (fExt.options != nullptr && fExt.options->set != nullptr)
793 LV2_Options_Option options[2];
794 carla_zeroStructs(options, 2);
796 LV2_Options_Option& optSampleRate(options[0]);
797 optSampleRate.context = LV2_OPTIONS_INSTANCE;
798 optSampleRate.subject = 0;
799 optSampleRate.key = kUridParamSampleRate;
800 optSampleRate.size = sizeof(float);
801 optSampleRate.type = kUridAtomFloat;
802 optSampleRate.value = &fLv2Options.sampleRate;
804 fExt.options->set(fHandle, options);
808 // ------------------------------------------------------------------------------------------------------------
809 // ui colors and scale
811 fLv2Options.bgColor = opts.bgColor;
812 fLv2Options.fgColor = opts.fgColor;
813 fLv2Options.uiScale = opts.uiScale;
815 // ------------------------------------------------------------------------------------------------------------
816 // window title
818 if (opts.windowTitle != nullptr)
819 fUiOptions.windowTitle = opts.windowTitle;
820 else
821 fUiOptions.windowTitle.clear();
823 fLv2Options.opts[Lv2PluginOptions::WindowTitle].size = static_cast<uint32_t>(fUiOptions.windowTitle.length());
824 fLv2Options.opts[Lv2PluginOptions::WindowTitle].value = fUiOptions.windowTitle.buffer();
826 // ------------------------------------------------------------------------------------------------------------
827 // transient win id
829 fLv2Options.transientWinId = static_cast<int64_t>(opts.transientWindowId);
830 fUiOptions.transientWindowId = opts.transientWindowId;
832 // ------------------------------------------------------------------------------------------------------------
833 // other
835 fUiOptions.isStandalone = opts.isStandalone;
836 fUiOptions.useTheme = opts.useTheme;
837 fUiOptions.useThemeColors = opts.useThemeColors;
840 #ifndef CARLA_OS_MAC
841 void setScaleFactor(const double scaleFactor) override
843 fLv2Options.uiScale = static_cast<float>(scaleFactor);
845 #endif
847 void uiResized(const uint width, const uint height) override
849 if (fHandle != nullptr && fExt.resize != nullptr)
850 fExt.resize->ui_resize(fHandle, static_cast<int>(width), static_cast<int>(height));
853 // ----------------------------------------------------------------------------------------------------------------
855 LV2_URID getCustomURID(const char* const uri)
857 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', kUridNull);
858 carla_debug("CarlaLv2Client::getCustomURID(\"%s\")", uri);
860 const std::string s_uri(uri);
861 const std::ptrdiff_t s_pos(std::find(fCustomURIDs.begin(), fCustomURIDs.end(), s_uri) - fCustomURIDs.begin());
863 if (s_pos <= 0 || s_pos >= INT32_MAX)
864 return kUridNull;
866 const LV2_URID urid = static_cast<LV2_URID>(s_pos);
867 const LV2_URID uriCount = static_cast<LV2_URID>(fCustomURIDs.size());
869 if (urid < uriCount)
870 return urid;
872 CARLA_SAFE_ASSERT(urid == uriCount);
874 fCustomURIDs.push_back(uri);
876 if (isPipeRunning())
877 writeLv2UridMessage(urid, uri);
879 return urid;
882 const char* getCustomURIDString(const LV2_URID urid) const noexcept
884 CARLA_SAFE_ASSERT_RETURN(urid != kUridNull, kUnmapFallback);
885 CARLA_SAFE_ASSERT_RETURN(urid < fCustomURIDs.size(), kUnmapFallback);
886 carla_debug("CarlaLv2Client::getCustomURIDString(%i)", urid);
888 return fCustomURIDs[urid].c_str();
891 // ----------------------------------------------------------------------------------------------------------------
893 void handleProgramChanged(const int32_t index)
895 if (isPipeRunning())
896 writeReloadProgramsMessage(index);
899 uint32_t handleUiPortMap(const char* const symbol)
901 CARLA_SAFE_ASSERT_RETURN(symbol != nullptr && symbol[0] != '\0', LV2UI_INVALID_PORT_INDEX);
902 carla_debug("CarlaLv2Client::handleUiPortMap(\"%s\")", symbol);
904 for (uint32_t i=0; i < fRdfDescriptor->PortCount; ++i)
906 if (std::strcmp(fRdfDescriptor->Ports[i].Symbol, symbol) == 0)
907 return i;
910 return LV2UI_INVALID_PORT_INDEX;
913 // ----------------------------------------------------------------------------------------------------------------
915 char* handleStateMapToAbstractPath(const char* const absolutePath)
917 // may already be an abstract path
918 if (! File::isAbsolutePath(absolutePath))
919 return strdup(absolutePath);
921 return strdup(File(absolutePath).getRelativePathFrom(File::getCurrentWorkingDirectory()).toRawUTF8());
924 char* handleStateMapToAbsolutePath(const bool createDir, const char* const abstractPath)
926 File target;
928 if (File::isAbsolutePath(abstractPath))
930 target = abstractPath;
932 else
934 target = File::getCurrentWorkingDirectory().getChildFile(abstractPath);
937 if (createDir)
939 File dir(target.getParentDirectory());
940 if (! dir.exists())
941 dir.createDirectory();
944 return strdup(target.getFullPathName().toRawUTF8());
947 // ----------------------------------------------------------------------------------------------------------------
949 LV2UI_Request_Value_Status handleUiRequestValue(const LV2_URID key,
950 const LV2_URID type,
951 const LV2_Feature* const* features)
953 CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
954 carla_debug("CarlaLv2Client::handleUIRequestValue(%u, %u, %p)", key, type, features);
956 if (type != kUridAtomPath)
957 return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
959 const char* const uri = getCustomURIDString(key);
960 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri != kUnmapFallback, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
962 // TODO check if a file browser is already open
964 for (uint32_t i=0; i < fRdfDescriptor->ParameterCount; ++i)
966 if (fRdfDescriptor->Parameters[i].Type != LV2_PARAMETER_TYPE_PATH)
967 continue;
968 if (std::strcmp(fRdfDescriptor->Parameters[i].URI, uri) != 0)
969 continue;
971 // TODO file browser filters, also label for title
972 if (isPipeRunning())
974 char tmpBuf[0xff];
976 const CarlaMutexLocker cml(getPipeLock());
978 writeMessage("requestvalue\n", 13);
980 std::snprintf(tmpBuf, 0xff-1, "%u\n", key);
981 tmpBuf[0xff-1] = '\0';
982 writeMessage(tmpBuf);
984 std::snprintf(tmpBuf, 0xff-1, "%u\n", type);
985 tmpBuf[0xff-1] = '\0';
986 writeMessage(tmpBuf);
989 return LV2UI_REQUEST_VALUE_SUCCESS;
992 return LV2UI_REQUEST_VALUE_ERR_UNSUPPORTED;
994 // may be unused
995 (void)features;
998 int handleUiResize(const int width, const int height)
1000 CARLA_SAFE_ASSERT_RETURN(fToolkit != nullptr, 1);
1001 CARLA_SAFE_ASSERT_RETURN(width > 0, 1);
1002 CARLA_SAFE_ASSERT_RETURN(height > 0, 1);
1003 carla_debug("CarlaLv2Client::handleUiResize(%i, %i)", width, height);
1005 fToolkit->setSize(static_cast<uint>(width), static_cast<uint>(height));
1006 return 0;
1009 void handleUiWrite(uint32_t rindex, uint32_t bufferSize, uint32_t format, const void* buffer)
1011 CARLA_SAFE_ASSERT_RETURN(buffer != nullptr,);
1012 CARLA_SAFE_ASSERT_RETURN(bufferSize > 0,);
1013 carla_debug("CarlaLv2Client::handleUiWrite(%i, %i, %i, %p)", rindex, bufferSize, format, buffer);
1015 switch (format)
1017 case kUridNull:
1018 CARLA_SAFE_ASSERT_RETURN(bufferSize == sizeof(float),);
1020 if (isPipeRunning())
1022 const float value(*(const float*)buffer);
1023 writeControlMessage(rindex, value);
1025 break;
1027 case kUridAtomTransferAtom:
1028 case kUridAtomTransferEvent:
1029 CARLA_SAFE_ASSERT_RETURN(bufferSize >= sizeof(LV2_Atom),);
1031 if (isPipeRunning())
1033 const LV2_Atom* const atom((const LV2_Atom*)buffer);
1035 // plugins sometimes fail on this, not good...
1036 const uint32_t totalSize = lv2_atom_total_size(atom);
1037 const uint32_t paddedSize = lv2_atom_pad_size(totalSize);
1039 if (bufferSize != totalSize && bufferSize != paddedSize)
1040 carla_stderr2("Warning: LV2 UI sending atom with invalid size %u! size: %u, padded-size: %u",
1041 bufferSize, totalSize, paddedSize);
1043 writeLv2AtomMessage(rindex, atom);
1045 break;
1047 default:
1048 carla_stderr("CarlaLv2Client::handleUiWrite(%i, %i, %i:\"%s\", %p) - unknown format",
1049 rindex, bufferSize, format, carla_lv2_urid_unmap(this, format), buffer);
1050 break;
1054 // ----------------------------------------------------------------------------------------------------------------
1056 private:
1057 LV2UI_Handle fHandle;
1058 LV2UI_Widget fWidget;
1059 LV2_Feature* fFeatures[kFeatureCount+1];
1061 const LV2UI_Descriptor* fDescriptor;
1062 const LV2_RDF_Descriptor* fRdfDescriptor;
1063 const LV2_RDF_UI* fRdfUiDescriptor;
1064 uint32_t fControlDesignatedPort;
1065 Lv2PluginOptions fLv2Options;
1067 Options fUiOptions;
1068 std::vector<std::string> fCustomURIDs;
1070 struct Extensions {
1071 const LV2_Options_Interface* options;
1072 const LV2_Programs_UI_Interface* programs;
1073 const LV2UI_Idle_Interface* idle;
1074 const LV2UI_Resize* resize;
1076 Extensions()
1077 : options(nullptr),
1078 programs(nullptr),
1079 idle(nullptr),
1080 resize(nullptr) {}
1081 } fExt;
1083 // ----------------------------------------------------------------------------------------------------------------
1084 // Logs Feature
1086 static int carla_lv2_log_printf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, ...)
1088 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
1089 CARLA_SAFE_ASSERT_RETURN(type != kUridNull, 0);
1090 CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
1092 #ifndef DEBUG
1093 if (type == kUridLogTrace)
1094 return 0;
1095 #endif
1097 va_list args;
1098 va_start(args, fmt);
1099 const int ret(carla_lv2_log_vprintf(handle, type, fmt, args));
1100 va_end(args);
1102 return ret;
1105 static int carla_lv2_log_vprintf(LV2_Log_Handle handle, LV2_URID type, const char* fmt, va_list ap)
1107 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 0);
1108 CARLA_SAFE_ASSERT_RETURN(type != kUridNull, 0);
1109 CARLA_SAFE_ASSERT_RETURN(fmt != nullptr, 0);
1111 int ret = 0;
1113 switch (type)
1115 case kUridLogError:
1116 std::fprintf(stderr, "\x1b[31m");
1117 ret = std::vfprintf(stderr, fmt, ap);
1118 std::fprintf(stderr, "\x1b[0m");
1119 break;
1121 case kUridLogNote:
1122 ret = std::vfprintf(stdout, fmt, ap);
1123 break;
1125 case kUridLogTrace:
1126 #ifdef DEBUG
1127 std::fprintf(stdout, "\x1b[30;1m");
1128 ret = std::vfprintf(stdout, fmt, ap);
1129 std::fprintf(stdout, "\x1b[0m");
1130 #endif
1131 break;
1133 case kUridLogWarning:
1134 ret = std::vfprintf(stderr, fmt, ap);
1135 break;
1137 default:
1138 break;
1141 return ret;
1144 // ----------------------------------------------------------------------------------------------------------------
1145 // Programs Feature
1147 static void carla_lv2_program_changed(LV2_Programs_Handle handle, int32_t index)
1149 CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1150 carla_debug("carla_lv2_program_changed(%p, %i)", handle, index);
1152 ((CarlaLv2Client*)handle)->handleProgramChanged(index);
1155 // ----------------------------------------------------------------------------------------------------------------
1156 // State Feature
1158 static void carla_lv2_state_free_path(LV2_State_Free_Path_Handle handle, char* path)
1160 CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1161 carla_debug("carla_lv2_state_free_path(%p, \"%s\")", handle, path);
1163 std::free(path);
1166 static char* carla_lv2_state_make_path_tmp(LV2_State_Make_Path_Handle handle, const char* path)
1168 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1169 CARLA_SAFE_ASSERT_RETURN(path != nullptr && path[0] != '\0', nullptr);
1170 carla_debug("carla_lv2_state_make_path_tmp(%p, \"%s\")", handle, path);
1172 return ((CarlaLv2Client*)handle)->handleStateMapToAbsolutePath(true, path);
1175 static char* carla_lv2_state_map_abstract_path_tmp(LV2_State_Map_Path_Handle handle, const char* absolute_path)
1177 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1178 CARLA_SAFE_ASSERT_RETURN(absolute_path != nullptr && absolute_path[0] != '\0', nullptr);
1179 carla_debug("carla_lv2_state_map_abstract_path_tmp(%p, \"%s\")", handle, absolute_path);
1181 return ((CarlaLv2Client*)handle)->handleStateMapToAbstractPath(absolute_path);
1184 static char* carla_lv2_state_map_absolute_path_tmp(LV2_State_Map_Path_Handle handle, const char* abstract_path)
1186 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1187 CARLA_SAFE_ASSERT_RETURN(abstract_path != nullptr && abstract_path[0] != '\0', nullptr);
1188 carla_debug("carla_lv2_state_map_absolute_path_tmp(%p, \"%s\")", handle, abstract_path);
1190 return ((CarlaLv2Client*)handle)->handleStateMapToAbsolutePath(false, abstract_path);
1193 // ----------------------------------------------------------------------------------------------------------------
1194 // URI-Map Feature
1196 static uint32_t carla_lv2_uri_to_id(LV2_URI_Map_Callback_Data data, const char* map, const char* uri)
1198 carla_debug("carla_lv2_uri_to_id(%p, \"%s\", \"%s\")", data, map, uri);
1199 return carla_lv2_urid_map((LV2_URID_Map_Handle*)data, uri);
1201 // unused
1202 (void)map;
1205 // ----------------------------------------------------------------------------------------------------------------
1206 // URID Feature
1208 static LV2_URID carla_lv2_urid_map(LV2_URID_Map_Handle handle, const char* uri)
1210 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, kUridNull);
1211 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', kUridNull);
1212 carla_debug("carla_lv2_urid_map(%p, \"%s\")", handle, uri);
1214 // Atom types
1215 if (std::strcmp(uri, LV2_ATOM__Blank) == 0)
1216 return kUridAtomBlank;
1217 if (std::strcmp(uri, LV2_ATOM__Bool) == 0)
1218 return kUridAtomBool;
1219 if (std::strcmp(uri, LV2_ATOM__Chunk) == 0)
1220 return kUridAtomChunk;
1221 if (std::strcmp(uri, LV2_ATOM__Double) == 0)
1222 return kUridAtomDouble;
1223 if (std::strcmp(uri, LV2_ATOM__Event) == 0)
1224 return kUridAtomEvent;
1225 if (std::strcmp(uri, LV2_ATOM__Float) == 0)
1226 return kUridAtomFloat;
1227 if (std::strcmp(uri, LV2_ATOM__Int) == 0)
1228 return kUridAtomInt;
1229 if (std::strcmp(uri, LV2_ATOM__Literal) == 0)
1230 return kUridAtomLiteral;
1231 if (std::strcmp(uri, LV2_ATOM__Long) == 0)
1232 return kUridAtomLong;
1233 if (std::strcmp(uri, LV2_ATOM__Number) == 0)
1234 return kUridAtomNumber;
1235 if (std::strcmp(uri, LV2_ATOM__Object) == 0)
1236 return kUridAtomObject;
1237 if (std::strcmp(uri, LV2_ATOM__Path) == 0)
1238 return kUridAtomPath;
1239 if (std::strcmp(uri, LV2_ATOM__Property) == 0)
1240 return kUridAtomProperty;
1241 if (std::strcmp(uri, LV2_ATOM__Resource) == 0)
1242 return kUridAtomResource;
1243 if (std::strcmp(uri, LV2_ATOM__Sequence) == 0)
1244 return kUridAtomSequence;
1245 if (std::strcmp(uri, LV2_ATOM__Sound) == 0)
1246 return kUridAtomSound;
1247 if (std::strcmp(uri, LV2_ATOM__String) == 0)
1248 return kUridAtomString;
1249 if (std::strcmp(uri, LV2_ATOM__Tuple) == 0)
1250 return kUridAtomTuple;
1251 if (std::strcmp(uri, LV2_ATOM__URI) == 0)
1252 return kUridAtomURI;
1253 if (std::strcmp(uri, LV2_ATOM__URID) == 0)
1254 return kUridAtomURID;
1255 if (std::strcmp(uri, LV2_ATOM__Vector) == 0)
1256 return kUridAtomVector;
1257 if (std::strcmp(uri, LV2_ATOM__atomTransfer) == 0)
1258 return kUridAtomTransferAtom;
1259 if (std::strcmp(uri, LV2_ATOM__eventTransfer) == 0)
1260 return kUridAtomTransferEvent;
1262 // BufSize types
1263 if (std::strcmp(uri, LV2_BUF_SIZE__maxBlockLength) == 0)
1264 return kUridBufMaxLength;
1265 if (std::strcmp(uri, LV2_BUF_SIZE__minBlockLength) == 0)
1266 return kUridBufMinLength;
1267 if (std::strcmp(uri, LV2_BUF_SIZE__nominalBlockLength) == 0)
1268 return kUridBufNominalLength;
1269 if (std::strcmp(uri, LV2_BUF_SIZE__sequenceSize) == 0)
1270 return kUridBufSequenceSize;
1272 // Log types
1273 if (std::strcmp(uri, LV2_LOG__Error) == 0)
1274 return kUridLogError;
1275 if (std::strcmp(uri, LV2_LOG__Note) == 0)
1276 return kUridLogNote;
1277 if (std::strcmp(uri, LV2_LOG__Trace) == 0)
1278 return kUridLogTrace;
1279 if (std::strcmp(uri, LV2_LOG__Warning) == 0)
1280 return kUridLogWarning;
1282 // Patch types
1283 if (std::strcmp(uri, LV2_PATCH__Set) == 0)
1284 return kUridPatchSet;
1285 if (std::strcmp(uri, LV2_PATCH__property) == 0)
1286 return kUridPatchProperty;
1287 if (std::strcmp(uri, LV2_PATCH__subject) == 0)
1288 return kUridPatchSubject;
1289 if (std::strcmp(uri, LV2_PATCH__value) == 0)
1290 return kUridPatchValue;
1292 // Time types
1293 if (std::strcmp(uri, LV2_TIME__Position) == 0)
1294 return kUridTimePosition;
1295 if (std::strcmp(uri, LV2_TIME__bar) == 0)
1296 return kUridTimeBar;
1297 if (std::strcmp(uri, LV2_TIME__barBeat) == 0)
1298 return kUridTimeBarBeat;
1299 if (std::strcmp(uri, LV2_TIME__beat) == 0)
1300 return kUridTimeBeat;
1301 if (std::strcmp(uri, LV2_TIME__beatUnit) == 0)
1302 return kUridTimeBeatUnit;
1303 if (std::strcmp(uri, LV2_TIME__beatsPerBar) == 0)
1304 return kUridTimeBeatsPerBar;
1305 if (std::strcmp(uri, LV2_TIME__beatsPerMinute) == 0)
1306 return kUridTimeBeatsPerMinute;
1307 if (std::strcmp(uri, LV2_TIME__frame) == 0)
1308 return kUridTimeFrame;
1309 if (std::strcmp(uri, LV2_TIME__framesPerSecond) == 0)
1310 return kUridTimeFramesPerSecond;
1311 if (std::strcmp(uri, LV2_TIME__speed) == 0)
1312 return kUridTimeSpeed;
1313 if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
1314 return kUridTimeTicksPerBeat;
1316 // Others
1317 if (std::strcmp(uri, LV2_MIDI__MidiEvent) == 0)
1318 return kUridMidiEvent;
1319 if (std::strcmp(uri, LV2_PARAMETERS__sampleRate) == 0)
1320 return kUridParamSampleRate;
1321 if (std::strcmp(uri, LV2_UI__backgroundColor) == 0)
1322 return kUridBackgroundColor;
1323 if (std::strcmp(uri, LV2_UI__foregroundColor) == 0)
1324 return kUridForegroundColor;
1325 #ifndef CARLA_OS_MAC
1326 if (std::strcmp(uri, LV2_UI__scaleFactor) == 0)
1327 return kUridScaleFactor;
1328 #endif
1329 if (std::strcmp(uri, LV2_UI__windowTitle) == 0)
1330 return kUridWindowTitle;
1332 // Custom Carla types
1333 if (std::strcmp(uri, URI_CARLA_ATOM_WORKER_IN) == 0)
1334 return kUridCarlaAtomWorkerIn;
1335 if (std::strcmp(uri, URI_CARLA_ATOM_WORKER_RESP) == 0)
1336 return kUridCarlaAtomWorkerResp;
1337 if (std::strcmp(uri, URI_CARLA_PARAMETER_CHANGE) == 0)
1338 return kUridCarlaParameterChange;
1339 if (std::strcmp(uri, LV2_KXSTUDIO_PROPERTIES__TransientWindowId) == 0)
1340 return kUridCarlaTransientWindowId;
1342 // Custom plugin types
1343 return ((CarlaLv2Client*)handle)->getCustomURID(uri);
1346 static const char* carla_lv2_urid_unmap(LV2_URID_Map_Handle handle, LV2_URID urid)
1348 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, nullptr);
1349 CARLA_SAFE_ASSERT_RETURN(urid != kUridNull, nullptr);
1350 carla_debug("carla_lv2_urid_unmap(%p, %i)", handle, urid);
1352 switch (urid)
1354 // Atom types
1355 case kUridAtomBlank:
1356 return LV2_ATOM__Blank;
1357 case kUridAtomBool:
1358 return LV2_ATOM__Bool;
1359 case kUridAtomChunk:
1360 return LV2_ATOM__Chunk;
1361 case kUridAtomDouble:
1362 return LV2_ATOM__Double;
1363 case kUridAtomEvent:
1364 return LV2_ATOM__Event;
1365 case kUridAtomFloat:
1366 return LV2_ATOM__Float;
1367 case kUridAtomInt:
1368 return LV2_ATOM__Int;
1369 case kUridAtomLiteral:
1370 return LV2_ATOM__Literal;
1371 case kUridAtomLong:
1372 return LV2_ATOM__Long;
1373 case kUridAtomNumber:
1374 return LV2_ATOM__Number;
1375 case kUridAtomObject:
1376 return LV2_ATOM__Object;
1377 case kUridAtomPath:
1378 return LV2_ATOM__Path;
1379 case kUridAtomProperty:
1380 return LV2_ATOM__Property;
1381 case kUridAtomResource:
1382 return LV2_ATOM__Resource;
1383 case kUridAtomSequence:
1384 return LV2_ATOM__Sequence;
1385 case kUridAtomSound:
1386 return LV2_ATOM__Sound;
1387 case kUridAtomString:
1388 return LV2_ATOM__String;
1389 case kUridAtomTuple:
1390 return LV2_ATOM__Tuple;
1391 case kUridAtomURI:
1392 return LV2_ATOM__URI;
1393 case kUridAtomURID:
1394 return LV2_ATOM__URID;
1395 case kUridAtomVector:
1396 return LV2_ATOM__Vector;
1397 case kUridAtomTransferAtom:
1398 return LV2_ATOM__atomTransfer;
1399 case kUridAtomTransferEvent:
1400 return LV2_ATOM__eventTransfer;
1402 // BufSize types
1403 case kUridBufMaxLength:
1404 return LV2_BUF_SIZE__maxBlockLength;
1405 case kUridBufMinLength:
1406 return LV2_BUF_SIZE__minBlockLength;
1407 case kUridBufNominalLength:
1408 return LV2_BUF_SIZE__nominalBlockLength;
1409 case kUridBufSequenceSize:
1410 return LV2_BUF_SIZE__sequenceSize;
1412 // Log types
1413 case kUridLogError:
1414 return LV2_LOG__Error;
1415 case kUridLogNote:
1416 return LV2_LOG__Note;
1417 case kUridLogTrace:
1418 return LV2_LOG__Trace;
1419 case kUridLogWarning:
1420 return LV2_LOG__Warning;
1422 // Patch types
1423 case kUridPatchSet:
1424 return LV2_PATCH__Set;
1425 case kUridPatchProperty:
1426 return LV2_PATCH__property;
1427 case kUridPatchSubject:
1428 return LV2_PATCH__subject;
1429 case kUridPatchValue:
1430 return LV2_PATCH__value;
1432 // Time types
1433 case kUridTimePosition:
1434 return LV2_TIME__Position;
1435 case kUridTimeBar:
1436 return LV2_TIME__bar;
1437 case kUridTimeBarBeat:
1438 return LV2_TIME__barBeat;
1439 case kUridTimeBeat:
1440 return LV2_TIME__beat;
1441 case kUridTimeBeatUnit:
1442 return LV2_TIME__beatUnit;
1443 case kUridTimeBeatsPerBar:
1444 return LV2_TIME__beatsPerBar;
1445 case kUridTimeBeatsPerMinute:
1446 return LV2_TIME__beatsPerMinute;
1447 case kUridTimeFrame:
1448 return LV2_TIME__frame;
1449 case kUridTimeFramesPerSecond:
1450 return LV2_TIME__framesPerSecond;
1451 case kUridTimeSpeed:
1452 return LV2_TIME__speed;
1453 case kUridTimeTicksPerBeat:
1454 return LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat;
1456 // Others
1457 case kUridMidiEvent:
1458 return LV2_MIDI__MidiEvent;
1459 case kUridParamSampleRate:
1460 return LV2_PARAMETERS__sampleRate;
1461 case kUridBackgroundColor:
1462 return LV2_UI__backgroundColor;
1463 case kUridForegroundColor:
1464 return LV2_UI__foregroundColor;
1465 #ifndef CARLA_OS_MAC
1466 case kUridScaleFactor:
1467 return LV2_UI__scaleFactor;
1468 #endif
1469 case kUridWindowTitle:
1470 return LV2_UI__windowTitle;
1472 // Custom Carla types
1473 case kUridCarlaAtomWorkerIn:
1474 return URI_CARLA_ATOM_WORKER_IN;
1475 case kUridCarlaAtomWorkerResp:
1476 return URI_CARLA_ATOM_WORKER_RESP;
1477 case kUridCarlaParameterChange:
1478 return URI_CARLA_PARAMETER_CHANGE;
1479 case kUridCarlaTransientWindowId:
1480 return LV2_KXSTUDIO_PROPERTIES__TransientWindowId;
1483 // Custom types
1484 return ((CarlaLv2Client*)handle)->getCustomURIDString(urid);
1487 // ----------------------------------------------------------------------------------------------------------------
1488 // UI Port-Map Feature
1490 static uint32_t carla_lv2_ui_port_map(LV2UI_Feature_Handle handle, const char* symbol)
1492 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, LV2UI_INVALID_PORT_INDEX);
1493 carla_debug("carla_lv2_ui_port_map(%p, \"%s\")", handle, symbol);
1495 return ((CarlaLv2Client*)handle)->handleUiPortMap(symbol);
1498 // ----------------------------------------------------------------------------------------------------------------
1499 // UI Request Parameter Feature
1501 static LV2UI_Request_Value_Status carla_lv2_ui_request_value(LV2UI_Feature_Handle handle,
1502 LV2_URID key,
1503 LV2_URID type,
1504 const LV2_Feature* const* features)
1506 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, LV2UI_REQUEST_VALUE_ERR_UNKNOWN);
1507 carla_debug("carla_lv2_ui_request_value(%p, %u, %u, %p)", handle, key, type, features);
1509 return ((CarlaLv2Client*)handle)->handleUiRequestValue(key, type, features);
1512 // ----------------------------------------------------------------------------------------------------------------
1513 // UI Resize Feature
1515 static int carla_lv2_ui_resize(LV2UI_Feature_Handle handle, int width, int height)
1517 CARLA_SAFE_ASSERT_RETURN(handle != nullptr, 1);
1518 carla_debug("carla_lv2_ui_resize(%p, %i, %i)", handle, width, height);
1520 return ((CarlaLv2Client*)handle)->handleUiResize(width, height);
1523 // ----------------------------------------------------------------------------------------------------------------
1524 // UI Extension
1526 static void carla_lv2_ui_write_function(LV2UI_Controller controller, uint32_t port_index, uint32_t buffer_size, uint32_t format, const void* buffer)
1528 CARLA_SAFE_ASSERT_RETURN(controller != nullptr,);
1529 carla_debug("carla_lv2_ui_write_function(%p, %i, %i, %i, %p)", controller, port_index, buffer_size, format, buffer);
1531 ((CarlaLv2Client*)controller)->handleUiWrite(port_index, buffer_size, format, buffer);
1534 CARLA_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(CarlaLv2Client)
1537 // --------------------------------------------------------------------------------------------------------------------
1539 CARLA_BRIDGE_UI_END_NAMESPACE
1541 // --------------------------------------------------------------------------------------------------------------------
1543 int main(int argc, const char* argv[])
1545 CARLA_BRIDGE_UI_USE_NAMESPACE
1547 if (argc < 2)
1549 carla_stderr("usage: %s <plugin-uri> [ui-uri]", argv[0]);
1550 return 1;
1553 const bool testingModeOnly = (argc != 7);
1555 // try to get sampleRate value
1556 if (const char* const sampleRateStr = std::getenv("CARLA_SAMPLE_RATE"))
1558 const CarlaScopedLocale csl;
1559 gInitialSampleRate = std::atof(sampleRateStr);
1562 // Init LV2 client
1563 CarlaLv2Client client;
1565 // Load UI
1566 int ret;
1568 if (client.init(argc, argv))
1570 client.exec(testingModeOnly);
1571 ret = 0;
1573 else
1575 ret = 1;
1578 return ret;
1581 // --------------------------------------------------------------------------------------------------------------------
1583 #include "CarlaMacUtils.cpp"
1585 // --------------------------------------------------------------------------------------------------------------------