Cleanup
[carla.git] / source / utils / CarlaLv2Utils.hpp
blob7843cb97229a05704d9e3f0f2383a6832c2ffaea
1 /*
2 * Carla LV2 utils
3 * Copyright (C) 2011-2023 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 #ifndef CARLA_LV2_UTILS_HPP_INCLUDED
19 #define CARLA_LV2_UTILS_HPP_INCLUDED
21 #include "CarlaMathUtils.hpp"
22 #include "CarlaStringList.hpp"
23 #include "CarlaMIDI.h"
25 #ifndef nullptr
26 # undef NULL
27 # define NULL nullptr
28 #endif
30 // disable -Wdocumentation for LV2 headers
31 #if defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) > 300
32 # pragma clang diagnostic push
33 # pragma clang diagnostic ignored "-Wdocumentation"
34 #endif
36 #include "lv2/lv2.h"
37 #include "lv2/atom.h"
38 #include "lv2/atom-forge.h"
39 #include "lv2/atom-helpers.h"
40 #include "lv2/atom-util.h"
41 #include "lv2/buf-size.h"
42 #include "lv2/data-access.h"
43 // dynmanifest
44 #include "lv2/event.h"
45 #include "lv2/event-helpers.h"
46 #include "lv2/inline-display.h"
47 #include "lv2/instance-access.h"
48 #include "lv2/log.h"
49 // logger
50 #include "lv2/midi.h"
51 #include "lv2/midnam.h"
52 // morph
53 #include "lv2/options.h"
54 #include "lv2/parameters.h"
55 #include "lv2/patch.h"
56 #include "lv2/port-groups.h"
57 #include "lv2/port-props.h"
58 #include "lv2/presets.h"
59 #include "lv2/resize-port.h"
60 #include "lv2/state.h"
61 #include "lv2/time.h"
62 #include "lv2/ui.h"
63 #include "lv2/units.h"
64 #include "lv2/uri-map.h"
65 #include "lv2/urid.h"
66 #include "lv2/worker.h"
68 #include "lv2/lv2-miditype.h"
69 #include "lv2/lv2-midifunctions.h"
70 #include "lv2/lv2_external_ui.h"
71 #include "lv2/lv2_kxstudio_properties.h"
72 #include "lv2/lv2_programs.h"
73 #include "lv2/lv2_rtmempool.h"
75 #include "lv2/control-input-port-change-request.h"
77 #include "lilv/lilvmm.hpp"
78 #include "sratom/sratom.h"
79 #include "lilv/config/lilv_config.h"
81 // enable -Wdocumentation again
82 #if defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) > 300
83 # pragma clang diagnostic pop
84 #endif
86 #include "lv2_rdf.hpp"
88 #if defined(CARLA_UTILS_USE_QT)
89 # include <QtCore/QStringList>
90 #else
91 # include "water/text/StringArray.h"
92 #endif
94 // used for scalepoint sorting
95 #include <map>
96 typedef std::map<double,const LilvScalePoint*> LilvScalePointMap;
98 // --------------------------------------------------------------------------------------------------------------------
99 // Define namespaces and missing prefixes
101 #define NS_dct "http://purl.org/dc/terms/"
102 #define NS_doap "http://usefulinc.com/ns/doap#"
103 #define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
104 #define NS_rdfs "http://www.w3.org/2000/01/rdf-schema#"
105 #define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#"
106 #define NS_devp "http://lv2plug.in/ns/dev/extportinfo#"
107 #define NS_mod "http://moddevices.com/ns/modgui#"
109 #define LV2_MIDI_Map__CC "http://ll-plugins.nongnu.org/lv2/namespace#CC"
110 #define LV2_MIDI_Map__NRPN "http://ll-plugins.nongnu.org/lv2/namespace#NRPN"
112 #define LV2_MIDI_LL__MidiPort "http://ll-plugins.nongnu.org/lv2/ext/MidiPort"
114 #define LV2_UI__makeResident LV2_UI_PREFIX "makeResident"
115 #define LV2_UI__makeSONameResident LV2_UI_PREFIX "makeSONameResident"
117 // TODO: update LV2 headers once again
118 #define LV2_CORE__Parameter LV2_CORE_PREFIX "Parameter" ///< http://lv2plug.in/ns/lv2core#Parameter
119 #define LV2_CORE__enabled LV2_CORE_PREFIX "enabled" ///< http://lv2plug.in/ns/lv2core#enabled
120 #define LV2_CORE__isSideChain LV2_CORE_PREFIX "isSideChain" ///< http://lv2plug.in/ns/lv2core#isSideChain
122 // --------------------------------------------------------------------------------------------------------------------
123 // Custom Atom types
125 struct LV2_Atom_MidiEvent {
126 LV2_Atom atom; /**< Atom header. */
127 uint8_t data[4]; /**< MIDI data (body). */
130 static inline
131 uint32_t lv2_atom_total_size(const LV2_Atom_MidiEvent& midiEv)
133 return static_cast<uint32_t>(sizeof(LV2_Atom)) + midiEv.atom.size;
136 // ---------------------------------------------------------------------------------------------------------------------
137 // -Weffc++ compat ext widget
139 extern "C" {
141 typedef struct _LV2_External_UI_Widget_Compat {
142 void (*run )(struct _LV2_External_UI_Widget_Compat*);
143 void (*show)(struct _LV2_External_UI_Widget_Compat*);
144 void (*hide)(struct _LV2_External_UI_Widget_Compat*);
146 _LV2_External_UI_Widget_Compat() noexcept
147 : run(nullptr), show(nullptr), hide(nullptr) {}
149 } LV2_External_UI_Widget_Compat;
153 // --------------------------------------------------------------------------------------------------------------------
154 // Our LV2 World class
156 class Lv2WorldClass : public Lilv::World
158 public:
159 // Base Types
160 Lilv::Node port;
161 Lilv::Node symbol;
162 Lilv::Node designation;
163 Lilv::Node freeWheeling;
164 Lilv::Node reportsLatency;
166 // Plugin Types
167 Lilv::Node class_allpass;
168 Lilv::Node class_amplifier;
169 Lilv::Node class_analyzer;
170 Lilv::Node class_bandpass;
171 Lilv::Node class_chorus;
172 Lilv::Node class_comb;
173 Lilv::Node class_compressor;
174 Lilv::Node class_constant;
175 Lilv::Node class_converter;
176 Lilv::Node class_delay;
177 Lilv::Node class_distortion;
178 Lilv::Node class_dynamics;
179 Lilv::Node class_eq;
180 Lilv::Node class_envelope;
181 Lilv::Node class_expander;
182 Lilv::Node class_filter;
183 Lilv::Node class_flanger;
184 Lilv::Node class_function;
185 Lilv::Node class_gate;
186 Lilv::Node class_generator;
187 Lilv::Node class_highpass;
188 Lilv::Node class_instrument;
189 Lilv::Node class_limiter;
190 Lilv::Node class_lowpass;
191 Lilv::Node class_mixer;
192 Lilv::Node class_modulator;
193 Lilv::Node class_multiEQ;
194 Lilv::Node class_oscillator;
195 Lilv::Node class_paraEQ;
196 Lilv::Node class_phaser;
197 Lilv::Node class_pitch;
198 Lilv::Node class_reverb;
199 Lilv::Node class_simulator;
200 Lilv::Node class_spatial;
201 Lilv::Node class_spectral;
202 Lilv::Node class_utility;
203 Lilv::Node class_waveshaper;
205 // Port Types
206 Lilv::Node port_input;
207 Lilv::Node port_output;
208 Lilv::Node port_control;
209 Lilv::Node port_audio;
210 Lilv::Node port_cv;
211 Lilv::Node port_atom;
212 Lilv::Node port_event;
213 Lilv::Node port_midi;
215 // Port Properties
216 Lilv::Node pprop_optional;
217 Lilv::Node pprop_enumeration;
218 Lilv::Node pprop_integer;
219 Lilv::Node pprop_isSideChain;
220 Lilv::Node pprop_sampleRate;
221 Lilv::Node pprop_toggled;
222 Lilv::Node pprop_artifacts;
223 Lilv::Node pprop_continuousCV;
224 Lilv::Node pprop_discreteCV;
225 Lilv::Node pprop_expensive;
226 Lilv::Node pprop_strictBounds;
227 Lilv::Node pprop_logarithmic;
228 Lilv::Node pprop_notAutomatic;
229 Lilv::Node pprop_notOnGUI;
230 Lilv::Node pprop_trigger;
231 Lilv::Node pprop_nonAutomatable;
233 // Unit Hints
234 Lilv::Node unit_name;
235 Lilv::Node unit_render;
236 Lilv::Node unit_symbol;
237 Lilv::Node unit_unit;
239 // UI Types
240 Lilv::Node ui;
241 Lilv::Node ui_gtk2;
242 Lilv::Node ui_gtk3;
243 Lilv::Node ui_qt4;
244 Lilv::Node ui_qt5;
245 Lilv::Node ui_cocoa;
246 Lilv::Node ui_windows;
247 Lilv::Node ui_x11;
248 Lilv::Node ui_external;
249 Lilv::Node ui_externalOld;
251 // Misc
252 Lilv::Node atom_bufferType;
253 Lilv::Node atom_sequence;
254 Lilv::Node atom_supports;
256 Lilv::Node lv2_name;
257 Lilv::Node lv2_symbol;
258 Lilv::Node patch_readable;
259 Lilv::Node patch_writable;
260 Lilv::Node pg_group;
261 Lilv::Node pg_sideChainOf;
262 Lilv::Node preset_preset;
263 Lilv::Node state_state;
265 Lilv::Node ui_portIndex;
266 Lilv::Node ui_portNotif;
267 Lilv::Node ui_protocol;
269 Lilv::Node value_default;
270 Lilv::Node value_minimum;
271 Lilv::Node value_maximum;
273 Lilv::Node rz_asLargeAs;
274 Lilv::Node rz_minSize;
276 // Port Data Types
277 Lilv::Node midi_binding;
278 Lilv::Node midi_ctlrNumber;
279 Lilv::Node midi_event;
280 Lilv::Node patch_message;
281 Lilv::Node time_position;
283 // MIDI CC
284 Lilv::Node mm_defaultControl;
285 Lilv::Node mm_controlType;
286 Lilv::Node mm_controlNumber;
288 // Other
289 Lilv::Node dct_replaces;
290 Lilv::Node doap_license;
291 Lilv::Node rdf_type;
292 Lilv::Node rdfs_comment;
293 Lilv::Node rdfs_label;
294 Lilv::Node rdfs_range;
296 bool needsInit;
298 const LilvPlugins* allPlugins;
299 const LilvPlugin** cachedPlugins;
300 uint pluginCount;
302 // ----------------------------------------------------------------------------------------------------------------
304 Lv2WorldClass()
305 : Lilv::World(),
306 port (new_uri(LV2_CORE__port)),
307 symbol (new_uri(LV2_CORE__symbol)),
308 designation (new_uri(LV2_CORE__designation)),
309 freeWheeling (new_uri(LV2_CORE__freeWheeling)),
310 reportsLatency (new_uri(LV2_CORE__reportsLatency)),
312 class_allpass (new_uri(LV2_CORE__AllpassPlugin)),
313 class_amplifier (new_uri(LV2_CORE__AmplifierPlugin)),
314 class_analyzer (new_uri(LV2_CORE__AnalyserPlugin)),
315 class_bandpass (new_uri(LV2_CORE__BandpassPlugin)),
316 class_chorus (new_uri(LV2_CORE__ChorusPlugin)),
317 class_comb (new_uri(LV2_CORE__CombPlugin)),
318 class_compressor (new_uri(LV2_CORE__CompressorPlugin)),
319 class_constant (new_uri(LV2_CORE__ConstantPlugin)),
320 class_converter (new_uri(LV2_CORE__ConverterPlugin)),
321 class_delay (new_uri(LV2_CORE__DelayPlugin)),
322 class_distortion (new_uri(LV2_CORE__DistortionPlugin)),
323 class_dynamics (new_uri(LV2_CORE__DynamicsPlugin)),
324 class_eq (new_uri(LV2_CORE__EQPlugin)),
325 class_envelope (new_uri(LV2_CORE__EnvelopePlugin)),
326 class_expander (new_uri(LV2_CORE__ExpanderPlugin)),
327 class_filter (new_uri(LV2_CORE__FilterPlugin)),
328 class_flanger (new_uri(LV2_CORE__FlangerPlugin)),
329 class_function (new_uri(LV2_CORE__FunctionPlugin)),
330 class_gate (new_uri(LV2_CORE__GatePlugin)),
331 class_generator (new_uri(LV2_CORE__GeneratorPlugin)),
332 class_highpass (new_uri(LV2_CORE__HighpassPlugin)),
333 class_instrument (new_uri(LV2_CORE__InstrumentPlugin)),
334 class_limiter (new_uri(LV2_CORE__LimiterPlugin)),
335 class_lowpass (new_uri(LV2_CORE__LowpassPlugin)),
336 class_mixer (new_uri(LV2_CORE__MixerPlugin)),
337 class_modulator (new_uri(LV2_CORE__ModulatorPlugin)),
338 class_multiEQ (new_uri(LV2_CORE__MultiEQPlugin)),
339 class_oscillator (new_uri(LV2_CORE__OscillatorPlugin)),
340 class_paraEQ (new_uri(LV2_CORE__ParaEQPlugin)),
341 class_phaser (new_uri(LV2_CORE__PhaserPlugin)),
342 class_pitch (new_uri(LV2_CORE__PitchPlugin)),
343 class_reverb (new_uri(LV2_CORE__ReverbPlugin)),
344 class_simulator (new_uri(LV2_CORE__SimulatorPlugin)),
345 class_spatial (new_uri(LV2_CORE__SpatialPlugin)),
346 class_spectral (new_uri(LV2_CORE__SpectralPlugin)),
347 class_utility (new_uri(LV2_CORE__UtilityPlugin)),
348 class_waveshaper (new_uri(LV2_CORE__WaveshaperPlugin)),
350 port_input (new_uri(LV2_CORE__InputPort)),
351 port_output (new_uri(LV2_CORE__OutputPort)),
352 port_control (new_uri(LV2_CORE__ControlPort)),
353 port_audio (new_uri(LV2_CORE__AudioPort)),
354 port_cv (new_uri(LV2_CORE__CVPort)),
355 port_atom (new_uri(LV2_ATOM__AtomPort)),
356 port_event (new_uri(LV2_EVENT__EventPort)),
357 port_midi (new_uri(LV2_MIDI_LL__MidiPort)),
359 pprop_optional (new_uri(LV2_CORE__connectionOptional)),
360 pprop_enumeration (new_uri(LV2_CORE__enumeration)),
361 pprop_integer (new_uri(LV2_CORE__integer)),
362 pprop_isSideChain (new_uri(LV2_CORE__isSideChain)),
363 pprop_sampleRate (new_uri(LV2_CORE__sampleRate)),
364 pprop_toggled (new_uri(LV2_CORE__toggled)),
365 pprop_artifacts (new_uri(LV2_PORT_PROPS__causesArtifacts)),
366 pprop_continuousCV (new_uri(LV2_PORT_PROPS__continuousCV)),
367 pprop_discreteCV (new_uri(LV2_PORT_PROPS__discreteCV)),
368 pprop_expensive (new_uri(LV2_PORT_PROPS__expensive)),
369 pprop_strictBounds (new_uri(LV2_PORT_PROPS__hasStrictBounds)),
370 pprop_logarithmic (new_uri(LV2_PORT_PROPS__logarithmic)),
371 pprop_notAutomatic (new_uri(LV2_PORT_PROPS__notAutomatic)),
372 pprop_notOnGUI (new_uri(LV2_PORT_PROPS__notOnGUI)),
373 pprop_trigger (new_uri(LV2_PORT_PROPS__trigger)),
374 pprop_nonAutomatable (new_uri(LV2_KXSTUDIO_PROPERTIES__NonAutomatable)),
376 unit_name (new_uri(LV2_UNITS__name)),
377 unit_render (new_uri(LV2_UNITS__render)),
378 unit_symbol (new_uri(LV2_UNITS__symbol)),
379 unit_unit (new_uri(LV2_UNITS__unit)),
381 ui (new_uri(LV2_UI__UI)),
382 ui_gtk2 (new_uri(LV2_UI__GtkUI)),
383 ui_gtk3 (new_uri(LV2_UI__Gtk3UI)),
384 ui_qt4 (new_uri(LV2_UI__Qt4UI)),
385 ui_qt5 (new_uri(LV2_UI__Qt5UI)),
386 ui_cocoa (new_uri(LV2_UI__CocoaUI)),
387 ui_windows (new_uri(LV2_UI__WindowsUI)),
388 ui_x11 (new_uri(LV2_UI__X11UI)),
389 ui_external (new_uri(LV2_EXTERNAL_UI__Widget)),
390 ui_externalOld (new_uri(LV2_EXTERNAL_UI_DEPRECATED_URI)),
392 atom_bufferType (new_uri(LV2_ATOM__bufferType)),
393 atom_sequence (new_uri(LV2_ATOM__Sequence)),
394 atom_supports (new_uri(LV2_ATOM__supports)),
396 lv2_name (new_uri(LV2_CORE__name)),
397 lv2_symbol (new_uri(LV2_CORE__symbol)),
398 patch_readable (new_uri(LV2_PATCH__readable)),
399 patch_writable (new_uri(LV2_PATCH__writable)),
400 pg_group (new_uri(LV2_PORT_GROUPS__group)),
401 pg_sideChainOf (new_uri(LV2_PORT_GROUPS__sideChainOf)),
402 preset_preset (new_uri(LV2_PRESETS__Preset)),
403 state_state (new_uri(LV2_STATE__state)),
405 ui_portIndex (new_uri(LV2_UI__portIndex)),
406 ui_portNotif (new_uri(LV2_UI__portNotification)),
407 ui_protocol (new_uri(LV2_UI__protocol)),
409 value_default (new_uri(LV2_CORE__default)),
410 value_minimum (new_uri(LV2_CORE__minimum)),
411 value_maximum (new_uri(LV2_CORE__maximum)),
413 rz_asLargeAs (new_uri(LV2_RESIZE_PORT__asLargeAs)),
414 rz_minSize (new_uri(LV2_RESIZE_PORT__minimumSize)),
416 midi_binding (new_uri(LV2_MIDI__binding)),
417 midi_ctlrNumber (new_uri(LV2_MIDI__controllerNumber)),
418 midi_event (new_uri(LV2_MIDI__MidiEvent)),
419 patch_message (new_uri(LV2_PATCH__Message)),
420 time_position (new_uri(LV2_TIME__Position)),
422 mm_defaultControl (new_uri(NS_llmm "defaultMidiController")),
423 mm_controlType (new_uri(NS_llmm "controllerType")),
424 mm_controlNumber (new_uri(NS_llmm "controllerNumber")),
426 dct_replaces (new_uri(NS_dct "replaces")),
427 doap_license (new_uri(NS_doap "license")),
428 rdf_type (new_uri(NS_rdf "type")),
429 rdfs_comment (new_uri(NS_rdfs "comment")),
430 rdfs_label (new_uri(NS_rdfs "label")),
431 rdfs_range (new_uri(NS_rdfs "range")),
433 needsInit(true),
434 allPlugins(nullptr),
435 cachedPlugins(nullptr),
436 pluginCount(0) {}
438 ~Lv2WorldClass() override
440 pluginCount = 0;
441 allPlugins = nullptr;
443 if (cachedPlugins != nullptr)
445 delete[] cachedPlugins;
446 cachedPlugins = nullptr;
450 // FIXME - remove this
451 static Lv2WorldClass& getInstance()
453 static Lv2WorldClass lv2World;
454 return lv2World;
457 void initIfNeeded(const char* LV2_PATH)
459 if (LV2_PATH == nullptr || LV2_PATH[0] == '\0')
461 static const char* const DEFAULT_LV2_PATH = LILV_DEFAULT_LV2_PATH;
462 LV2_PATH = DEFAULT_LV2_PATH;
465 if (! needsInit)
466 return;
468 needsInit = false;
470 Lilv::World::load_all(LV2_PATH);
472 allPlugins = lilv_world_get_all_plugins(this->me);
473 CARLA_SAFE_ASSERT_RETURN(allPlugins != nullptr,);
475 if ((pluginCount = lilv_plugins_size(allPlugins)))
477 cachedPlugins = new const LilvPlugin*[pluginCount+1];
478 carla_zeroPointers(cachedPlugins, pluginCount+1);
480 int i = 0;
481 for (LilvIter* it = lilv_plugins_begin(allPlugins); ! lilv_plugins_is_end(allPlugins, it); it = lilv_plugins_next(allPlugins, it))
482 cachedPlugins[i++] = lilv_plugins_get(allPlugins, it);
486 void load_bundle(const char* const bundle)
488 CARLA_SAFE_ASSERT_RETURN(bundle != nullptr && bundle[0] != '\0',);
489 CARLA_SAFE_ASSERT_RETURN(needsInit,);
491 needsInit = false;
492 Lilv::World::load_bundle(Lilv::Node(new_uri(bundle)));
494 allPlugins = lilv_world_get_all_plugins(this->me);
495 CARLA_SAFE_ASSERT_RETURN(allPlugins != nullptr,);
497 if ((pluginCount = lilv_plugins_size(allPlugins)))
499 cachedPlugins = new const LilvPlugin*[pluginCount+1];
500 carla_zeroPointers(cachedPlugins, pluginCount+1);
502 int i = 0;
503 for (LilvIter* it = lilv_plugins_begin(allPlugins); ! lilv_plugins_is_end(allPlugins, it); it = lilv_plugins_next(allPlugins, it))
504 cachedPlugins[i++] = lilv_plugins_get(allPlugins, it);
508 uint getPluginCount() const
510 CARLA_SAFE_ASSERT_RETURN(! needsInit, 0);
512 return pluginCount;
515 const LilvPlugin* getPluginFromIndex(const uint index) const
517 CARLA_SAFE_ASSERT_RETURN(! needsInit, nullptr);
518 CARLA_SAFE_ASSERT_RETURN(cachedPlugins != nullptr, nullptr);
519 CARLA_SAFE_ASSERT_RETURN(index < pluginCount, nullptr);
521 return cachedPlugins[index];
524 const LilvPlugin* getPluginFromURI(const LV2_URI uri) const
526 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', nullptr);
527 CARLA_SAFE_ASSERT_RETURN(! needsInit, nullptr);
528 CARLA_SAFE_ASSERT_RETURN(allPlugins != nullptr, nullptr);
530 LilvNode* const uriNode(lilv_new_uri(this->me, uri));
531 CARLA_SAFE_ASSERT_RETURN(uriNode != nullptr, nullptr);
533 const LilvPlugin* const cPlugin(lilv_plugins_get_by_uri(allPlugins, uriNode));
534 lilv_node_free(uriNode);
536 return cPlugin;
539 LilvState* getStateFromURI(const LV2_URI uri, const LV2_URID_Map* const uridMap) const
541 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', nullptr);
542 CARLA_SAFE_ASSERT_RETURN(uridMap != nullptr, nullptr);
543 CARLA_SAFE_ASSERT_RETURN(! needsInit, nullptr);
545 LilvNode* const uriNode(lilv_new_uri(this->me, uri));
546 CARLA_SAFE_ASSERT_RETURN(uriNode != nullptr, nullptr);
548 CARLA_SAFE_ASSERT(lilv_world_load_resource(this->me, uriNode) >= 0);
550 LilvState* const cState(lilv_state_new_from_world(this->me, uridMap, uriNode));
551 lilv_node_free(uriNode);
553 return cState;
556 CARLA_PREVENT_VIRTUAL_HEAP_ALLOCATION
557 CARLA_DECLARE_NON_COPYABLE(Lv2WorldClass)
560 // --------------------------------------------------------------------------------------------------------------------
561 // Our LV2 Plugin base class
563 #if defined(__clang__)
564 # pragma clang diagnostic push
565 # pragma clang diagnostic ignored "-Weffc++"
566 # pragma clang diagnostic ignored "-Wnon-virtual-dtor"
567 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
568 # pragma GCC diagnostic push
569 # pragma GCC diagnostic ignored "-Weffc++"
570 # pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
571 #endif
572 template<class TimeInfoStruct>
573 class Lv2PluginBaseClass : public LV2_External_UI_Widget_Compat
575 #if defined(__clang__)
576 # pragma clang diagnostic pop
577 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
578 # pragma GCC diagnostic pop
579 #endif
580 public:
581 Lv2PluginBaseClass(const double sampleRate, const LV2_Feature* const* const features)
582 : fIsActive(false),
583 fIsOffline(false),
584 fUsingNominal(false),
585 fBufferSize(0),
586 fSampleRate(sampleRate),
587 fFreePath(nullptr),
588 fUridMap(nullptr),
589 fUridUnmap(nullptr),
590 fWorker(nullptr),
591 fInlineDisplay(nullptr),
592 fTimeInfo(),
593 fLastPositionData(),
594 fPorts(),
595 fURIs(),
596 fUI()
598 run = extui_run;
599 show = extui_show;
600 hide = extui_hide;
602 if (fSampleRate < 1.0)
604 carla_stderr("Host doesn't provide a valid sample rate");
605 return;
608 const LV2_State_Free_Path* freePath = nullptr;
609 const LV2_Options_Option* options = nullptr;
610 const LV2_URID_Map* uridMap = nullptr;
611 const LV2_URID_Unmap* uridUnmap = nullptr;
612 const LV2_Worker_Schedule* worker = nullptr;
613 const LV2_Inline_Display* idisp = nullptr;
615 for (int i=0; features[i] != nullptr; ++i)
617 /**/ if (std::strcmp(features[i]->URI, LV2_STATE__freePath) == 0)
618 freePath = (const LV2_State_Free_Path*)features[i]->data;
619 else if (std::strcmp(features[i]->URI, LV2_OPTIONS__options) == 0)
620 options = (const LV2_Options_Option*)features[i]->data;
621 else if (std::strcmp(features[i]->URI, LV2_URID__map) == 0)
622 uridMap = (const LV2_URID_Map*)features[i]->data;
623 else if (std::strcmp(features[i]->URI, LV2_URID__unmap) == 0)
624 uridUnmap = (const LV2_URID_Unmap*)features[i]->data;
625 else if (std::strcmp(features[i]->URI, LV2_WORKER__schedule) == 0)
626 worker = (const LV2_Worker_Schedule*)features[i]->data;
627 else if (std::strcmp(features[i]->URI, LV2_INLINEDISPLAY__queue_draw) == 0)
628 idisp = (const LV2_Inline_Display*)features[i]->data;
631 if (options == nullptr || uridMap == nullptr)
633 carla_stderr("Host doesn't provide option and urid-map features");
634 return;
637 for (int i=0; options[i].key != 0; ++i)
639 if (uridUnmap != nullptr) {
640 carla_debug("Host option %i:\"%s\"", i, uridUnmap->unmap(uridUnmap->handle, options[i].key));
643 if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__nominalBlockLength))
645 if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
647 const int32_t value(*(const int32_t*)options[i].value);
648 CARLA_SAFE_ASSERT_CONTINUE(value > 0);
650 fBufferSize = static_cast<uint32_t>(value);
651 fUsingNominal = true;
653 else
655 carla_stderr("Host provides nominalBlockLength but has wrong value type");
657 break;
660 if (options[i].key == uridMap->map(uridMap->handle, LV2_BUF_SIZE__maxBlockLength))
662 if (options[i].type == uridMap->map(uridMap->handle, LV2_ATOM__Int))
664 const int32_t value(*(const int32_t*)options[i].value);
665 CARLA_SAFE_ASSERT_CONTINUE(value > 0);
667 fBufferSize = static_cast<uint32_t>(value);
669 else
671 carla_stderr("Host provides maxBlockLength but has wrong value type");
673 // no break, continue in case host supports nominalBlockLength
677 if (fBufferSize == 0)
679 carla_stderr("Host doesn't provide buffer-size feature");
680 //return;
681 // as testing, continue for now
682 fBufferSize = 1024;
685 fUridMap = uridMap;
686 fURIs.map(uridMap);
688 fFreePath = freePath;
689 fUridUnmap = uridUnmap;
690 fWorker = worker;
691 fInlineDisplay = idisp;
693 clearTimeData();
696 virtual ~Lv2PluginBaseClass() {}
698 bool loadedInProperHost() const noexcept
700 return fUridMap != nullptr && fBufferSize != 0;
703 // ----------------------------------------------------------------------------------------------------------------
705 void lv2_connect_port(const uint32_t port, void* const dataLocation) noexcept
707 fPorts.connectPort(port, dataLocation);
710 bool lv2_pre_run(const uint32_t frames)
712 CARLA_SAFE_ASSERT_RETURN(fIsActive, false);
714 fIsOffline = (fPorts.freewheel != nullptr && *fPorts.freewheel >= 0.5f);
716 // cache midi events and time information first
717 if (fPorts.usesTime)
719 LV2_ATOM_SEQUENCE_FOREACH(fPorts.eventsIn[0], event)
721 if (event == nullptr)
722 continue;
723 if (event->body.type != fURIs.atomBlank && event->body.type != fURIs.atomObject)
724 continue;
726 const LV2_Atom_Object* const obj((const LV2_Atom_Object*)&event->body);
728 if (obj->body.otype != fURIs.timePos)
729 continue;
731 LV2_Atom* bar = nullptr;
732 LV2_Atom* barBeat = nullptr;
733 LV2_Atom* beatUnit = nullptr;
734 LV2_Atom* beatsPerBar = nullptr;
735 LV2_Atom* beatsPerMinute = nullptr;
736 LV2_Atom* frame = nullptr;
737 LV2_Atom* speed = nullptr;
738 LV2_Atom* ticksPerBeat = nullptr;
740 lv2_atom_object_get(obj,
741 fURIs.timeBar, &bar,
742 fURIs.timeBarBeat, &barBeat,
743 fURIs.timeBeatUnit, &beatUnit,
744 fURIs.timeBeatsPerBar, &beatsPerBar,
745 fURIs.timeBeatsPerMinute, &beatsPerMinute,
746 fURIs.timeFrame, &frame,
747 fURIs.timeSpeed, &speed,
748 fURIs.timeTicksPerBeat, &ticksPerBeat,
751 // need to handle this first as other values depend on it
752 if (ticksPerBeat != nullptr)
754 double ticksPerBeatValue = -1.0;
756 /**/ if (ticksPerBeat->type == fURIs.atomDouble)
757 ticksPerBeatValue = ((LV2_Atom_Double*)ticksPerBeat)->body;
758 else if (ticksPerBeat->type == fURIs.atomFloat)
759 ticksPerBeatValue = ((LV2_Atom_Float*)ticksPerBeat)->body;
760 else if (ticksPerBeat->type == fURIs.atomInt)
761 ticksPerBeatValue = static_cast<double>(((LV2_Atom_Int*)ticksPerBeat)->body);
762 else if (ticksPerBeat->type == fURIs.atomLong)
763 ticksPerBeatValue = static_cast<double>(((LV2_Atom_Long*)ticksPerBeat)->body);
764 else
765 carla_stderr("Unknown lv2 ticksPerBeat value type");
767 if (ticksPerBeatValue > 0.0)
768 fTimeInfo.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat = ticksPerBeatValue;
769 else
770 carla_stderr("Invalid lv2 ticksPerBeat value");
773 // same
774 if (speed != nullptr)
776 /**/ if (speed->type == fURIs.atomDouble)
777 fLastPositionData.speed = ((LV2_Atom_Double*)speed)->body;
778 else if (speed->type == fURIs.atomFloat)
779 fLastPositionData.speed = ((LV2_Atom_Float*)speed)->body;
780 else if (speed->type == fURIs.atomInt)
781 fLastPositionData.speed = static_cast<double>(((LV2_Atom_Int*)speed)->body);
782 else if (speed->type == fURIs.atomLong)
783 fLastPositionData.speed = static_cast<double>(((LV2_Atom_Long*)speed)->body);
784 else
785 carla_stderr("Unknown lv2 speed value type");
787 fTimeInfo.playing = carla_isNotZero(fLastPositionData.speed);
789 if (fTimeInfo.playing && fLastPositionData.beatsPerMinute > 0.0)
791 fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute*
792 std::abs(fLastPositionData.speed);
796 if (bar != nullptr)
798 int64_t barValue = -1;
800 /**/ if (bar->type == fURIs.atomDouble)
801 barValue = static_cast<int64_t>(((LV2_Atom_Double*)bar)->body);
802 else if (bar->type == fURIs.atomFloat)
803 barValue = static_cast<int64_t>(((LV2_Atom_Float*)bar)->body);
804 else if (bar->type == fURIs.atomInt)
805 barValue = ((LV2_Atom_Int*)bar)->body;
806 else if (bar->type == fURIs.atomLong)
807 barValue = ((LV2_Atom_Long*)bar)->body;
808 else
809 carla_stderr("Unknown lv2 bar value type");
811 if (barValue >= 0 && barValue < INT32_MAX)
813 fLastPositionData.bar = static_cast<int32_t>(barValue);
814 fLastPositionData.bar_f = static_cast<float>(barValue);
815 fTimeInfo.bbt.bar = fLastPositionData.bar + 1;
817 else
819 carla_stderr("Invalid lv2 bar value");
823 if (barBeat != nullptr)
825 double barBeatValue = -1.0;
827 /**/ if (barBeat->type == fURIs.atomDouble)
828 barBeatValue = ((LV2_Atom_Double*)barBeat)->body;
829 else if (barBeat->type == fURIs.atomFloat)
830 barBeatValue = ((LV2_Atom_Float*)barBeat)->body;
831 else if (barBeat->type == fURIs.atomInt)
832 barBeatValue = static_cast<float>(((LV2_Atom_Int*)barBeat)->body);
833 else if (barBeat->type == fURIs.atomLong)
834 barBeatValue = static_cast<float>(((LV2_Atom_Long*)barBeat)->body);
835 else
836 carla_stderr("Unknown lv2 barBeat value type");
838 if (barBeatValue >= 0.0)
840 fLastPositionData.barBeat = static_cast<float>(barBeatValue);
842 const double rest = std::fmod(barBeatValue, 1.0);
843 fTimeInfo.bbt.beat = static_cast<int32_t>(barBeatValue-rest+1.0);
844 fTimeInfo.bbt.tick = static_cast<int32_t>(rest*fTimeInfo.bbt.ticksPerBeat+0.5);
846 else
848 carla_stderr("Invalid lv2 barBeat value");
852 if (beatUnit != nullptr)
854 int64_t beatUnitValue = -1;
856 /**/ if (beatUnit->type == fURIs.atomDouble)
857 beatUnitValue = static_cast<int64_t>(((LV2_Atom_Double*)beatUnit)->body);
858 else if (beatUnit->type == fURIs.atomFloat)
859 beatUnitValue = static_cast<int64_t>(((LV2_Atom_Float*)beatUnit)->body);
860 else if (beatUnit->type == fURIs.atomInt)
861 beatUnitValue = ((LV2_Atom_Int*)beatUnit)->body;
862 else if (beatUnit->type == fURIs.atomLong)
863 beatUnitValue = ((LV2_Atom_Long*)beatUnit)->body;
864 else
865 carla_stderr("Unknown lv2 beatUnit value type");
867 if (beatUnitValue > 0 && beatUnitValue < UINT32_MAX)
869 fLastPositionData.beatUnit = static_cast<uint32_t>(beatUnitValue);
870 fTimeInfo.bbt.beatType = static_cast<float>(beatUnitValue);
872 else
874 carla_stderr("Invalid lv2 beatUnit value");
878 if (beatsPerBar != nullptr)
880 float beatsPerBarValue = -1.0f;
882 /**/ if (beatsPerBar->type == fURIs.atomDouble)
883 beatsPerBarValue = static_cast<float>(((LV2_Atom_Double*)beatsPerBar)->body);
884 else if (beatsPerBar->type == fURIs.atomFloat)
885 beatsPerBarValue = ((LV2_Atom_Float*)beatsPerBar)->body;
886 else if (beatsPerBar->type == fURIs.atomInt)
887 beatsPerBarValue = static_cast<float>(((LV2_Atom_Int*)beatsPerBar)->body);
888 else if (beatsPerBar->type == fURIs.atomLong)
889 beatsPerBarValue = static_cast<float>(((LV2_Atom_Long*)beatsPerBar)->body);
890 else
891 carla_stderr("Unknown lv2 beatsPerBar value type");
893 if (beatsPerBarValue > 0.0f)
894 fTimeInfo.bbt.beatsPerBar = fLastPositionData.beatsPerBar = beatsPerBarValue;
895 else
896 carla_stderr("Invalid lv2 beatsPerBar value");
899 if (beatsPerMinute != nullptr)
901 double beatsPerMinuteValue = -1.0;
903 /**/ if (beatsPerMinute->type == fURIs.atomDouble)
904 beatsPerMinuteValue = ((LV2_Atom_Double*)beatsPerMinute)->body;
905 else if (beatsPerMinute->type == fURIs.atomFloat)
906 beatsPerMinuteValue = ((LV2_Atom_Float*)beatsPerMinute)->body;
907 else if (beatsPerMinute->type == fURIs.atomInt)
908 beatsPerMinuteValue = static_cast<double>(((LV2_Atom_Int*)beatsPerMinute)->body);
909 else if (beatsPerMinute->type == fURIs.atomLong)
910 beatsPerMinuteValue = static_cast<double>(((LV2_Atom_Long*)beatsPerMinute)->body);
911 else
912 carla_stderr("Unknown lv2 beatsPerMinute value type");
914 if (beatsPerMinuteValue >= 12.0 && beatsPerMinuteValue <= 999.0)
916 fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute = beatsPerMinuteValue;
918 if (carla_isNotZero(fLastPositionData.speed))
919 fTimeInfo.bbt.beatsPerMinute *= std::abs(fLastPositionData.speed);
921 else
923 carla_stderr("Invalid lv2 beatsPerMinute value");
927 if (frame != nullptr)
929 int64_t frameValue = -1;
931 /**/ if (frame->type == fURIs.atomDouble)
932 frameValue = static_cast<int64_t>(((LV2_Atom_Double*)frame)->body);
933 else if (frame->type == fURIs.atomFloat)
934 frameValue = static_cast<int64_t>(((LV2_Atom_Float*)frame)->body);
935 else if (frame->type == fURIs.atomInt)
936 frameValue = ((LV2_Atom_Int*)frame)->body;
937 else if (frame->type == fURIs.atomLong)
938 frameValue = ((LV2_Atom_Long*)frame)->body;
939 else
940 carla_stderr("Unknown lv2 frame value type");
942 if (frameValue >= 0)
943 fTimeInfo.frame = fLastPositionData.frame = static_cast<uint64_t>(frameValue);
944 else
945 carla_stderr("Invalid lv2 frame value");
948 fTimeInfo.bbt.barStartTick = static_cast<double>(fTimeInfo.bbt.ticksPerBeat) *
949 static_cast<double>(fTimeInfo.bbt.beatsPerBar) *
950 (fTimeInfo.bbt.bar-1);
952 fTimeInfo.bbt.valid = (fLastPositionData.beatsPerMinute > 0.0 &&
953 fLastPositionData.beatUnit > 0 &&
954 fLastPositionData.beatsPerBar > 0.0f);
958 // Check for updated parameters
959 float curValue;
961 for (uint32_t i=0; i < fPorts.numParams; ++i)
963 if (fPorts.paramsOut[i])
964 continue;
966 CARLA_SAFE_ASSERT_CONTINUE(fPorts.paramsPtr[i] != nullptr)
968 curValue = *fPorts.paramsPtr[i];
970 if (carla_isEqual(fPorts.paramsLast[i], curValue))
971 continue;
973 fPorts.paramsLast[i] = curValue;
974 handleParameterValueChanged(i, curValue);
977 // init event out data
978 if (fPorts.numMidiOuts > 0 || fPorts.hasUI)
980 const uint32_t count = fPorts.numMidiOuts > 0 ? fPorts.numMidiOuts : 1;
982 for (uint32_t i=0; i < count; ++i)
984 LV2_Atom_Sequence* const seq(fPorts.eventsOut[i]);
985 CARLA_SAFE_ASSERT_CONTINUE(seq != nullptr);
987 fPorts.eventsOutData[i].capacity = seq->atom.size;
988 fPorts.eventsOutData[i].offset = 0;
990 seq->atom.size = sizeof(LV2_Atom_Sequence_Body);
991 seq->atom.type = fURIs.atomSequence;
992 seq->body.unit = 0;
993 seq->body.pad = 0;
997 if (frames == 0)
998 return false;
1000 return true;
1003 void lv2_post_run(const uint32_t frames)
1005 // update timePos for next callback
1007 if (carla_isZero(fLastPositionData.speed))
1008 return;
1010 if (fLastPositionData.speed > 0.0)
1012 // playing forwards
1013 fLastPositionData.frame += frames;
1015 else
1017 // playing backwards
1018 if (frames >= fLastPositionData.frame)
1019 fLastPositionData.frame = 0;
1020 else
1021 fLastPositionData.frame -= frames;
1024 fTimeInfo.frame = fLastPositionData.frame;
1026 if (fTimeInfo.bbt.valid)
1028 const double beatsPerMinute = fLastPositionData.beatsPerMinute * fLastPositionData.speed;
1029 const double framesPerBeat = 60.0 * fSampleRate / beatsPerMinute;
1030 const double addedBarBeats = double(frames) / framesPerBeat;
1032 if (fLastPositionData.barBeat >= 0.0f)
1034 fLastPositionData.barBeat = std::fmod(fLastPositionData.barBeat+static_cast<float>(addedBarBeats),
1035 fLastPositionData.beatsPerBar);
1037 const double rest = std::fmod(fLastPositionData.barBeat, 1.0f);
1038 fTimeInfo.bbt.beat = static_cast<int32_t>(static_cast<double>(fLastPositionData.barBeat)-rest+1.0);
1039 fTimeInfo.bbt.tick = rest * fTimeInfo.bbt.ticksPerBeat;
1041 if (fLastPositionData.bar_f >= 0.0f)
1043 fLastPositionData.bar_f += std::floor((fLastPositionData.barBeat+static_cast<float>(addedBarBeats))/
1044 fLastPositionData.beatsPerBar);
1046 if (fLastPositionData.bar_f <= 0.0f)
1048 fLastPositionData.bar = 0;
1049 fLastPositionData.bar_f = 0.0f;
1051 else
1053 fLastPositionData.bar = static_cast<int32_t>(fLastPositionData.bar_f+0.5f);
1056 fTimeInfo.bbt.bar = fLastPositionData.bar + 1;
1058 fTimeInfo.bbt.barStartTick = static_cast<double>(fTimeInfo.bbt.ticksPerBeat) *
1059 static_cast<double>(fTimeInfo.bbt.beatsPerBar) *
1060 (fTimeInfo.bbt.bar-1);
1066 // ----------------------------------------------------------------------------------------------------------------
1068 uint32_t lv2_get_options(LV2_Options_Option* const /*options*/) const
1070 // currently unused
1071 return LV2_OPTIONS_SUCCESS;
1074 uint32_t lv2_set_options(const LV2_Options_Option* const options)
1076 for (int i=0; options[i].key != 0; ++i)
1078 if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__nominalBlockLength))
1080 if (options[i].type == fURIs.atomInt)
1082 const int32_t value(*(const int32_t*)options[i].value);
1083 CARLA_SAFE_ASSERT_CONTINUE(value > 0);
1085 const uint32_t newBufferSize = static_cast<uint32_t>(value);
1087 if (fBufferSize != newBufferSize)
1089 fBufferSize = newBufferSize;
1090 handleBufferSizeChanged(newBufferSize);
1093 else
1095 carla_stderr("Host changed nominalBlockLength but with wrong value type");
1098 else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_BUF_SIZE__maxBlockLength) && ! fUsingNominal)
1100 if (options[i].type == fURIs.atomInt)
1102 const int32_t value(*(const int32_t*)options[i].value);
1103 CARLA_SAFE_ASSERT_CONTINUE(value > 0);
1105 const uint32_t newBufferSize = static_cast<uint32_t>(value);
1107 if (fBufferSize != newBufferSize)
1109 fBufferSize = newBufferSize;
1110 handleBufferSizeChanged(newBufferSize);
1113 else
1115 carla_stderr("Host changed maxBlockLength but with wrong value type");
1118 else if (options[i].key == fUridMap->map(fUridMap->handle, LV2_PARAMETERS__sampleRate))
1120 if (options[i].type == fURIs.atomFloat)
1122 const double value(*(const float*)options[i].value);
1123 CARLA_SAFE_ASSERT_CONTINUE(value > 0.0);
1125 if (carla_isNotEqual(fSampleRate, value))
1127 fSampleRate = value;
1128 handleSampleRateChanged(value);
1131 else
1133 carla_stderr("Host changed sampleRate but with wrong value type");
1138 return LV2_OPTIONS_SUCCESS;
1141 // ----------------------------------------------------------------------------------------------------------------
1143 int lv2ui_idle() const
1145 if (! fUI.isVisible)
1146 return 1;
1148 handleUiRun();
1149 return 0;
1152 int lv2ui_show()
1154 handleUiShow();
1155 return 0;
1158 int lv2ui_hide()
1160 handleUiHide();
1161 return 0;
1164 void lv2ui_cleanup()
1166 if (fUI.isVisible)
1167 handleUiHide();
1169 fUI.host = nullptr;
1170 fUI.touch = nullptr;
1171 fUI.writeFunction = nullptr;
1172 fUI.controller = nullptr;
1175 // ----------------------------------------------------------------------------------------------------------------
1177 protected:
1178 virtual void handleUiRun() const = 0;
1179 virtual void handleUiShow() = 0;
1180 virtual void handleUiHide() = 0;
1182 virtual void handleParameterValueChanged(const uint32_t index, const float value) = 0;
1183 virtual void handleBufferSizeChanged(const uint32_t bufferSize) = 0;
1184 virtual void handleSampleRateChanged(const double sampleRate) = 0;
1186 void resetTimeInfo() noexcept
1188 clearTimeData();
1190 // hosts may not send all values, resulting on some invalid data
1191 fTimeInfo.bbt.bar = 1;
1192 fTimeInfo.bbt.beat = 1;
1193 fTimeInfo.bbt.beatsPerBar = 4;
1194 fTimeInfo.bbt.beatType = 4;
1195 fTimeInfo.bbt.ticksPerBeat = fLastPositionData.ticksPerBeat = 960.0;
1196 fTimeInfo.bbt.beatsPerMinute = fLastPositionData.beatsPerMinute = 120.0;
1199 // LV2 host data
1200 bool fIsActive : 1;
1201 bool fIsOffline : 1;
1202 bool fUsingNominal : 1;
1203 uint32_t fBufferSize;
1204 double fSampleRate;
1206 // LV2 host features
1207 const LV2_State_Free_Path* fFreePath;
1208 const LV2_URID_Map* fUridMap;
1209 const LV2_URID_Unmap* fUridUnmap;
1210 const LV2_Worker_Schedule* fWorker;
1211 const LV2_Inline_Display* fInlineDisplay;
1213 // Time info stuff
1214 TimeInfoStruct fTimeInfo;
1216 struct Lv2PositionData {
1217 int32_t bar;
1218 float bar_f;
1219 float barBeat;
1220 uint32_t beatUnit;
1221 float beatsPerBar;
1222 double beatsPerMinute;
1223 uint64_t frame;
1224 double speed;
1225 double ticksPerBeat;
1227 Lv2PositionData()
1228 : bar(-1),
1229 bar_f(-1.0f),
1230 barBeat(-1.0f),
1231 beatUnit(0),
1232 beatsPerBar(0.0f),
1233 beatsPerMinute(-1.0),
1234 frame(0),
1235 speed(0.0),
1236 ticksPerBeat(-1.0) {}
1238 void clear()
1240 bar = -1;
1241 bar_f = -1.0f;
1242 barBeat = -1.0f;
1243 beatUnit = 0;
1244 beatsPerBar = 0.0f;
1245 beatsPerMinute = -1.0;
1246 frame = 0;
1247 speed = 0.0;
1248 ticksPerBeat = -1.0;
1251 } fLastPositionData;
1253 // Port stuff
1254 struct Ports {
1255 // need to save current state
1256 struct EventsOutData {
1257 uint32_t capacity;
1258 uint32_t offset;
1260 EventsOutData()
1261 : capacity(0),
1262 offset(0) {}
1265 // store port info
1266 uint32_t indexOffset;
1267 uint32_t numAudioIns;
1268 uint32_t numAudioOuts;
1269 uint32_t numCVIns;
1270 uint32_t numCVOuts;
1271 uint32_t numMidiIns;
1272 uint32_t numMidiOuts;
1273 uint32_t numParams;
1274 bool hasUI;
1275 bool usesTime;
1277 // port buffers
1278 const LV2_Atom_Sequence** eventsIn;
1279 /* */ LV2_Atom_Sequence** eventsOut;
1280 /* */ EventsOutData* eventsOutData;
1281 /* */ float** audioCVIns;
1282 /* */ float** audioCVOuts;
1283 /* */ float* freewheel;
1285 // cached parameter values
1286 float* paramsLast;
1287 float** paramsPtr;
1288 bool* paramsOut;
1290 Ports()
1291 : indexOffset(0),
1292 numAudioIns(0),
1293 numAudioOuts(0),
1294 numCVIns(0),
1295 numCVOuts(0),
1296 numMidiIns(0),
1297 numMidiOuts(0),
1298 numParams(0),
1299 hasUI(false),
1300 usesTime(false),
1301 eventsIn(nullptr),
1302 eventsOut(nullptr),
1303 eventsOutData(nullptr),
1304 audioCVIns(nullptr),
1305 audioCVOuts(nullptr),
1306 freewheel(nullptr),
1307 paramsLast(nullptr),
1308 paramsPtr(nullptr),
1309 paramsOut(nullptr) {}
1311 ~Ports()
1313 if (eventsIn != nullptr)
1315 delete[] eventsIn;
1316 eventsIn = nullptr;
1319 if (eventsOut != nullptr)
1321 delete[] eventsOut;
1322 eventsOut = nullptr;
1325 if (eventsOutData != nullptr)
1327 delete[] eventsOutData;
1328 eventsOutData = nullptr;
1331 if (audioCVIns != nullptr)
1333 delete[] audioCVIns;
1334 audioCVIns = nullptr;
1337 if (audioCVOuts != nullptr)
1339 delete[] audioCVOuts;
1340 audioCVOuts = nullptr;
1343 if (paramsLast != nullptr)
1345 delete[] paramsLast;
1346 paramsLast = nullptr;
1349 if (paramsPtr != nullptr)
1351 delete[] paramsPtr;
1352 paramsPtr = nullptr;
1355 if (paramsOut != nullptr)
1357 delete[] paramsOut;
1358 paramsOut = nullptr;
1362 // NOTE: assumes num* has been filled by parent class
1363 void init()
1365 if (numMidiIns > 0)
1367 eventsIn = new const LV2_Atom_Sequence*[numMidiIns];
1369 for (uint32_t i=0; i < numMidiIns; ++i)
1370 eventsIn[i] = nullptr;
1372 else if (usesTime || hasUI)
1374 eventsIn = new const LV2_Atom_Sequence*[1];
1375 eventsIn[0] = nullptr;
1378 if (numMidiOuts > 0)
1380 eventsOut = new LV2_Atom_Sequence*[numMidiOuts];
1381 eventsOutData = new EventsOutData[numMidiOuts];
1383 for (uint32_t i=0; i < numMidiOuts; ++i)
1384 eventsOut[i] = nullptr;
1386 else if (hasUI)
1388 eventsOut = new LV2_Atom_Sequence*[1];
1389 eventsOut[0] = nullptr;
1390 eventsOutData = new EventsOutData[1];
1393 if (const uint32_t numAudioCVIns = numAudioIns+numCVIns)
1395 audioCVIns = new float*[numAudioCVIns];
1396 carla_zeroPointers(audioCVIns, numAudioCVIns);
1399 if (const uint32_t numAudioCVOuts = numAudioOuts+numCVOuts)
1401 audioCVOuts = new float*[numAudioCVOuts];
1402 carla_zeroPointers(audioCVOuts, numAudioCVOuts);
1405 if (numParams > 0)
1407 paramsLast = new float[numParams];
1408 paramsPtr = new float*[numParams];
1409 paramsOut = new bool[numParams];
1411 carla_zeroFloats(paramsLast, numParams);
1412 carla_zeroPointers(paramsPtr, numParams);
1413 carla_zeroStructs(paramsOut, numParams);
1415 // NOTE: need to be filled in by the parent class
1418 indexOffset = numAudioIns + numAudioOuts + numCVIns + numCVOuts;
1419 // 1 event port for time or ui if no midi input is used
1420 indexOffset += numMidiIns > 0 ? numMidiIns : ((usesTime || hasUI) ? 1 : 0);
1421 // 1 event port for ui if no midi output is used
1422 indexOffset += numMidiOuts > 0 ? numMidiOuts : (hasUI ? 1 : 0);
1423 // 1 extra for freewheel port
1424 indexOffset += 1;
1427 void connectPort(const uint32_t port, void* const dataLocation)
1429 uint32_t index = 0;
1431 if (numMidiIns > 0 || usesTime || hasUI)
1433 if (port == index++)
1435 eventsIn[0] = (LV2_Atom_Sequence*)dataLocation;
1436 return;
1440 for (uint32_t i=1; i < numMidiIns; ++i)
1442 if (port == index++)
1444 eventsIn[i] = (LV2_Atom_Sequence*)dataLocation;
1445 return;
1449 if (numMidiOuts > 0 || hasUI)
1451 if (port == index++)
1453 eventsOut[0] = (LV2_Atom_Sequence*)dataLocation;
1454 return;
1458 for (uint32_t i=1; i < numMidiOuts; ++i)
1460 if (port == index++)
1462 eventsOut[i] = (LV2_Atom_Sequence*)dataLocation;
1463 return;
1467 if (port == index++)
1469 freewheel = (float*)dataLocation;
1470 return;
1473 for (uint32_t i=0; i < numAudioIns; ++i)
1475 if (port == index++)
1477 audioCVIns[i] = (float*)dataLocation;
1478 return;
1482 for (uint32_t i=0; i < numAudioOuts; ++i)
1484 if (port == index++)
1486 audioCVOuts[i] = (float*)dataLocation;
1487 return;
1491 for (uint32_t i=0; i < numCVIns; ++i)
1493 if (port == index++)
1495 audioCVIns[numAudioIns+i] = (float*)dataLocation;
1496 return;
1500 for (uint32_t i=0; i < numCVOuts; ++i)
1502 if (port == index++)
1504 audioCVOuts[numAudioOuts+i] = (float*)dataLocation;
1505 return;
1509 for (uint32_t i=0; i < numParams; ++i)
1511 if (port == index++)
1513 paramsPtr[i] = (float*)dataLocation;
1514 return;
1519 CARLA_DECLARE_NON_COPYABLE(Ports);
1520 } fPorts;
1522 // Rest of host<->plugin support
1523 struct URIDs {
1524 LV2_URID atomBlank;
1525 LV2_URID atomBool;
1526 LV2_URID atomObject;
1527 LV2_URID atomDouble;
1528 LV2_URID atomFloat;
1529 LV2_URID atomInt;
1530 LV2_URID atomLong;
1531 LV2_URID atomPath;
1532 LV2_URID atomSequence;
1533 LV2_URID atomString;
1534 LV2_URID atomURID;
1535 LV2_URID carlaFile;
1536 LV2_URID carlaFileAudio;
1537 LV2_URID carlaFileMIDI;
1538 LV2_URID carlaPreview;
1539 LV2_URID midiEvent;
1540 LV2_URID patchProperty;
1541 LV2_URID patchGet;
1542 LV2_URID patchSet;
1543 LV2_URID patchValue;
1544 LV2_URID timePos;
1545 LV2_URID timeBar;
1546 LV2_URID timeBarBeat;
1547 LV2_URID timeBeatsPerBar;
1548 LV2_URID timeBeatsPerMinute;
1549 LV2_URID timeBeatUnit;
1550 LV2_URID timeFrame;
1551 LV2_URID timeSpeed;
1552 LV2_URID timeTicksPerBeat;
1553 LV2_URID carlaRequestIdle;
1554 LV2_URID carlaUiEvents;
1556 URIDs()
1557 : atomBlank(0),
1558 atomBool(0),
1559 atomObject(0),
1560 atomDouble(0),
1561 atomFloat(0),
1562 atomInt(0),
1563 atomLong(0),
1564 atomPath(0),
1565 atomSequence(0),
1566 atomString(0),
1567 atomURID(0),
1568 carlaFile(0),
1569 carlaFileAudio(0),
1570 carlaFileMIDI(0),
1571 carlaPreview(0),
1572 midiEvent(0),
1573 patchProperty(0),
1574 patchGet(0),
1575 patchSet(0),
1576 patchValue(0),
1577 timePos(0),
1578 timeBar(0),
1579 timeBarBeat(0),
1580 timeBeatsPerBar(0),
1581 timeBeatsPerMinute(0),
1582 timeBeatUnit(0),
1583 timeFrame(0),
1584 timeSpeed(0),
1585 timeTicksPerBeat(0),
1586 carlaRequestIdle(0),
1587 carlaUiEvents(0) {}
1589 void map(const LV2_URID_Map* const uridMap)
1591 atomBlank = uridMap->map(uridMap->handle, LV2_ATOM__Blank);
1592 atomBool = uridMap->map(uridMap->handle, LV2_ATOM__Bool);
1593 atomObject = uridMap->map(uridMap->handle, LV2_ATOM__Object);
1594 atomDouble = uridMap->map(uridMap->handle, LV2_ATOM__Double);
1595 atomFloat = uridMap->map(uridMap->handle, LV2_ATOM__Float);
1596 atomInt = uridMap->map(uridMap->handle, LV2_ATOM__Int);
1597 atomLong = uridMap->map(uridMap->handle, LV2_ATOM__Long);
1598 atomPath = uridMap->map(uridMap->handle, LV2_ATOM__Path);
1599 atomSequence = uridMap->map(uridMap->handle, LV2_ATOM__Sequence);
1600 atomString = uridMap->map(uridMap->handle, LV2_ATOM__String);
1601 atomURID = uridMap->map(uridMap->handle, LV2_ATOM__URID);
1602 carlaFile = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file");
1603 carlaFileAudio = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file/audio");
1604 carlaFileMIDI = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/file/midi");
1605 carlaPreview = uridMap->map(uridMap->handle, "http://kxstudio.sf.net/carla/preview");
1606 midiEvent = uridMap->map(uridMap->handle, LV2_MIDI__MidiEvent);
1607 patchProperty = uridMap->map(uridMap->handle, LV2_PATCH__property);
1608 patchGet = uridMap->map(uridMap->handle, LV2_PATCH__Get);
1609 patchSet = uridMap->map(uridMap->handle, LV2_PATCH__Set);
1610 patchValue = uridMap->map(uridMap->handle, LV2_PATCH__value);
1611 timePos = uridMap->map(uridMap->handle, LV2_TIME__Position);
1612 timeBar = uridMap->map(uridMap->handle, LV2_TIME__bar);
1613 timeBarBeat = uridMap->map(uridMap->handle, LV2_TIME__barBeat);
1614 timeBeatUnit = uridMap->map(uridMap->handle, LV2_TIME__beatUnit);
1615 timeFrame = uridMap->map(uridMap->handle, LV2_TIME__frame);
1616 timeSpeed = uridMap->map(uridMap->handle, LV2_TIME__speed);
1617 timeBeatsPerBar = uridMap->map(uridMap->handle, LV2_TIME__beatsPerBar);
1618 timeBeatsPerMinute = uridMap->map(uridMap->handle, LV2_TIME__beatsPerMinute);
1619 timeTicksPerBeat = uridMap->map(uridMap->handle, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat);
1620 carlaRequestIdle = uridMap->map(uridMap->handle, "urn:carla:idle");
1621 carlaUiEvents = uridMap->map(uridMap->handle, "urn:carla:uiEvents");
1623 } fURIs;
1625 struct UI {
1626 const LV2_External_UI_Host* host;
1627 const LV2UI_Touch* touch;
1628 LV2UI_Write_Function writeFunction;
1629 LV2UI_Controller controller;
1630 bool isVisible;
1632 UI()
1633 : host(nullptr),
1634 touch(nullptr),
1635 writeFunction(nullptr),
1636 controller(nullptr),
1637 isVisible(false) {}
1638 } fUI;
1640 private:
1641 // ----------------------------------------------------------------------------------------------------------------
1643 #define handlePtr ((Lv2PluginBaseClass*)handle)
1645 static void extui_run(LV2_External_UI_Widget_Compat* handle)
1647 CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1649 handlePtr->handleUiRun();
1652 static void extui_show(LV2_External_UI_Widget_Compat* handle)
1654 CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1655 carla_debug("extui_show(%p)", handle);
1657 handlePtr->handleUiShow();
1660 static void extui_hide(LV2_External_UI_Widget_Compat* handle)
1662 CARLA_SAFE_ASSERT_RETURN(handle != nullptr,);
1663 carla_debug("extui_hide(%p)", handle);
1665 handlePtr->handleUiHide();
1668 #undef handlePtr
1670 // ----------------------------------------------------------------------------------------------------------------
1672 void clearTimeData() noexcept;
1674 // ----------------------------------------------------------------------------------------------------------------
1676 CARLA_DECLARE_NON_COPYABLE(Lv2PluginBaseClass)
1679 // --------------------------------------------------------------------------------------------------------------------
1680 // Create new RDF object (using lilv)
1682 static inline
1683 const LV2_RDF_Descriptor* lv2_rdf_new(const LV2_URI uri, const bool loadPresets)
1685 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', nullptr);
1687 Lv2WorldClass& lv2World(Lv2WorldClass::getInstance());
1689 const LilvPlugin* const cPlugin(lv2World.getPluginFromURI(uri));
1690 CARLA_SAFE_ASSERT_RETURN(cPlugin != nullptr, nullptr);
1692 Lilv::Plugin lilvPlugin(cPlugin);
1693 LV2_RDF_Descriptor* const rdfDescriptor(new LV2_RDF_Descriptor());
1695 CarlaStringList portGroupURIs(false); // does not allocate own elements
1696 LinkedList<LilvNode*> portGroupNodes;
1698 // ----------------------------------------------------------------------------------------------------------------
1699 // Set Plugin Type
1701 Lilv::Nodes typeNodes(lilvPlugin.get_value(lv2World.rdf_type));
1703 if (typeNodes.size() > 0)
1705 if (typeNodes.contains(lv2World.class_allpass))
1706 rdfDescriptor->Type[0] |= LV2_PLUGIN_ALLPASS;
1707 if (typeNodes.contains(lv2World.class_amplifier))
1708 rdfDescriptor->Type[0] |= LV2_PLUGIN_AMPLIFIER;
1709 if (typeNodes.contains(lv2World.class_analyzer))
1710 rdfDescriptor->Type[1] |= LV2_PLUGIN_ANALYSER;
1711 if (typeNodes.contains(lv2World.class_bandpass))
1712 rdfDescriptor->Type[0] |= LV2_PLUGIN_BANDPASS;
1713 if (typeNodes.contains(lv2World.class_chorus))
1714 rdfDescriptor->Type[1] |= LV2_PLUGIN_CHORUS;
1715 if (typeNodes.contains(lv2World.class_comb))
1716 rdfDescriptor->Type[1] |= LV2_PLUGIN_COMB;
1717 if (typeNodes.contains(lv2World.class_compressor))
1718 rdfDescriptor->Type[0] |= LV2_PLUGIN_COMPRESSOR;
1719 if (typeNodes.contains(lv2World.class_constant))
1720 rdfDescriptor->Type[1] |= LV2_PLUGIN_CONSTANT;
1721 if (typeNodes.contains(lv2World.class_converter))
1722 rdfDescriptor->Type[1] |= LV2_PLUGIN_CONVERTER;
1723 if (typeNodes.contains(lv2World.class_delay))
1724 rdfDescriptor->Type[0] |= LV2_PLUGIN_DELAY;
1725 if (typeNodes.contains(lv2World.class_distortion))
1726 rdfDescriptor->Type[0] |= LV2_PLUGIN_DISTORTION;
1727 if (typeNodes.contains(lv2World.class_dynamics))
1728 rdfDescriptor->Type[0] |= LV2_PLUGIN_DYNAMICS;
1729 if (typeNodes.contains(lv2World.class_eq))
1730 rdfDescriptor->Type[0] |= LV2_PLUGIN_EQ;
1731 if (typeNodes.contains(lv2World.class_envelope))
1732 rdfDescriptor->Type[0] |= LV2_PLUGIN_ENVELOPE;
1733 if (typeNodes.contains(lv2World.class_expander))
1734 rdfDescriptor->Type[0] |= LV2_PLUGIN_EXPANDER;
1735 if (typeNodes.contains(lv2World.class_filter))
1736 rdfDescriptor->Type[0] |= LV2_PLUGIN_FILTER;
1737 if (typeNodes.contains(lv2World.class_flanger))
1738 rdfDescriptor->Type[1] |= LV2_PLUGIN_FLANGER;
1739 if (typeNodes.contains(lv2World.class_function))
1740 rdfDescriptor->Type[1] |= LV2_PLUGIN_FUNCTION;
1741 if (typeNodes.contains(lv2World.class_gate))
1742 rdfDescriptor->Type[0] |= LV2_PLUGIN_GATE;
1743 if (typeNodes.contains(lv2World.class_generator))
1744 rdfDescriptor->Type[1] |= LV2_PLUGIN_GENERATOR;
1745 if (typeNodes.contains(lv2World.class_highpass))
1746 rdfDescriptor->Type[0] |= LV2_PLUGIN_HIGHPASS;
1747 if (typeNodes.contains(lv2World.class_instrument))
1748 rdfDescriptor->Type[1] |= LV2_PLUGIN_INSTRUMENT;
1749 if (typeNodes.contains(lv2World.class_limiter))
1750 rdfDescriptor->Type[0] |= LV2_PLUGIN_LIMITER;
1751 if (typeNodes.contains(lv2World.class_lowpass))
1752 rdfDescriptor->Type[0] |= LV2_PLUGIN_LOWPASS;
1753 if (typeNodes.contains(lv2World.class_mixer))
1754 rdfDescriptor->Type[1] |= LV2_PLUGIN_MIXER;
1755 if (typeNodes.contains(lv2World.class_modulator))
1756 rdfDescriptor->Type[1] |= LV2_PLUGIN_MODULATOR;
1757 if (typeNodes.contains(lv2World.class_multiEQ))
1758 rdfDescriptor->Type[0] |= LV2_PLUGIN_MULTI_EQ;
1759 if (typeNodes.contains(lv2World.class_oscillator))
1760 rdfDescriptor->Type[1] |= LV2_PLUGIN_OSCILLATOR;
1761 if (typeNodes.contains(lv2World.class_paraEQ))
1762 rdfDescriptor->Type[0] |= LV2_PLUGIN_PARA_EQ;
1763 if (typeNodes.contains(lv2World.class_phaser))
1764 rdfDescriptor->Type[1] |= LV2_PLUGIN_PHASER;
1765 if (typeNodes.contains(lv2World.class_pitch))
1766 rdfDescriptor->Type[1] |= LV2_PLUGIN_PITCH;
1767 if (typeNodes.contains(lv2World.class_reverb))
1768 rdfDescriptor->Type[0] |= LV2_PLUGIN_REVERB;
1769 if (typeNodes.contains(lv2World.class_simulator))
1770 rdfDescriptor->Type[0] |= LV2_PLUGIN_SIMULATOR;
1771 if (typeNodes.contains(lv2World.class_spatial))
1772 rdfDescriptor->Type[1] |= LV2_PLUGIN_SPATIAL;
1773 if (typeNodes.contains(lv2World.class_spectral))
1774 rdfDescriptor->Type[1] |= LV2_PLUGIN_SPECTRAL;
1775 if (typeNodes.contains(lv2World.class_utility))
1776 rdfDescriptor->Type[1] |= LV2_PLUGIN_UTILITY;
1777 if (typeNodes.contains(lv2World.class_waveshaper))
1778 rdfDescriptor->Type[0] |= LV2_PLUGIN_WAVESHAPER;
1781 lilv_nodes_free(const_cast<LilvNodes*>(typeNodes.me));
1784 // ----------------------------------------------------------------------------------------------------------------
1785 // Set Plugin Information
1787 rdfDescriptor->URI = carla_strdup(uri);
1789 if (LilvNode* const nameNode = lilv_plugin_get_name(lilvPlugin.me))
1791 if (const char* const name = lilv_node_as_string(nameNode))
1792 rdfDescriptor->Name = carla_strdup(name);
1793 lilv_node_free(nameNode);
1796 if (const char* const author = lilvPlugin.get_author_name().as_string())
1797 rdfDescriptor->Author = carla_strdup(author);
1799 if (const char* const binary = lilvPlugin.get_library_uri().as_string())
1800 rdfDescriptor->Binary = carla_strdup_free(lilv_file_uri_parse(binary, nullptr));
1802 if (const char* const bundle = lilvPlugin.get_bundle_uri().as_string())
1803 rdfDescriptor->Bundle = carla_strdup_free(lilv_file_uri_parse(bundle, nullptr));
1805 Lilv::Nodes licenseNodes(lilvPlugin.get_value(lv2World.doap_license));
1807 if (licenseNodes.size() > 0)
1809 if (const char* const license = licenseNodes.get_first().as_string())
1810 rdfDescriptor->License = carla_strdup(license);
1813 lilv_nodes_free(const_cast<LilvNodes*>(licenseNodes.me));
1816 // ----------------------------------------------------------------------------------------------------------------
1817 // Set Plugin UniqueID
1819 Lilv::Nodes replaceNodes(lilvPlugin.get_value(lv2World.dct_replaces));
1821 if (replaceNodes.size() > 0)
1823 Lilv::Node replaceNode(replaceNodes.get_first());
1825 if (replaceNode.is_uri())
1827 #if defined(CARLA_UTILS_USE_QT)
1828 const QString replaceURI(replaceNode.as_uri());
1830 if (replaceURI.startsWith("urn:"))
1832 const QString replaceId(replaceURI.split(":").last());
1834 bool ok;
1835 const ulong uniqueId(replaceId.toULong(&ok));
1837 if (ok && uniqueId != 0)
1838 rdfDescriptor->UniqueID = uniqueId;
1840 #else
1841 const water::String replaceURI(replaceNode.as_uri());
1843 if (replaceURI.startsWith("urn:"))
1845 const int uniqueId(replaceURI.getTrailingIntValue());
1847 if (uniqueId > 0)
1848 rdfDescriptor->UniqueID = static_cast<ulong>(uniqueId);
1850 #endif
1854 lilv_nodes_free(const_cast<LilvNodes*>(replaceNodes.me));
1857 // ----------------------------------------------------------------------------------------------------------------
1858 // Set Plugin Ports
1860 if (const uint numPorts = lilvPlugin.get_num_ports())
1862 rdfDescriptor->PortCount = numPorts;
1863 rdfDescriptor->Ports = new LV2_RDF_Port[numPorts];
1865 for (uint i = 0; i < numPorts; ++i)
1867 Lilv::Port lilvPort(lilvPlugin.get_port_by_index(i));
1868 CARLA_SAFE_ASSERT_CONTINUE(lilvPort.me != nullptr);
1870 LV2_RDF_Port* const rdfPort(&rdfDescriptor->Ports[i]);
1872 // --------------------------------------------------------------------------------------------------------
1873 // Set Port Information
1875 if (LilvNode* const nameNode = lilv_port_get_name(lilvPlugin.me, lilvPort.me))
1877 if (const char* const name = lilv_node_as_string(nameNode))
1878 rdfPort->Name = carla_strdup(name);
1879 lilv_node_free(nameNode);
1882 if (const char* const symbol = lilv_node_as_string(lilvPort.get_symbol()))
1883 rdfPort->Symbol = carla_strdup(symbol);
1885 if (LilvNode* const commentNode = lilvPort.get(lv2World.rdfs_comment.me))
1887 rdfPort->Comment = carla_strdup(lilv_node_as_string(commentNode));
1888 lilv_node_free(commentNode);
1891 if (LilvNode* const groupNode = lilvPort.get(lv2World.pg_group.me))
1893 rdfPort->GroupURI = carla_strdup(lilv_node_as_uri(groupNode));
1895 if (portGroupURIs.appendUnique(rdfPort->GroupURI))
1896 portGroupNodes.append(groupNode);
1897 else
1898 lilv_node_free(groupNode);
1902 // --------------------------------------------------------------------------------------------------------
1903 // Set Port Mode and Type
1905 // Input or Output
1906 /**/ if (lilvPort.is_a(lv2World.port_input))
1907 rdfPort->Types |= LV2_PORT_INPUT;
1908 else if (lilvPort.is_a(lv2World.port_output))
1909 rdfPort->Types |= LV2_PORT_OUTPUT;
1910 else
1911 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' is not input or output", uri, rdfPort->Name);
1913 // Data Type
1914 /**/ if (lilvPort.is_a(lv2World.port_control))
1916 rdfPort->Types |= LV2_PORT_CONTROL;
1918 else if (lilvPort.is_a(lv2World.port_audio))
1920 rdfPort->Types |= LV2_PORT_AUDIO;
1922 else if (lilvPort.is_a(lv2World.port_cv))
1924 rdfPort->Types |= LV2_PORT_CV;
1926 else if (lilvPort.is_a(lv2World.port_atom))
1928 rdfPort->Types |= LV2_PORT_ATOM;
1930 Lilv::Nodes bufferTypeNodes(lilvPort.get_value(lv2World.atom_bufferType));
1932 for (LilvIter* it = lilv_nodes_begin(bufferTypeNodes.me); ! lilv_nodes_is_end(bufferTypeNodes.me, it); it = lilv_nodes_next(bufferTypeNodes.me, it))
1934 const Lilv::Node node(lilv_nodes_get(bufferTypeNodes.me, it));
1935 CARLA_SAFE_ASSERT_CONTINUE(node.is_uri());
1937 if (node.equals(lv2World.atom_sequence))
1938 rdfPort->Types |= LV2_PORT_ATOM_SEQUENCE;
1939 else
1940 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses an unknown atom buffer type '%s'", uri, rdfPort->Name, node.as_uri());
1943 Lilv::Nodes supportNodes(lilvPort.get_value(lv2World.atom_supports));
1945 for (LilvIter* it = lilv_nodes_begin(supportNodes.me); ! lilv_nodes_is_end(supportNodes.me, it); it = lilv_nodes_next(supportNodes.me, it))
1947 const Lilv::Node node(lilv_nodes_get(supportNodes.me, it));
1948 CARLA_SAFE_ASSERT_CONTINUE(node.is_uri());
1950 /**/ if (node.equals(lv2World.midi_event))
1951 rdfPort->Types |= LV2_PORT_DATA_MIDI_EVENT;
1953 else if (node.equals(lv2World.patch_message))
1954 rdfPort->Types |= LV2_PORT_DATA_PATCH_MESSAGE;
1956 else if (node.equals(lv2World.time_position))
1957 rdfPort->Types |= LV2_PORT_DATA_TIME_POSITION;
1959 #if 0
1960 // something new we don't support yet?
1961 else if (std::strstr(node.as_uri(), "lv2plug.in/") != nullptr)
1962 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' is of atom type but has unsupported data '%s'", uri, rdfPort->Name, node.as_uri());
1963 #endif
1966 lilv_nodes_free(const_cast<LilvNodes*>(bufferTypeNodes.me));
1967 lilv_nodes_free(const_cast<LilvNodes*>(supportNodes.me));
1969 else if (lilvPort.is_a(lv2World.port_event))
1971 rdfPort->Types |= LV2_PORT_EVENT;
1972 bool supported = false;
1974 if (lilvPort.supports_event(lv2World.midi_event))
1976 rdfPort->Types |= LV2_PORT_DATA_MIDI_EVENT;
1977 supported = true;
1979 if (lilvPort.supports_event(lv2World.patch_message))
1981 rdfPort->Types |= LV2_PORT_DATA_PATCH_MESSAGE;
1982 supported = true;
1984 if (lilvPort.supports_event(lv2World.time_position))
1986 rdfPort->Types |= LV2_PORT_DATA_TIME_POSITION;
1987 supported = true;
1990 if (! supported)
1991 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' is of event type but has unsupported data", uri, rdfPort->Name);
1993 else if (lilvPort.is_a(lv2World.port_midi))
1995 rdfPort->Types |= LV2_PORT_MIDI_LL;
1996 rdfPort->Types |= LV2_PORT_DATA_MIDI_EVENT;
1998 else
1999 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' is of unknown data type", uri, rdfPort->Name);
2002 // --------------------------------------------------------------------------------------------------------
2003 // Set Port Properties
2005 if (lilvPort.has_property(lv2World.pprop_optional))
2006 rdfPort->Properties |= LV2_PORT_OPTIONAL;
2007 if (lilvPort.has_property(lv2World.pprop_enumeration))
2008 rdfPort->Properties |= LV2_PORT_ENUMERATION;
2009 if (lilvPort.has_property(lv2World.pprop_integer))
2010 rdfPort->Properties |= LV2_PORT_INTEGER;
2011 if (lilvPort.has_property(lv2World.pprop_isSideChain))
2012 rdfPort->Properties |= LV2_PORT_SIDECHAIN;
2013 if (lilvPort.has_property(lv2World.pprop_sampleRate))
2014 rdfPort->Properties |= LV2_PORT_SAMPLE_RATE;
2015 if (lilvPort.has_property(lv2World.pprop_toggled))
2016 rdfPort->Properties |= LV2_PORT_TOGGLED;
2018 if (lilvPort.has_property(lv2World.pprop_artifacts))
2019 rdfPort->Properties |= LV2_PORT_CAUSES_ARTIFACTS;
2020 if (lilvPort.has_property(lv2World.pprop_continuousCV))
2021 rdfPort->Properties |= LV2_PORT_CONTINUOUS_CV;
2022 if (lilvPort.has_property(lv2World.pprop_discreteCV))
2023 rdfPort->Properties |= LV2_PORT_DISCRETE_CV;
2024 if (lilvPort.has_property(lv2World.pprop_expensive))
2025 rdfPort->Properties |= LV2_PORT_EXPENSIVE;
2026 if (lilvPort.has_property(lv2World.pprop_strictBounds))
2027 rdfPort->Properties |= LV2_PORT_STRICT_BOUNDS;
2028 if (lilvPort.has_property(lv2World.pprop_logarithmic))
2029 rdfPort->Properties |= LV2_PORT_LOGARITHMIC;
2030 if (lilvPort.has_property(lv2World.pprop_notAutomatic))
2031 rdfPort->Properties |= LV2_PORT_NOT_AUTOMATIC;
2032 if (lilvPort.has_property(lv2World.pprop_notOnGUI))
2033 rdfPort->Properties |= LV2_PORT_NOT_ON_GUI;
2034 if (lilvPort.has_property(lv2World.pprop_trigger))
2035 rdfPort->Properties |= LV2_PORT_TRIGGER;
2036 if (lilvPort.has_property(lv2World.pprop_nonAutomatable))
2037 rdfPort->Properties |= LV2_PORT_NON_AUTOMATABLE;
2039 if (lilvPort.has_property(lv2World.reportsLatency))
2040 rdfPort->Designation = LV2_PORT_DESIGNATION_LATENCY;
2042 // check if sidechain (some plugins use sidechain groups instead of isSidechain)
2043 if (LilvNode* const portGroupNode = lilvPort.get(lv2World.pg_group.me))
2045 if (LilvNode* const portSideChainOfNode = lilv_world_get(lv2World.me, portGroupNode,
2046 lv2World.pg_sideChainOf.me, nullptr))
2048 rdfPort->Properties |= LV2_PORT_SIDECHAIN;
2049 lilv_node_free(portSideChainOfNode);
2051 lilv_node_free(portGroupNode);
2054 // no port properties set, check if using old/invalid ones
2055 if (rdfPort->Properties == 0x0)
2057 const Lilv::Node oldPropArtifacts(lv2World.new_uri(NS_devp "causesArtifacts"));
2058 const Lilv::Node oldPropContinuousCV(lv2World.new_uri(NS_devp "continuousCV"));
2059 const Lilv::Node oldPropDiscreteCV(lv2World.new_uri(NS_devp "discreteCV"));
2060 const Lilv::Node oldPropExpensive(lv2World.new_uri(NS_devp "expensive"));
2061 const Lilv::Node oldPropStrictBounds(lv2World.new_uri(NS_devp "hasStrictBounds"));
2062 const Lilv::Node oldPropLogarithmic(lv2World.new_uri(NS_devp "logarithmic"));
2063 const Lilv::Node oldPropNotAutomatic(lv2World.new_uri(NS_devp "notAutomatic"));
2064 const Lilv::Node oldPropNotOnGUI(lv2World.new_uri(NS_devp "notOnGUI"));
2065 const Lilv::Node oldPropTrigger(lv2World.new_uri(NS_devp "trigger"));
2067 if (lilvPort.has_property(oldPropArtifacts))
2069 rdfPort->Properties |= LV2_PORT_CAUSES_ARTIFACTS;
2070 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'causesArtifacts'", uri, rdfPort->Name);
2072 if (lilvPort.has_property(oldPropContinuousCV))
2074 rdfPort->Properties |= LV2_PORT_CONTINUOUS_CV;
2075 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'continuousCV'", uri, rdfPort->Name);
2077 if (lilvPort.has_property(oldPropDiscreteCV))
2079 rdfPort->Properties |= LV2_PORT_DISCRETE_CV;
2080 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'discreteCV'", uri, rdfPort->Name);
2082 if (lilvPort.has_property(oldPropExpensive))
2084 rdfPort->Properties |= LV2_PORT_EXPENSIVE;
2085 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'expensive'", uri, rdfPort->Name);
2087 if (lilvPort.has_property(oldPropStrictBounds))
2089 rdfPort->Properties |= LV2_PORT_STRICT_BOUNDS;
2090 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'hasStrictBounds'", uri, rdfPort->Name);
2092 if (lilvPort.has_property(oldPropLogarithmic))
2094 rdfPort->Properties |= LV2_PORT_LOGARITHMIC;
2095 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'logarithmic'", uri, rdfPort->Name);
2097 if (lilvPort.has_property(oldPropNotAutomatic))
2099 rdfPort->Properties |= LV2_PORT_NOT_AUTOMATIC;
2100 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'notAutomatic'", uri, rdfPort->Name);
2102 if (lilvPort.has_property(oldPropNotOnGUI))
2104 rdfPort->Properties |= LV2_PORT_NOT_ON_GUI;
2105 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'notOnGUI'", uri, rdfPort->Name);
2107 if (lilvPort.has_property(oldPropTrigger))
2109 rdfPort->Properties |= LV2_PORT_TRIGGER;
2110 carla_stderr("lv2_rdf_new(\"%s\") - port '%s' uses old/invalid LV2 property for 'trigger'", uri, rdfPort->Name);
2115 // --------------------------------------------------------------------------------------------------------
2116 // Set Port Designation
2118 if (LilvNode* const designationNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.designation.me))
2120 if (const char* const designation = lilv_node_as_string(designationNode))
2122 /**/ if (std::strcmp(designation, LV2_CORE__control) == 0)
2123 rdfPort->Designation = LV2_PORT_DESIGNATION_CONTROL;
2124 else if (std::strcmp(designation, LV2_CORE__enabled) == 0)
2125 rdfPort->Designation = LV2_PORT_DESIGNATION_ENABLED;
2126 else if (std::strcmp(designation, LV2_CORE__freeWheeling) == 0)
2127 rdfPort->Designation = LV2_PORT_DESIGNATION_FREEWHEELING;
2128 else if (std::strcmp(designation, LV2_CORE__latency) == 0)
2129 rdfPort->Designation = LV2_PORT_DESIGNATION_LATENCY;
2130 else if (std::strcmp(designation, LV2_PARAMETERS__sampleRate) == 0)
2131 rdfPort->Designation = LV2_PORT_DESIGNATION_SAMPLE_RATE;
2132 else if (std::strcmp(designation, LV2_TIME__bar) == 0)
2133 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BAR;
2134 else if (std::strcmp(designation, LV2_TIME__barBeat) == 0)
2135 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BAR_BEAT;
2136 else if (std::strcmp(designation, LV2_TIME__beat) == 0)
2137 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEAT;
2138 else if (std::strcmp(designation, LV2_TIME__beatUnit) == 0)
2139 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEAT_UNIT;
2140 else if (std::strcmp(designation, LV2_TIME__beatsPerBar) == 0)
2141 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEATS_PER_BAR;
2142 else if (std::strcmp(designation, LV2_TIME__beatsPerMinute) == 0)
2143 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_BEATS_PER_MINUTE;
2144 else if (std::strcmp(designation, LV2_TIME__frame) == 0)
2145 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_FRAME;
2146 else if (std::strcmp(designation, LV2_TIME__framesPerSecond) == 0)
2147 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_FRAMES_PER_SECOND;
2148 else if (std::strcmp(designation, LV2_TIME__speed) == 0)
2149 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_SPEED;
2150 else if (std::strcmp(designation, LV2_KXSTUDIO_PROPERTIES__TimePositionTicksPerBeat) == 0)
2151 rdfPort->Designation = LV2_PORT_DESIGNATION_TIME_TICKS_PER_BEAT;
2152 else if (std::strncmp(designation, LV2_PARAMETERS_PREFIX, std::strlen(LV2_PARAMETERS_PREFIX)) == 0)
2153 pass();
2154 else if (std::strncmp(designation, LV2_PORT_GROUPS_PREFIX, std::strlen(LV2_PORT_GROUPS_PREFIX)) == 0)
2155 pass();
2156 else
2157 carla_stderr("lv2_rdf_new(\"%s\") - got unknown port designation '%s'", uri, designation);
2159 lilv_node_free(designationNode);
2163 // --------------------------------------------------------------------------------------------------------
2164 // Set Port MIDI Map
2166 if (LilvNode* const bindingNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.midi_binding.me))
2168 if (lilv_node_is_string(bindingNode))
2170 if (const char* const bindingAsString = lilv_node_as_string(bindingNode))
2172 if (std::strncmp(bindingAsString, "B0", 2) == 0 && std::strlen(bindingAsString) == 6)
2174 const char binding[3] = { bindingAsString[2], bindingAsString[3], '\0' };
2175 const long number = std::strtol(binding, nullptr, 16);
2177 if (number >= 0 && number <= 0xff)
2179 rdfPort->MidiMap.Type = LV2_PORT_MIDI_MAP_CC;
2180 rdfPort->MidiMap.Number = static_cast<uint32_t>(number);
2185 else
2187 if (lilv_node_is_blank(bindingNode))
2189 Lilv::Nodes ctrlNumNodes(lv2World.find_nodes(bindingNode, lv2World.midi_ctlrNumber, nullptr));
2191 if (ctrlNumNodes.size() == 1)
2193 const int midiCC = ctrlNumNodes.get_first().as_int();
2195 if (midiCC >= 0 && midiCC <= 0xff)
2197 rdfPort->MidiMap.Type = LV2_PORT_MIDI_MAP_CC;
2198 rdfPort->MidiMap.Number = static_cast<uint32_t>(midiCC);
2202 lilv_nodes_free(const_cast<LilvNodes*>(ctrlNumNodes.me));
2206 lilv_node_free(bindingNode);
2208 else if (LilvNode* const midiMapNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.mm_defaultControl.me))
2210 if (lilv_node_is_blank(midiMapNode))
2212 Lilv::Nodes midiMapTypeNodes(lv2World.find_nodes(midiMapNode, lv2World.mm_controlType, nullptr));
2213 Lilv::Nodes midiMapNumberNodes(lv2World.find_nodes(midiMapNode, lv2World.mm_controlNumber, nullptr));
2215 if (midiMapTypeNodes.size() == 1 && midiMapNumberNodes.size() == 1)
2217 if (const char* const midiMapType = midiMapTypeNodes.get_first().as_string())
2219 /**/ if (std::strcmp(midiMapType, LV2_MIDI_Map__CC) == 0)
2220 rdfPort->MidiMap.Type = LV2_PORT_MIDI_MAP_CC;
2221 else if (std::strcmp(midiMapType, LV2_MIDI_Map__NRPN) == 0)
2222 rdfPort->MidiMap.Type = LV2_PORT_MIDI_MAP_NRPN;
2223 else
2224 carla_stderr("lv2_rdf_new(\"%s\") - got unknown port Midi-Map type '%s'", uri, midiMapType);
2226 rdfPort->MidiMap.Number = static_cast<uint32_t>(midiMapNumberNodes.get_first().as_int());
2230 lilv_nodes_free(const_cast<LilvNodes*>(midiMapTypeNodes.me));
2231 lilv_nodes_free(const_cast<LilvNodes*>(midiMapNumberNodes.me));
2234 lilv_node_free(midiMapNode);
2237 // --------------------------------------------------------------------------------------------------------
2238 // Set Port Points
2240 if (LilvNode* const defNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.value_default.me))
2242 rdfPort->Points.Hints |= LV2_PORT_POINT_DEFAULT;
2243 rdfPort->Points.Default = lilv_node_as_float(defNode);
2244 lilv_node_free(defNode);
2247 if (LilvNode* const minNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.value_minimum.me))
2249 rdfPort->Points.Hints |= LV2_PORT_POINT_MINIMUM;
2250 rdfPort->Points.Minimum = lilv_node_as_float(minNode);
2251 lilv_node_free(minNode);
2254 if (LilvNode* const maxNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.value_maximum.me))
2256 rdfPort->Points.Hints |= LV2_PORT_POINT_MAXIMUM;
2257 rdfPort->Points.Maximum = lilv_node_as_float(maxNode);
2258 lilv_node_free(maxNode);
2262 // --------------------------------------------------------------------------------------------------------
2263 // Set Port Unit
2265 if (LilvNode* const unitUnitNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.unit_unit.me))
2267 if (lilv_node_is_uri(unitUnitNode))
2269 if (const char* const unitUnit = lilv_node_as_uri(unitUnitNode))
2271 rdfPort->Unit.Hints |= LV2_PORT_UNIT_UNIT;
2273 /**/ if (std::strcmp(unitUnit, LV2_UNITS__bar) == 0)
2274 rdfPort->Unit.Unit = LV2_PORT_UNIT_BAR;
2275 else if (std::strcmp(unitUnit, LV2_UNITS__beat) == 0)
2276 rdfPort->Unit.Unit = LV2_PORT_UNIT_BEAT;
2277 else if (std::strcmp(unitUnit, LV2_UNITS__bpm) == 0)
2278 rdfPort->Unit.Unit = LV2_PORT_UNIT_BPM;
2279 else if (std::strcmp(unitUnit, LV2_UNITS__cent) == 0)
2280 rdfPort->Unit.Unit = LV2_PORT_UNIT_CENT;
2281 else if (std::strcmp(unitUnit, LV2_UNITS__cm) == 0)
2282 rdfPort->Unit.Unit = LV2_PORT_UNIT_CM;
2283 else if (std::strcmp(unitUnit, LV2_UNITS__coef) == 0)
2284 rdfPort->Unit.Unit = LV2_PORT_UNIT_COEF;
2285 else if (std::strcmp(unitUnit, LV2_UNITS__db) == 0)
2286 rdfPort->Unit.Unit = LV2_PORT_UNIT_DB;
2287 else if (std::strcmp(unitUnit, LV2_UNITS__degree) == 0)
2288 rdfPort->Unit.Unit = LV2_PORT_UNIT_DEGREE;
2289 else if (std::strcmp(unitUnit, LV2_UNITS__frame) == 0)
2290 rdfPort->Unit.Unit = LV2_PORT_UNIT_FRAME;
2291 else if (std::strcmp(unitUnit, LV2_UNITS__hz) == 0)
2292 rdfPort->Unit.Unit = LV2_PORT_UNIT_HZ;
2293 else if (std::strcmp(unitUnit, LV2_UNITS__inch) == 0)
2294 rdfPort->Unit.Unit = LV2_PORT_UNIT_INCH;
2295 else if (std::strcmp(unitUnit, LV2_UNITS__khz) == 0)
2296 rdfPort->Unit.Unit = LV2_PORT_UNIT_KHZ;
2297 else if (std::strcmp(unitUnit, LV2_UNITS__km) == 0)
2298 rdfPort->Unit.Unit = LV2_PORT_UNIT_KM;
2299 else if (std::strcmp(unitUnit, LV2_UNITS__m) == 0)
2300 rdfPort->Unit.Unit = LV2_PORT_UNIT_M;
2301 else if (std::strcmp(unitUnit, LV2_UNITS__mhz) == 0)
2302 rdfPort->Unit.Unit = LV2_PORT_UNIT_MHZ;
2303 else if (std::strcmp(unitUnit, LV2_UNITS__midiNote) == 0)
2304 rdfPort->Unit.Unit = LV2_PORT_UNIT_MIDINOTE;
2305 else if (std::strcmp(unitUnit, LV2_UNITS__mile) == 0)
2306 rdfPort->Unit.Unit = LV2_PORT_UNIT_MILE;
2307 else if (std::strcmp(unitUnit, LV2_UNITS__min) == 0)
2308 rdfPort->Unit.Unit = LV2_PORT_UNIT_MIN;
2309 else if (std::strcmp(unitUnit, LV2_UNITS__mm) == 0)
2310 rdfPort->Unit.Unit = LV2_PORT_UNIT_MM;
2311 else if (std::strcmp(unitUnit, LV2_UNITS__ms) == 0)
2312 rdfPort->Unit.Unit = LV2_PORT_UNIT_MS;
2313 else if (std::strcmp(unitUnit, LV2_UNITS__oct) == 0)
2314 rdfPort->Unit.Unit = LV2_PORT_UNIT_OCT;
2315 else if (std::strcmp(unitUnit, LV2_UNITS__pc) == 0)
2316 rdfPort->Unit.Unit = LV2_PORT_UNIT_PC;
2317 else if (std::strcmp(unitUnit, LV2_UNITS__s) == 0)
2318 rdfPort->Unit.Unit = LV2_PORT_UNIT_S;
2319 else if (std::strcmp(unitUnit, LV2_UNITS__semitone12TET) == 0)
2320 rdfPort->Unit.Unit = LV2_PORT_UNIT_SEMITONE;
2321 else if (std::strcmp(unitUnit, "http://moddevices.com/ns/mod#volts") == 0)
2322 rdfPort->Unit.Unit = LV2_PORT_UNIT_VOLTS;
2323 else
2324 carla_stderr("lv2_rdf_new(\"%s\") - got unknown unit '%s'", uri, unitUnit);
2328 if (LilvNode* const unitNameNode = lilv_world_get(lv2World.me, unitUnitNode, lv2World.unit_name.me, nullptr))
2330 if (const char* const unitName = lilv_node_as_string(unitNameNode))
2332 rdfPort->Unit.Hints |= LV2_PORT_UNIT_NAME;
2333 rdfPort->Unit.Name = carla_strdup(unitName);
2335 lilv_node_free(unitNameNode);
2338 if (LilvNode* const unitRenderNode = lilv_world_get(lv2World.me, unitUnitNode, lv2World.unit_render.me, nullptr))
2340 if (const char* const unitRender = lilv_node_as_string(unitRenderNode))
2342 rdfPort->Unit.Hints |= LV2_PORT_UNIT_RENDER;
2343 rdfPort->Unit.Render = carla_strdup(unitRender);
2345 lilv_node_free(unitRenderNode);
2348 if (LilvNode* const unitSymbolNode = lilv_world_get(lv2World.me, unitUnitNode, lv2World.unit_symbol.me, nullptr))
2350 if (const char* const unitSymbol = lilv_node_as_string(unitSymbolNode))
2352 rdfPort->Unit.Hints |= LV2_PORT_UNIT_SYMBOL;
2353 rdfPort->Unit.Symbol = carla_strdup(unitSymbol);
2355 lilv_node_free(unitSymbolNode);
2358 lilv_node_free(unitUnitNode);
2362 // --------------------------------------------------------------------------------------------------------
2363 // Set Port Minimum Size
2365 if (LilvNode* const minimumSizeNode = lilv_port_get(lilvPort.parent, lilvPort.me, lv2World.rz_minSize.me))
2367 const int minimumSize(lilv_node_as_int(minimumSizeNode));
2369 if (minimumSize > 0)
2370 rdfPort->MinimumSize = static_cast<uint32_t>(minimumSize);
2371 else
2372 carla_safe_assert_int("minimumSize > 0", __FILE__, __LINE__, minimumSize);
2374 lilv_node_free(minimumSizeNode);
2378 // --------------------------------------------------------------------------------------------------------
2379 // Set Port Scale Points
2381 Lilv::ScalePoints lilvScalePoints(lilvPort.get_scale_points());
2383 if (const uint numScalePoints = lilvScalePoints.size())
2385 rdfPort->ScalePoints = new LV2_RDF_PortScalePoint[numScalePoints];
2387 // get all scalepoints and sort them by value
2388 LilvScalePointMap sortedpoints;
2390 LILV_FOREACH(scale_points, it, lilvScalePoints)
2392 Lilv::ScalePoint lilvScalePoint(lilvScalePoints.get(it));
2394 CARLA_SAFE_ASSERT_CONTINUE(lilvScalePoint.get_label() != nullptr);
2396 if (const LilvNode* const valuenode = lilvScalePoint.get_value())
2398 const double valueid = lilv_node_as_float(valuenode);
2399 sortedpoints[valueid] = lilvScalePoint.me;
2403 // now safe to store, sorted by using std::map
2404 uint numUsed = 0;
2405 for (LilvScalePointMap::iterator it=sortedpoints.begin(), end=sortedpoints.end(); it != end; ++it)
2407 CARLA_SAFE_ASSERT_BREAK(numUsed < numScalePoints);
2408 LV2_RDF_PortScalePoint* const rdfScalePoint(&rdfPort->ScalePoints[numUsed++]);
2410 const LilvScalePoint* const scalepoint = it->second;
2412 const LilvNode* const xlabel = lilv_scale_point_get_label(scalepoint);
2413 const LilvNode* const xvalue = lilv_scale_point_get_value(scalepoint);
2415 rdfScalePoint->Label = carla_strdup(lilv_node_as_string(xlabel));
2416 rdfScalePoint->Value = lilv_node_as_float(xvalue);
2419 rdfPort->ScalePointCount = numUsed;
2422 lilv_nodes_free(const_cast<LilvNodes*>(lilvScalePoints.me));
2427 // ----------------------------------------------------------------------------------------------------------------
2428 // Set Plugin Parameters
2430 std::map<std::string, LV2_RDF_Parameter> parameters;
2431 Lilv::Nodes patchReadableNodes(lilvPlugin.get_value(lv2World.patch_readable));
2432 Lilv::Nodes patchWritableNodes(lilvPlugin.get_value(lv2World.patch_writable));
2434 if (const uint numParameters = patchWritableNodes.size())
2436 uint numUsed = 0;
2437 LILV_FOREACH(nodes, it, patchWritableNodes)
2439 CARLA_SAFE_ASSERT_BREAK(numUsed < numParameters);
2441 Lilv::Node patchWritableNode(patchWritableNodes.get(it));
2443 if (LilvNode* const typeNode = lilv_world_get(lv2World.me, patchWritableNode,
2444 lv2World.rdf_type.me, nullptr))
2446 const char* const type = lilv_node_as_uri(typeNode);
2448 if (std::strcmp(type, LV2_CORE__Parameter) != 0)
2450 lilv_node_free(typeNode);
2451 continue;
2454 lilv_node_free(typeNode);
2456 else
2458 continue;
2461 CARLA_SAFE_ASSERT_CONTINUE(patchWritableNode.is_uri());
2463 ++numUsed;
2464 LV2_RDF_Parameter rdfParam;
2465 rdfParam.URI = carla_strdup(patchWritableNode.as_uri());
2466 rdfParam.Flags = LV2_PARAMETER_FLAG_INPUT;
2468 if (patchReadableNodes.contains(patchWritableNode))
2469 rdfParam.Flags |= LV2_PARAMETER_FLAG_OUTPUT;
2471 // ----------------------------------------------------------------------------------------------------
2472 // Set Basics
2474 if (LilvNode* const rangeNode = lilv_world_get(lv2World.me, patchWritableNode,
2475 lv2World.rdfs_range.me, nullptr))
2477 const char* const rangeURI = lilv_node_as_string(rangeNode);
2479 /**/ if (std::strcmp(rangeURI, LV2_ATOM__Bool) == 0)
2480 rdfParam.Type = LV2_PARAMETER_TYPE_BOOL;
2481 else if (std::strcmp(rangeURI, LV2_ATOM__Int) == 0)
2482 rdfParam.Type = LV2_PARAMETER_TYPE_INT;
2483 else if (std::strcmp(rangeURI, LV2_ATOM__Long) == 0)
2484 rdfParam.Type = LV2_PARAMETER_TYPE_LONG;
2485 else if (std::strcmp(rangeURI, LV2_ATOM__Float) == 0)
2486 rdfParam.Type = LV2_PARAMETER_TYPE_FLOAT;
2487 else if (std::strcmp(rangeURI, LV2_ATOM__Double) == 0)
2488 rdfParam.Type = LV2_PARAMETER_TYPE_DOUBLE;
2489 else if (std::strcmp(rangeURI, LV2_ATOM__Path) == 0)
2490 rdfParam.Type = LV2_PARAMETER_TYPE_PATH;
2491 else if (std::strcmp(rangeURI, LV2_ATOM__String) == 0)
2492 rdfParam.Type = LV2_PARAMETER_TYPE_STRING;
2493 else
2494 carla_stderr("lv2_rdf_new(\"%s\") - got unknown parameter type '%s'", uri, rangeURI);
2496 lilv_node_free(rangeNode);
2499 if (LilvNode* const labelNode = lilv_world_get(lv2World.me, patchWritableNode,
2500 lv2World.rdfs_label.me, nullptr))
2502 rdfParam.Label = carla_strdup(lilv_node_as_string(labelNode));
2503 lilv_node_free(labelNode);
2506 if (LilvNode* const commentNode = lilv_world_get(lv2World.me, patchWritableNode,
2507 lv2World.rdfs_comment.me, nullptr))
2509 rdfParam.Comment = carla_strdup_safe(lilv_node_as_string(commentNode));
2510 lilv_node_free(commentNode);
2513 if (LilvNode* const groupNode = lilv_world_get(lv2World.me, patchWritableNode,
2514 lv2World.pg_group.me, nullptr))
2516 rdfParam.GroupURI = carla_strdup_safe(lilv_node_as_uri(groupNode));
2518 if (portGroupURIs.appendUnique(rdfParam.GroupURI))
2519 portGroupNodes.append(groupNode);
2520 else
2521 lilv_node_free(groupNode);
2524 // ----------------------------------------------------------------------------------------------------
2525 // Set Port MIDI Map
2527 if (LilvNode* const bindingNode = lilv_world_get(lv2World.me, patchWritableNode,
2528 lv2World.midi_binding.me, nullptr))
2530 if (const char* const bindingAsString = lilv_node_as_string(bindingNode))
2532 if (std::strncmp(bindingAsString, "B0", 2) == 0 && std::strlen(bindingAsString) == 6)
2534 const char binding[3] = { bindingAsString[2], bindingAsString[3], '\0' };
2535 const long number = std::strtol(binding, nullptr, 16);
2537 if (number >= 0 && number <= 0xff)
2539 rdfParam.MidiMap.Type = LV2_PORT_MIDI_MAP_CC;
2540 rdfParam.MidiMap.Number = static_cast<uint32_t>(number);
2545 lilv_node_free(bindingNode);
2548 // ----------------------------------------------------------------------------------------------------
2549 // Set Port Points
2551 if (LilvNode* const defNode = lilv_world_get(lv2World.me, patchWritableNode,
2552 lv2World.value_default.me, nullptr))
2554 rdfParam.Points.Hints |= LV2_PORT_POINT_DEFAULT;
2555 rdfParam.Points.Default = lilv_node_as_float(defNode);
2556 lilv_node_free(defNode);
2559 if (LilvNode* const minNode = lilv_world_get(lv2World.me, patchWritableNode,
2560 lv2World.value_minimum.me, nullptr))
2562 rdfParam.Points.Hints |= LV2_PORT_POINT_MINIMUM;
2563 rdfParam.Points.Minimum = lilv_node_as_float(minNode);
2564 lilv_node_free(minNode);
2567 if (LilvNode* const maxNode = lilv_world_get(lv2World.me, patchWritableNode,
2568 lv2World.value_maximum.me, nullptr))
2570 rdfParam.Points.Hints |= LV2_PORT_POINT_MAXIMUM;
2571 rdfParam.Points.Maximum = lilv_node_as_float(maxNode);
2572 lilv_node_free(maxNode);
2575 // ----------------------------------------------------------------------------------------------------
2576 // Set Port Unit
2578 if (LilvNode* const unitUnitNode = lilv_world_get(lv2World.me, patchWritableNode,
2579 lv2World.unit_unit.me, nullptr))
2581 if (lilv_node_is_uri(unitUnitNode))
2583 if (const char* const unitUnit = lilv_node_as_uri(unitUnitNode))
2585 rdfParam.Unit.Hints |= LV2_PORT_UNIT_UNIT;
2587 /**/ if (std::strcmp(unitUnit, LV2_UNITS__bar) == 0)
2588 rdfParam.Unit.Unit = LV2_PORT_UNIT_BAR;
2589 else if (std::strcmp(unitUnit, LV2_UNITS__beat) == 0)
2590 rdfParam.Unit.Unit = LV2_PORT_UNIT_BEAT;
2591 else if (std::strcmp(unitUnit, LV2_UNITS__bpm) == 0)
2592 rdfParam.Unit.Unit = LV2_PORT_UNIT_BPM;
2593 else if (std::strcmp(unitUnit, LV2_UNITS__cent) == 0)
2594 rdfParam.Unit.Unit = LV2_PORT_UNIT_CENT;
2595 else if (std::strcmp(unitUnit, LV2_UNITS__cm) == 0)
2596 rdfParam.Unit.Unit = LV2_PORT_UNIT_CM;
2597 else if (std::strcmp(unitUnit, LV2_UNITS__coef) == 0)
2598 rdfParam.Unit.Unit = LV2_PORT_UNIT_COEF;
2599 else if (std::strcmp(unitUnit, LV2_UNITS__db) == 0)
2600 rdfParam.Unit.Unit = LV2_PORT_UNIT_DB;
2601 else if (std::strcmp(unitUnit, LV2_UNITS__degree) == 0)
2602 rdfParam.Unit.Unit = LV2_PORT_UNIT_DEGREE;
2603 else if (std::strcmp(unitUnit, LV2_UNITS__frame) == 0)
2604 rdfParam.Unit.Unit = LV2_PORT_UNIT_FRAME;
2605 else if (std::strcmp(unitUnit, LV2_UNITS__hz) == 0)
2606 rdfParam.Unit.Unit = LV2_PORT_UNIT_HZ;
2607 else if (std::strcmp(unitUnit, LV2_UNITS__inch) == 0)
2608 rdfParam.Unit.Unit = LV2_PORT_UNIT_INCH;
2609 else if (std::strcmp(unitUnit, LV2_UNITS__khz) == 0)
2610 rdfParam.Unit.Unit = LV2_PORT_UNIT_KHZ;
2611 else if (std::strcmp(unitUnit, LV2_UNITS__km) == 0)
2612 rdfParam.Unit.Unit = LV2_PORT_UNIT_KM;
2613 else if (std::strcmp(unitUnit, LV2_UNITS__m) == 0)
2614 rdfParam.Unit.Unit = LV2_PORT_UNIT_M;
2615 else if (std::strcmp(unitUnit, LV2_UNITS__mhz) == 0)
2616 rdfParam.Unit.Unit = LV2_PORT_UNIT_MHZ;
2617 else if (std::strcmp(unitUnit, LV2_UNITS__midiNote) == 0)
2618 rdfParam.Unit.Unit = LV2_PORT_UNIT_MIDINOTE;
2619 else if (std::strcmp(unitUnit, LV2_UNITS__mile) == 0)
2620 rdfParam.Unit.Unit = LV2_PORT_UNIT_MILE;
2621 else if (std::strcmp(unitUnit, LV2_UNITS__min) == 0)
2622 rdfParam.Unit.Unit = LV2_PORT_UNIT_MIN;
2623 else if (std::strcmp(unitUnit, LV2_UNITS__mm) == 0)
2624 rdfParam.Unit.Unit = LV2_PORT_UNIT_MM;
2625 else if (std::strcmp(unitUnit, LV2_UNITS__ms) == 0)
2626 rdfParam.Unit.Unit = LV2_PORT_UNIT_MS;
2627 else if (std::strcmp(unitUnit, LV2_UNITS__oct) == 0)
2628 rdfParam.Unit.Unit = LV2_PORT_UNIT_OCT;
2629 else if (std::strcmp(unitUnit, LV2_UNITS__pc) == 0)
2630 rdfParam.Unit.Unit = LV2_PORT_UNIT_PC;
2631 else if (std::strcmp(unitUnit, LV2_UNITS__s) == 0)
2632 rdfParam.Unit.Unit = LV2_PORT_UNIT_S;
2633 else if (std::strcmp(unitUnit, LV2_UNITS__semitone12TET) == 0)
2634 rdfParam.Unit.Unit = LV2_PORT_UNIT_SEMITONE;
2635 else if (std::strcmp(unitUnit, "http://moddevices.com/ns/mod#volts") == 0)
2636 rdfParam.Unit.Unit = LV2_PORT_UNIT_VOLTS;
2637 else
2638 carla_stderr("lv2_rdf_new(\"%s\") - got unknown unit '%s'", uri, unitUnit);
2642 if (LilvNode* const unitNameNode = lilv_world_get(lv2World.me, unitUnitNode,
2643 lv2World.unit_name.me, nullptr))
2645 if (const char* const unitName = lilv_node_as_string(unitNameNode))
2647 rdfParam.Unit.Hints |= LV2_PORT_UNIT_NAME;
2648 rdfParam.Unit.Name = carla_strdup(unitName);
2650 lilv_node_free(unitNameNode);
2653 if (LilvNode* const unitRenderNode = lilv_world_get(lv2World.me, unitUnitNode,
2654 lv2World.unit_render.me, nullptr))
2656 if (const char* const unitRender = lilv_node_as_string(unitRenderNode))
2658 rdfParam.Unit.Hints |= LV2_PORT_UNIT_RENDER;
2659 rdfParam.Unit.Render = carla_strdup(unitRender);
2661 lilv_node_free(unitRenderNode);
2664 if (LilvNode* const unitSymbolNode = lilv_world_get(lv2World.me, unitUnitNode,
2665 lv2World.unit_symbol.me, nullptr))
2667 if (const char* const unitSymbol = lilv_node_as_string(unitSymbolNode))
2669 rdfParam.Unit.Hints |= LV2_PORT_UNIT_SYMBOL;
2670 rdfParam.Unit.Symbol = carla_strdup(unitSymbol);
2672 lilv_node_free(unitSymbolNode);
2675 lilv_node_free(unitUnitNode);
2678 parameters[rdfParam.URI].copyAndReplace(rdfParam);
2681 CARLA_SAFE_ASSERT_UINT2(parameters.size() == numUsed, parameters.size(), numUsed);
2682 rdfDescriptor->Parameters = new LV2_RDF_Parameter[numUsed];
2683 rdfDescriptor->ParameterCount = numUsed;
2685 numUsed = 0;
2686 for (std::map<std::string, LV2_RDF_Parameter>::iterator it = parameters.begin(), end = parameters.end();
2687 it != end; ++it)
2689 rdfDescriptor->Parameters[numUsed++].copyAndReplace(it->second);
2693 lilv_nodes_free(const_cast<LilvNodes*>(patchReadableNodes.me));
2694 lilv_nodes_free(const_cast<LilvNodes*>(patchWritableNodes.me));
2697 // ----------------------------------------------------------------------------------------------------------------
2698 // Set Plugin Port Groups
2700 if (const size_t portGroupCount = portGroupURIs.count())
2702 rdfDescriptor->PortGroups = new LV2_RDF_PortGroup[portGroupCount];
2704 uint32_t count = 0;
2705 CarlaStringList::Itenerator itu = portGroupURIs.begin2();
2706 LinkedList<LilvNode*>::Itenerator itn = portGroupNodes.begin2();
2707 for (; itu.valid() && itn.valid(); itu.next(), itn.next())
2709 const char* const portGroupURI = itu.getValue(nullptr);
2710 CARLA_SAFE_ASSERT_CONTINUE(portGroupURI != nullptr);
2712 LilvNode* const portGroupNode = itn.getValue(nullptr);
2713 CARLA_SAFE_ASSERT_CONTINUE(portGroupNode != nullptr);
2715 LV2_RDF_PortGroup& portGroup(rdfDescriptor->PortGroups[count]);
2716 portGroup.URI = portGroupURI;
2718 if (LilvNode* const portGroupNameNode = lilv_world_get(lv2World.me, portGroupNode,
2719 lv2World.lv2_name.me, nullptr))
2721 portGroup.Name = carla_strdup_safe(lilv_node_as_string(portGroupNameNode));
2722 lilv_node_free(portGroupNameNode);
2724 // some plugins use rdfs:label, spec was not clear which one to use
2725 else if (LilvNode* const portGroupLabelNode = lilv_world_get(lv2World.me, portGroupNode,
2726 lv2World.rdfs_label.me, nullptr))
2728 portGroup.Name = carla_strdup_safe(lilv_node_as_string(portGroupLabelNode));
2729 lilv_node_free(portGroupLabelNode);
2732 if (LilvNode* const portGroupSymbolNode = lilv_world_get(lv2World.me, portGroupNode,
2733 lv2World.lv2_symbol.me, nullptr))
2735 portGroup.Symbol = carla_strdup_safe(lilv_node_as_string(portGroupSymbolNode));
2736 lilv_node_free(portGroupSymbolNode);
2739 ++count;
2740 lilv_node_free(portGroupNode);
2743 rdfDescriptor->PortGroupCount = count;
2744 portGroupNodes.clear();
2747 // ----------------------------------------------------------------------------------------------------------------
2748 // Set Plugin Presets
2750 if (loadPresets)
2752 Lilv::Nodes presetNodes(lilvPlugin.get_related(lv2World.preset_preset));
2754 if (presetNodes.size() > 0)
2756 // create a list of preset URIs (for sorting and unique-ness)
2757 #if defined(CARLA_UTILS_USE_QT)
2758 QStringList presetListURIs;
2760 LILV_FOREACH(nodes, it, presetNodes)
2762 Lilv::Node presetNode(presetNodes.get(it));
2764 QString presetURI(presetNode.as_uri());
2766 if (! (presetURI.trimmed().isEmpty() || presetListURIs.contains(presetURI)))
2767 presetListURIs.append(presetURI);
2770 presetListURIs.sort();
2772 rdfDescriptor->PresetCount = static_cast<uint32_t>(presetListURIs.count());
2773 #else
2774 water::StringArray presetListURIs;
2776 LILV_FOREACH(nodes, it, presetNodes)
2778 Lilv::Node presetNode(presetNodes.get(it));
2780 water::String presetURI(presetNode.as_uri());
2782 if (presetURI.trim().isNotEmpty())
2783 presetListURIs.addIfNotAlreadyThere(presetURI);
2786 presetListURIs.sortNatural();
2788 rdfDescriptor->PresetCount = static_cast<uint32_t>(presetListURIs.size());
2789 #endif
2791 // create presets with unique URIs
2792 rdfDescriptor->Presets = new LV2_RDF_Preset[rdfDescriptor->PresetCount];
2794 // set preset data
2795 LILV_FOREACH(nodes, it, presetNodes)
2797 Lilv::Node presetNode(presetNodes.get(it));
2799 const char* const presetURI(presetNode.as_uri());
2800 CARLA_SAFE_ASSERT_CONTINUE(presetURI != nullptr && presetURI[0] != '\0');
2802 // try to find label without loading the preset resource first
2803 Lilv::Nodes presetLabelNodes(lv2World.find_nodes(presetNode, lv2World.rdfs_label, nullptr));
2805 // failed, try loading resource
2806 if (presetLabelNodes.size() == 0)
2808 // if loading resource fails, skip this preset
2809 if (lv2World.load_resource(presetNode) == -1)
2810 continue;
2812 // ok, let's try again
2813 presetLabelNodes = lv2World.find_nodes(presetNode, lv2World.rdfs_label, nullptr);
2816 if (presetLabelNodes.size() > 0)
2818 #if defined(CARLA_UTILS_USE_QT)
2819 const int index = presetListURIs.indexOf(QString(presetURI));
2820 #else
2821 const int index = presetListURIs.indexOf(water::String(presetURI));
2822 #endif
2823 CARLA_SAFE_ASSERT_CONTINUE(index >= 0 && index < static_cast<int>(rdfDescriptor->PresetCount));
2825 LV2_RDF_Preset* const rdfPreset(&rdfDescriptor->Presets[index]);
2827 // ---------------------------------------------------
2828 // Set Preset Information
2830 rdfPreset->URI = carla_strdup(presetURI);
2832 if (const char* const label = presetLabelNodes.get_first().as_string())
2833 rdfPreset->Label = carla_strdup(label);
2835 lilv_nodes_free(const_cast<LilvNodes*>(presetLabelNodes.me));
2840 lilv_nodes_free(const_cast<LilvNodes*>(presetNodes.me));
2843 // ----------------------------------------------------------------------------------------------------------------
2844 // Set Plugin Features
2846 Lilv::Nodes lilvFeatureNodes(lilvPlugin.get_supported_features());
2848 if (const uint numFeatures = lilvFeatureNodes.size())
2850 Lilv::Nodes lilvFeatureNodesR(lilvPlugin.get_required_features());
2852 rdfDescriptor->Features = new LV2_RDF_Feature[numFeatures];
2854 uint numUsed = 0;
2855 LILV_FOREACH(nodes, it, lilvFeatureNodes)
2857 CARLA_SAFE_ASSERT_BREAK(numUsed < numFeatures);
2859 Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it));
2860 LV2_RDF_Feature* const rdfFeature(&rdfDescriptor->Features[numUsed++]);
2862 rdfFeature->Required = lilvFeatureNodesR.contains(lilvFeatureNode);
2864 if (const char* const featureURI = lilvFeatureNode.as_uri())
2865 rdfFeature->URI = carla_strdup(featureURI);
2866 else
2867 rdfFeature->URI = nullptr;
2870 rdfDescriptor->FeatureCount = numUsed;
2871 lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodesR.me));
2874 lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodes.me));
2877 // ----------------------------------------------------------------------------------------------------------------
2878 // Set Plugin Extensions
2880 Lilv::Nodes lilvExtensionDataNodes(lilvPlugin.get_extension_data());
2882 if (const uint numExtensions = lilvExtensionDataNodes.size())
2884 rdfDescriptor->Extensions = new LV2_URI[numExtensions];
2886 uint numUsed = 0;
2887 LILV_FOREACH(nodes, it, lilvExtensionDataNodes)
2889 CARLA_SAFE_ASSERT_BREAK(numUsed < numExtensions);
2891 Lilv::Node lilvExtensionDataNode(lilvExtensionDataNodes.get(it));
2892 LV2_URI* const rdfExtension(&rdfDescriptor->Extensions[numUsed++]);
2894 if (lilvExtensionDataNode.is_uri())
2896 if (const char* const extURI = lilvExtensionDataNode.as_uri())
2898 *rdfExtension = carla_strdup(extURI);
2899 continue;
2902 *rdfExtension = nullptr;
2905 for (uint32_t x=numUsed; x < rdfDescriptor->ExtensionCount; ++x)
2906 rdfDescriptor->Extensions[x] = nullptr;
2908 rdfDescriptor->ExtensionCount = numUsed;
2911 lilv_nodes_free(const_cast<LilvNodes*>(lilvExtensionDataNodes.me));
2914 // ----------------------------------------------------------------------------------------------------------------
2915 // Set Plugin UIs
2917 #ifdef CARLA_OS_LINUX
2918 const bool hasMODGui = lilvPlugin.get_modgui_resources_directory().as_uri() != nullptr;
2919 #else
2920 const bool hasMODGui = false;
2921 #endif
2923 Lilv::UIs lilvUIs(lilvPlugin.get_uis());
2925 const uint numUIs = lilvUIs.size() + (hasMODGui ? 1 : 0);
2927 if (numUIs > 0)
2929 rdfDescriptor->UIs = new LV2_RDF_UI[numUIs];
2931 uint numUsed = 0;
2932 LILV_FOREACH(uis, it, lilvUIs)
2934 CARLA_SAFE_ASSERT_BREAK(numUsed < numUIs);
2936 Lilv::UI lilvUI(lilvUIs.get(it));
2937 LV2_RDF_UI* const rdfUI(&rdfDescriptor->UIs[numUsed++]);
2939 lv2World.load_resource(lilvUI.get_uri());
2941 // ----------------------------------------------------------------------------------------------------
2942 // Set UI Type
2944 /**/ if (lilvUI.is_a(lv2World.ui_gtk2))
2945 rdfUI->Type = LV2_UI_GTK2;
2946 else if (lilvUI.is_a(lv2World.ui_gtk3))
2947 rdfUI->Type = LV2_UI_GTK3;
2948 else if (lilvUI.is_a(lv2World.ui_qt4))
2949 rdfUI->Type = LV2_UI_QT4;
2950 else if (lilvUI.is_a(lv2World.ui_qt5))
2951 rdfUI->Type = LV2_UI_QT5;
2952 else if (lilvUI.is_a(lv2World.ui_cocoa))
2953 rdfUI->Type = LV2_UI_COCOA;
2954 else if (lilvUI.is_a(lv2World.ui_windows))
2955 rdfUI->Type = LV2_UI_WINDOWS;
2956 else if (lilvUI.is_a(lv2World.ui_x11))
2957 rdfUI->Type = LV2_UI_X11;
2958 else if (lilvUI.is_a(lv2World.ui_external))
2959 rdfUI->Type = LV2_UI_EXTERNAL;
2960 else if (lilvUI.is_a(lv2World.ui_externalOld))
2961 rdfUI->Type = LV2_UI_OLD_EXTERNAL;
2962 else if (lilvUI.is_a(lv2World.ui))
2963 rdfUI->Type = LV2_UI_NONE;
2964 else
2965 carla_stderr("lv2_rdf_new(\"%s\") - UI '%s' is of unknown type", uri, lilvUI.get_uri().as_uri());
2967 // ----------------------------------------------------------------------------------------------------
2968 // Set UI Information
2970 if (const char* const uiURI = lilvUI.get_uri().as_uri())
2971 rdfUI->URI = carla_strdup(uiURI);
2973 if (const char* const uiBinary = lilvUI.get_binary_uri().as_string())
2974 rdfUI->Binary = carla_strdup_free(lilv_file_uri_parse(uiBinary, nullptr));
2976 if (const char* const uiBundle = lilvUI.get_bundle_uri().as_string())
2977 rdfUI->Bundle = carla_strdup_free(lilv_file_uri_parse(uiBundle, nullptr));
2980 // ----------------------------------------------------------------------------------------------------
2981 // Set UI Features
2983 Lilv::Nodes lilvFeatureNodes(lilvUI.get_supported_features());
2985 if (const uint numFeatures = lilvFeatureNodes.size())
2987 Lilv::Nodes lilvFeatureNodesR(lilvUI.get_required_features());
2989 rdfUI->Features = new LV2_RDF_Feature[numFeatures];
2991 uint numUsed2 = 0;
2992 LILV_FOREACH(nodes, it2, lilvFeatureNodes)
2994 CARLA_SAFE_ASSERT_UINT2_BREAK(numUsed2 < numFeatures, numUsed2, numFeatures);
2996 Lilv::Node lilvFeatureNode(lilvFeatureNodes.get(it2));
2997 LV2_RDF_Feature* const rdfFeature(&rdfUI->Features[numUsed2++]);
2999 rdfFeature->Required = lilvFeatureNodesR.contains(lilvFeatureNode);
3001 if (const char* const featureURI = lilvFeatureNode.as_uri())
3002 rdfFeature->URI = carla_strdup(featureURI);
3003 else
3004 rdfFeature->URI = nullptr;
3007 rdfUI->FeatureCount = numUsed2;
3008 lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodesR.me));
3011 lilv_nodes_free(const_cast<LilvNodes*>(lilvFeatureNodes.me));
3014 // ----------------------------------------------------------------------------------------------------
3015 // Set UI Extensions
3017 Lilv::Nodes lilvExtensionDataNodes(lilvUI.get_extension_data());
3019 if (const uint numExtensions = lilvExtensionDataNodes.size())
3021 rdfUI->Extensions = new LV2_URI[numExtensions];
3023 uint numUsed2 = 0;
3024 LILV_FOREACH(nodes, it2, lilvExtensionDataNodes)
3026 CARLA_SAFE_ASSERT_UINT2_BREAK(numUsed2 < numExtensions, numUsed2, numExtensions);
3028 Lilv::Node lilvExtensionDataNode(lilvExtensionDataNodes.get(it2));
3029 LV2_URI* const rdfExtension(&rdfUI->Extensions[numUsed2++]);
3031 if (lilvExtensionDataNode.is_uri())
3033 if (const char* const extURI = lilvExtensionDataNode.as_uri())
3035 *rdfExtension = carla_strdup(extURI);
3036 continue;
3039 *rdfExtension = nullptr;
3042 for (uint x2=numUsed2; x2 < rdfUI->ExtensionCount; ++x2)
3043 rdfUI->Extensions[x2] = nullptr;
3045 rdfUI->ExtensionCount = numUsed2;
3048 lilv_nodes_free(const_cast<LilvNodes*>(lilvExtensionDataNodes.me));
3051 // ----------------------------------------------------------------------------------------------------
3052 // Set UI Port Notifications
3054 Lilv::Nodes portNotifNodes(lv2World.find_nodes(lilvUI.get_uri(), lv2World.ui_portNotif.me, nullptr));
3056 if (const uint portNotifCount = portNotifNodes.size())
3058 rdfUI->PortNotificationCount = portNotifCount;
3059 rdfUI->PortNotifications = new LV2_RDF_UI_PortNotification[portNotifCount];
3061 uint numUsed2 = 0;
3062 LILV_FOREACH(nodes, it2, portNotifNodes)
3064 CARLA_SAFE_ASSERT_UINT2_BREAK(numUsed2 < portNotifCount, numUsed2, portNotifCount);
3066 Lilv::Node portNotifNode(portNotifNodes.get(it2));
3067 LV2_RDF_UI_PortNotification* const rdfPortNotif(&rdfUI->PortNotifications[numUsed2++]);
3069 LilvNode* const protocolNode = lilv_world_get(lv2World.me, portNotifNode,
3070 lv2World.ui_protocol.me, nullptr);
3072 if (protocolNode != nullptr)
3074 CARLA_SAFE_ASSERT_CONTINUE(lilv_node_is_uri(protocolNode));
3076 const char* const protocol = lilv_node_as_uri(protocolNode);
3077 CARLA_SAFE_ASSERT_CONTINUE(protocol != nullptr && protocol[0] != '\0');
3079 /**/ if (std::strcmp(protocol, LV2_UI__floatProtocol) == 0)
3080 rdfPortNotif->Protocol = LV2_UI_PORT_PROTOCOL_FLOAT;
3081 else if (std::strcmp(protocol, LV2_UI__peakProtocol) == 0)
3082 rdfPortNotif->Protocol = LV2_UI_PORT_PROTOCOL_PEAK;
3084 else
3086 rdfPortNotif->Protocol = LV2_UI_PORT_PROTOCOL_FLOAT;
3089 /**/ if (LilvNode* const symbolNode = lilv_world_get(lv2World.me, portNotifNode,
3090 lv2World.symbol.me, nullptr))
3092 CARLA_SAFE_ASSERT_CONTINUE(lilv_node_is_string(symbolNode));
3094 const char* const symbol = lilv_node_as_string(symbolNode);
3095 CARLA_SAFE_ASSERT_CONTINUE(symbol != nullptr && symbol[0] != '\0');
3097 rdfPortNotif->Symbol = carla_strdup(symbol);
3099 lilv_node_free(symbolNode);
3101 else if (LilvNode* const indexNode = lilv_world_get(lv2World.me, portNotifNode,
3102 lv2World.ui_portIndex.me, nullptr))
3104 CARLA_SAFE_ASSERT_CONTINUE(lilv_node_is_int(indexNode));
3106 const int index = lilv_node_as_int(indexNode);
3107 CARLA_SAFE_ASSERT_CONTINUE(index >= 0);
3109 rdfPortNotif->Index = static_cast<uint32_t>(index);
3111 lilv_node_free(indexNode);
3114 lilv_node_free(protocolNode);
3118 lilv_nodes_free(const_cast<LilvNodes*>(portNotifNodes.me));
3122 for (; hasMODGui;)
3124 CARLA_SAFE_ASSERT_BREAK(numUsed == numUIs-1);
3126 LV2_RDF_UI* const rdfUI(&rdfDescriptor->UIs[numUsed++]);
3128 // -------------------------------------------------------
3129 // Set UI Type
3131 rdfUI->Type = LV2_UI_MOD;
3133 // -------------------------------------------------------
3134 // Set UI Information
3136 if (const char* const resDir = lilvPlugin.get_modgui_resources_directory().as_uri())
3137 rdfUI->URI = carla_strdup_free(lilv_file_uri_parse(resDir, nullptr));
3139 if (rdfDescriptor->Bundle != nullptr)
3140 rdfUI->Bundle = carla_strdup(rdfDescriptor->Bundle);
3142 break;
3145 rdfDescriptor->UICount = numUsed;
3148 lilv_nodes_free(const_cast<LilvNodes*>(lilvUIs.me));
3151 return rdfDescriptor;
3154 // --------------------------------------------------------------------------------------------------------------------
3155 // Check if we support a plugin port
3157 static inline
3158 bool is_lv2_port_supported(const LV2_Property types) noexcept
3160 if (LV2_IS_PORT_CONTROL(types))
3161 return true;
3162 if (LV2_IS_PORT_AUDIO(types))
3163 return true;
3164 if (LV2_IS_PORT_CV(types))
3165 return true;
3166 if (LV2_IS_PORT_ATOM_SEQUENCE(types))
3167 return true;
3168 if (LV2_IS_PORT_EVENT(types))
3169 return true;
3170 if (LV2_IS_PORT_MIDI_LL(types))
3171 return true;
3172 return false;
3175 // --------------------------------------------------------------------------------------------------------------------
3176 // Check if we support a plugin feature
3178 static inline
3179 bool is_lv2_feature_supported(const LV2_URI uri) noexcept
3181 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', false);
3183 if (std::strcmp(uri, LV2_BUF_SIZE__boundedBlockLength) == 0)
3184 return true;
3185 if (std::strcmp(uri, LV2_BUF_SIZE__fixedBlockLength) == 0)
3186 return true;
3187 if (std::strcmp(uri, LV2_BUF_SIZE__powerOf2BlockLength) == 0)
3188 return true;
3189 if (std::strcmp(uri, LV2_CONTROL_INPUT_PORT_CHANGE_REQUEST_URI) == 0)
3190 return true;
3191 if (std::strcmp(uri, LV2_CORE__hardRTCapable) == 0)
3192 return true;
3193 if (std::strcmp(uri, LV2_CORE__inPlaceBroken) == 0)
3194 return true;
3195 if (std::strcmp(uri, LV2_CORE__isLive) == 0)
3196 return true;
3197 if (std::strcmp(uri, LV2_EVENT_URI) == 0)
3198 return true;
3199 if (std::strcmp(uri, LV2_INLINEDISPLAY__queue_draw) == 0)
3200 return true;
3201 if (std::strcmp(uri, LV2_LOG__log) == 0)
3202 return true;
3203 if (std::strcmp(uri, LV2_OPTIONS__options) == 0)
3204 return true;
3205 if (std::strcmp(uri, LV2_PROGRAMS__Host) == 0)
3206 return true;
3207 if (std::strcmp(uri, LV2_RESIZE_PORT__resize) == 0)
3208 return true;
3209 if (std::strcmp(uri, LV2_RTSAFE_MEMORY_POOL__Pool) == 0)
3210 return true;
3211 if (std::strcmp(uri, LV2_RTSAFE_MEMORY_POOL_DEPRECATED_URI) == 0)
3212 return true;
3213 if (std::strcmp(uri, LV2_STATE__freePath) == 0)
3214 return true;
3215 if (std::strcmp(uri, LV2_STATE__loadDefaultState) == 0)
3216 return true;
3217 if (std::strcmp(uri, LV2_STATE__makePath) == 0)
3218 return true;
3219 if (std::strcmp(uri, LV2_STATE__mapPath) == 0)
3220 return true;
3221 if (std::strcmp(uri, LV2_STATE__threadSafeRestore) == 0)
3222 return true;
3223 if (std::strcmp(uri, LV2_PORT_PROPS__supportsStrictBounds) == 0)
3224 return true;
3225 if (std::strcmp(uri, LV2_URI_MAP_URI) == 0)
3226 return true;
3227 if (std::strcmp(uri, LV2_URID__map) == 0)
3228 return true;
3229 if (std::strcmp(uri, LV2_URID__unmap) == 0)
3230 return true;
3231 if (std::strcmp(uri, LV2_WORKER__schedule) == 0)
3232 return true;
3233 return false;
3236 // --------------------------------------------------------------------------------------------------------------------
3237 // Check if we support a plugin or UI feature
3239 static inline
3240 bool is_lv2_ui_feature_supported(const LV2_URI uri) noexcept
3242 CARLA_SAFE_ASSERT_RETURN(uri != nullptr && uri[0] != '\0', false);
3244 if (is_lv2_feature_supported(uri))
3245 return true;
3246 #ifndef BUILD_BRIDGE_UI
3247 if (std::strcmp(uri, LV2_DATA_ACCESS_URI) == 0)
3248 return true;
3249 if (std::strcmp(uri, LV2_INSTANCE_ACCESS_URI) == 0)
3250 return true;
3251 #endif
3252 if (std::strcmp(uri, LV2_UI__fixedSize) == 0)
3253 return true;
3254 if (std::strcmp(uri, LV2_UI__idleInterface) == 0)
3255 return true;
3256 if (std::strcmp(uri, LV2_UI__makeResident) == 0)
3257 return true;
3258 if (std::strcmp(uri, LV2_UI__makeSONameResident) == 0)
3259 return true;
3260 if (std::strcmp(uri, LV2_UI__noUserResize) == 0)
3261 return true;
3262 if (std::strcmp(uri, LV2_UI__parent) == 0)
3263 return true;
3264 if (std::strcmp(uri, LV2_UI__portMap) == 0)
3265 return true;
3266 if (std::strcmp(uri, LV2_UI__portSubscribe) == 0)
3267 return true;
3268 if (std::strcmp(uri, LV2_UI__requestValue) == 0)
3269 return true;
3270 if (std::strcmp(uri, LV2_UI__resize) == 0)
3271 return true;
3272 if (std::strcmp(uri, LV2_UI__touch) == 0)
3273 return true;
3274 if (std::strcmp(uri, LV2_EXTERNAL_UI__Widget) == 0)
3275 return true;
3276 if (std::strcmp(uri, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0)
3277 return true;
3278 return false;
3281 // --------------------------------------------------------------------------------------------------------------------
3283 #endif // CARLA_LV2_UTILS_HPP_INCLUDED