From 429a2b7ad93f6ab8dcd06a98c60a67b425f81d55 Mon Sep 17 00:00:00 2001 From: falkTX Date: Tue, 1 May 2012 02:24:27 +0100 Subject: [PATCH] More work on Carla-lv2 support --- src/carla-includes/lilv/lilv.h | 19 + src/carla-includes/lilv/lilvmm.hpp | 15 +- src/carla-includes/lv2/programs.h | 141 +++ src/carla-lilv/lilv-0.14.0/lilv/lilv.h | 19 + src/carla-lilv/lilv-0.14.0/lilv/lilvmm.hpp | 279 ------ src/carla-lilv/lilv-0.14.0/src/ui.c | 54 + src/carla/carla_backend.cpp | 6 +- src/carla/lv2.cpp | 1046 ++++---------------- src/carla/lv2_rdf.h | 969 +++++++++++++++++- 9 files changed, 1401 insertions(+), 1147 deletions(-) create mode 100644 src/carla-includes/lv2/programs.h delete mode 100644 src/carla-lilv/lilv-0.14.0/lilv/lilvmm.hpp diff --git a/src/carla-includes/lilv/lilv.h b/src/carla-includes/lilv/lilv.h index 2423c6e..96746a7 100644 --- a/src/carla-includes/lilv/lilv.h +++ b/src/carla-includes/lilv/lilv.h @@ -1692,6 +1692,25 @@ LILV_API const LilvNode* lilv_ui_get_binary_uri(const LilvUI* ui); +/** + Custom calls +*/ +LILV_API +LilvNodes* +lilv_ui_get_supported_features(const LilvUI* ui); + +LILV_API +LilvNodes* +lilv_ui_get_required_features(const LilvUI* ui); + +LILV_API +LilvNodes* +lilv_ui_get_optional_features(const LilvUI* ui); + +LILV_API +LilvNodes* +lilv_ui_get_extension_data(const LilvUI* ui); + /** @} @} diff --git a/src/carla-includes/lilv/lilvmm.hpp b/src/carla-includes/lilv/lilvmm.hpp index 3d92d88..1a929f1 100644 --- a/src/carla-includes/lilv/lilvmm.hpp +++ b/src/carla-includes/lilv/lilvmm.hpp @@ -165,10 +165,14 @@ struct UI { inline UI(const LilvUI* c_obj) : me(c_obj) {} LILV_WRAP_CONVERSION(const LilvUI); - LILV_WRAP0(Node, ui, get_uri); - LILV_WRAP1(bool, ui, is_a, LilvNode*, ui_class); - LILV_WRAP0(Node, ui, get_bundle_uri); - LILV_WRAP0(Node, ui, get_binary_uri); + LILV_WRAP0(Node, ui, get_uri); + LILV_WRAP1(bool, ui, is_a, LilvNode*, ui_class); + LILV_WRAP0(Node, ui, get_bundle_uri); + LILV_WRAP0(Node, ui, get_binary_uri); + LILV_WRAP0(Nodes, ui, get_supported_features); + LILV_WRAP0(Nodes, ui, get_required_features); + LILV_WRAP0(Nodes, ui, get_optional_features); + LILV_WRAP0(Nodes, ui, get_extension_data); const LilvUI* me; }; @@ -200,6 +204,8 @@ struct Plugin { LILV_WRAP0(Node, plugin, get_author_email); LILV_WRAP0(Node, plugin, get_author_homepage); LILV_WRAP0(bool, plugin, is_replaced); + LILV_WRAP0(Nodes, plugin, get_extension_data); + LILV_WRAP1(Nodes, plugin, get_related, Node, pred); LILV_WRAP0(UIs, plugin, get_uis); inline Port get_port_by_index(unsigned index) { @@ -284,6 +290,7 @@ struct World { LILV_WRAP2_VOID(world, set_option, const char*, uri, LilvNode*, value); LILV_WRAP0_VOID(world, load_all); LILV_WRAP1_VOID(world, load_bundle, LilvNode*, bundle_uri); + LILV_WRAP1_VOID(world, load_resource, LilvNode*, resource); LILV_WRAP0(const LilvPluginClass*, world, get_plugin_class); LILV_WRAP0(const LilvPluginClasses*, world, get_plugin_classes); LILV_WRAP0(const Plugins, world, get_all_plugins); diff --git a/src/carla-includes/lv2/programs.h b/src/carla-includes/lv2/programs.h new file mode 100644 index 0000000..eb969b8 --- /dev/null +++ b/src/carla-includes/lv2/programs.h @@ -0,0 +1,141 @@ +/* + LV2 Programs Extension + Copyright 2012 Filipe Coelho + + Permission to use, copy, modify, and/or distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. + + THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +*/ + +/** + @file programs.h + C header for the LV2 programs extension . +*/ + +#ifndef LV2_PROGRAMS_H +#define LV2_PROGRAMS_H + +#include + +#define LV2_PROGRAMS_URI "http://kxstudio.sf.net/ns/lv2ext/programs" +#define LV2_PROGRAMS_PREFIX LV2_PROGRAMS_URI "#" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void* LV2_Programs_Handle; + +typedef struct _LV2_Program_Descriptor { + + /** Bank number for this program. Note that this extension does not + support MIDI-style separation of bank LSB and MSB values. There is + no restriction on the set of available banks: the numbers do not + need to be contiguous, there does not need to be a bank 0, etc. */ + uint32_t bank; + + /** Program number (unique within its bank) for this program. + There is no restriction on the set of available programs: the + numbers do not need to be contiguous, there does not need to + be a program 0, etc. */ + uint32_t program; + + /** Name of the program. */ + const char * name; + +} LV2_Program_Descriptor; + +/** + Programs extension, plugin data. + + When the plugin's extension_data is called with argument LV2_PROGRAMS_URI, + the plugin MUST return an LV2_Programs_Plugin_Extension structure, which + remains valid for the lifetime of the plugin. +*/ +typedef struct { + /** + * get_program() + * + * This member is a function pointer that provides a description + * of a program (named preset sound) available on this plugin. + * + * The Index argument is an index into the plugin's list of + * programs, not a program number as represented by the Program + * field of the LV2_Program_Descriptor. (This distinction is + * needed to support plugins that use non-contiguous program or + * bank numbers.) + * + * This function returns a LV2_Program_Descriptor pointer that is + * guaranteed to be valid only until the next call to get_program, + * deactivate, or configure, on the same plugin instance. This + * function must return NULL if passed an Index argument out of + * range, so that the host can use it to query the number of + * programs as well as their properties. + */ + const LV2_Program_Descriptor *(*get_program)(LV2_Programs_Handle handle, + uint32_t index); + + /** + * select_program() + * + * This member is a function pointer that selects a new program + * for this plugin. The program change should take effect + * immediately at the start of the next run() call. (This + * means that a host providing the capability of changing programs + * between any two notes on a track must vary the block size so as + * to place the program change at the right place. A host that + * wanted to avoid this would probably just instantiate a plugin + * for each program.) + * + * Plugins should ignore a select_program() call with an invalid + * bank or program. + * + * A plugin is not required to select any particular default + * program on activate(): it's the host's duty to set a program + * explicitly. + * + * A plugin is permitted to re-write the values of its input + * control ports when select_program is called. The host should + * re-read the input control port values and update its own + * records appropriately. (This is the only circumstance in which + * a LV2 plugin is allowed to modify its own control-input ports.) + */ + void (*select_program)(LV2_Programs_Handle handle, + uint32_t bank, + uint32_t program); + +} LV2_Programs_Plugin_Extension; + +/** + Programs extension, UI data. + + When the UI's extension_data is called with argument LV2_PROGRAMS_URI, + the UI MUST return an LV2_Programs_UI_Extension structure, which + remains valid for the lifetime of the UI. +*/ +typedef struct { + /** + * select_program() + * + * This is exactly the same as select_program in LV2_Programs_Plugin_Extension, + * but this struct related to a UI instead of a plugin. + */ + void (*select_program)(LV2_Programs_Handle handle, + uint32_t bank, + uint32_t program); + +} LV2_Programs_UI_Extension; + +#ifdef __cplusplus +} +#endif + +#endif /* LV2_PROGRAMS_H */ diff --git a/src/carla-lilv/lilv-0.14.0/lilv/lilv.h b/src/carla-lilv/lilv-0.14.0/lilv/lilv.h index 2423c6e..96746a7 100644 --- a/src/carla-lilv/lilv-0.14.0/lilv/lilv.h +++ b/src/carla-lilv/lilv-0.14.0/lilv/lilv.h @@ -1692,6 +1692,25 @@ LILV_API const LilvNode* lilv_ui_get_binary_uri(const LilvUI* ui); +/** + Custom calls +*/ +LILV_API +LilvNodes* +lilv_ui_get_supported_features(const LilvUI* ui); + +LILV_API +LilvNodes* +lilv_ui_get_required_features(const LilvUI* ui); + +LILV_API +LilvNodes* +lilv_ui_get_optional_features(const LilvUI* ui); + +LILV_API +LilvNodes* +lilv_ui_get_extension_data(const LilvUI* ui); + /** @} @} diff --git a/src/carla-lilv/lilv-0.14.0/lilv/lilvmm.hpp b/src/carla-lilv/lilv-0.14.0/lilv/lilvmm.hpp deleted file mode 100644 index fc080e2..0000000 --- a/src/carla-lilv/lilv-0.14.0/lilv/lilvmm.hpp +++ /dev/null @@ -1,279 +0,0 @@ -/* - Copyright 2007-2011 David Robillard - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#ifndef LILV_LILVMM_HPP -#define LILV_LILVMM_HPP - -#include "lilv/lilv.h" - -namespace Lilv { - -static inline const char* -uri_to_path(const char* uri) { - return lilv_uri_to_path(uri); -} - -#define LILV_WRAP0(RT, prefix, name) \ - inline RT name() { return lilv_ ## prefix ## _ ## name (me); } - -#define LILV_WRAP0_VOID(prefix, name) \ - inline void name() { lilv_ ## prefix ## _ ## name(me); } - -#define LILV_WRAP1(RT, prefix, name, T1, a1) \ - inline RT name(T1 a1) { return lilv_ ## prefix ## _ ## name (me, a1); } - -#define LILV_WRAP1_VOID(prefix, name, T1, a1) \ - inline void name(T1 a1) { lilv_ ## prefix ## _ ## name(me, a1); } - -#define LILV_WRAP2(RT, prefix, name, T1, a1, T2, a2) \ - inline RT name(T1 a1, T2 a2) { \ - return lilv_ ## prefix ## _ ## name(me, a1, a2); \ - } - -#define LILV_WRAP2_VOID(prefix, name, T1, a1, T2, a2) \ - inline void name(T1 a1, T2 a2) { lilv_ ## prefix ## _ ## name(me, a1, a2); } - -#ifndef SWIG -#define LILV_WRAP_CONVERSION(CT) \ - inline operator CT*() const { return me; } -#else -#define LILV_WRAP_CONVERSION(CT) -#endif - -struct Node { - inline Node(const LilvNode* node) : me(lilv_node_duplicate(node)) {} - inline Node(const Node& copy) : me(lilv_node_duplicate(copy.me)) {} - - inline ~Node() { lilv_node_free(me); } - - inline bool equals(const Node& other) const { - return lilv_node_equals(me, other.me); - } - - inline bool operator==(const Node& other) const { return equals(other); } - - LILV_WRAP_CONVERSION(LilvNode); - - LILV_WRAP0(char*, node, get_turtle_token); - LILV_WRAP0(bool, node, is_uri); - LILV_WRAP0(const char*, node, as_uri); - LILV_WRAP0(bool, node, is_blank); - LILV_WRAP0(const char*, node, as_blank); - LILV_WRAP0(bool, node, is_literal); - LILV_WRAP0(bool, node, is_string); - LILV_WRAP0(const char*, node, as_string); - LILV_WRAP0(bool, node, is_float); - LILV_WRAP0(float, node, as_float); - LILV_WRAP0(bool, node, is_int); - LILV_WRAP0(int, node, as_int); - LILV_WRAP0(bool, node, is_bool); - LILV_WRAP0(bool, node, as_bool); - - LilvNode* me; -}; - -struct ScalePoint { - inline ScalePoint(const LilvScalePoint* c_obj) : me(c_obj) {} - LILV_WRAP_CONVERSION(const LilvScalePoint); - - LILV_WRAP0(const LilvNode*, scale_point, get_label); - LILV_WRAP0(const LilvNode*, scale_point, get_value); - - const LilvScalePoint* me; -}; - -struct PluginClass { - inline PluginClass(const LilvPluginClass* c_obj) : me(c_obj) {} - LILV_WRAP_CONVERSION(const LilvPluginClass); - - LILV_WRAP0(Node, plugin_class, get_parent_uri); - LILV_WRAP0(Node, plugin_class, get_uri); - LILV_WRAP0(Node, plugin_class, get_label); - LILV_WRAP0(LilvPluginClasses*, plugin_class, get_children); - - const LilvPluginClass* me; -}; - -#define LILV_WRAP_COLL(CT, ET, prefix) \ - inline CT(const Lilv ## CT* c_obj) : me(c_obj) {} \ - LILV_WRAP_CONVERSION(const Lilv ## CT); \ - LILV_WRAP0(unsigned, prefix, size); \ - LILV_WRAP1(const ET, prefix, get, LilvIter*, i); \ - LILV_WRAP0(LilvIter*, prefix, begin); \ - LILV_WRAP1(LilvIter*, prefix, next, LilvIter*, i); \ - LILV_WRAP1(bool, prefix, is_end, LilvIter*, i); \ - const Lilv ## CT* me; \ - -struct PluginClasses { - LILV_WRAP_COLL(PluginClasses, PluginClass, plugin_classes); - LILV_WRAP1(const PluginClass, plugin_classes, - get_by_uri, const LilvNode*, uri); -}; - -struct ScalePoints { - LILV_WRAP_COLL(ScalePoints, ScalePoint, scale_points); -}; - -struct Nodes { - LILV_WRAP_COLL(Nodes, Node, nodes); - LILV_WRAP1(bool, nodes, contains, const Node, node); -}; - -struct Port { - inline Port(const LilvPlugin* p, const LilvPort* c_obj) - : parent(p), me(c_obj) - {} - - LILV_WRAP_CONVERSION(const LilvPort); - -#define LILV_PORT_WRAP0(RT, name) \ - inline RT name () { return lilv_port_ ## name (parent, me); } - -#define LILV_PORT_WRAP1(RT, name, T1, a1) \ - inline RT name (T1 a1) { return lilv_port_ ## name (parent, me, a1); } - - LILV_PORT_WRAP1(LilvNodes*, get_value, LilvNode*, predicate); - LILV_PORT_WRAP0(LilvNodes*, get_properties) - LILV_PORT_WRAP1(bool, has_property, LilvNode*, property_uri); - LILV_PORT_WRAP1(bool, supports_event, LilvNode*, event_uri); - LILV_PORT_WRAP0(const LilvNode*, get_symbol); - LILV_PORT_WRAP0(LilvNode*, get_name); - LILV_PORT_WRAP0(const LilvNodes*, get_classes); - LILV_PORT_WRAP1(bool, is_a, LilvNode*, port_class); - LILV_PORT_WRAP0(LilvScalePoints*, get_scale_points); - - // TODO: get_range (output parameters) - - const LilvPlugin* parent; - const LilvPort* me; -}; - -struct Plugin { - inline Plugin(const LilvPlugin* c_obj) : me(c_obj) {} - LILV_WRAP_CONVERSION(const LilvPlugin); - - LILV_WRAP0(bool, plugin, verify); - LILV_WRAP0(Node, plugin, get_uri); - LILV_WRAP0(Node, plugin, get_bundle_uri); - LILV_WRAP0(Nodes, plugin, get_data_uris); - LILV_WRAP0(Node, plugin, get_library_uri); - LILV_WRAP0(Node, plugin, get_name); - LILV_WRAP0(PluginClass, plugin, get_class); - LILV_WRAP1(Nodes, plugin, get_value, Node, pred); - LILV_WRAP1(bool, plugin, has_feature, Node, feature_uri); - LILV_WRAP0(Nodes, plugin, get_supported_features); - LILV_WRAP0(Nodes, plugin, get_required_features); - LILV_WRAP0(Nodes, plugin, get_optional_features); - LILV_WRAP0(unsigned, plugin, get_num_ports); - LILV_WRAP0(bool, plugin, has_latency); - LILV_WRAP0(unsigned, plugin, get_latency_port_index); - LILV_WRAP0(Node, plugin, get_author_name); - LILV_WRAP0(Node, plugin, get_author_email); - LILV_WRAP0(Node, plugin, get_author_homepage); - LILV_WRAP0(bool, plugin, is_replaced); - - inline Port get_port_by_index(unsigned index) { - return Port(me, lilv_plugin_get_port_by_index(me, index)); - } - - inline Port get_port_by_symbol(LilvNode* symbol) { - return Port(me, lilv_plugin_get_port_by_symbol(me, symbol)); - } - - inline void get_port_ranges_float(float* min_values, - float* max_values, - float* def_values) { - return lilv_plugin_get_port_ranges_float( - me, min_values, max_values, def_values); - } - - inline unsigned get_num_ports_of_class(LilvNode* class_1, - LilvNode* class_2) { - // TODO: varargs - return lilv_plugin_get_num_ports_of_class(me, class_1, class_2, NULL); - } - - const LilvPlugin* me; -}; - -struct Plugins { - LILV_WRAP_COLL(Plugins, Plugin, plugins); - LILV_WRAP1(const Plugin, plugins, get_by_uri, const LilvNode*, uri); -}; - -struct Instance { - inline Instance(Plugin plugin, double sample_rate) { - // TODO: features - me = lilv_plugin_instantiate(plugin, sample_rate, NULL); - } - - LILV_WRAP_CONVERSION(LilvInstance); - - LILV_WRAP2_VOID(instance, connect_port, - unsigned, port_index, - void*, data_location); - - LILV_WRAP0_VOID(instance, activate); - LILV_WRAP1_VOID(instance, run, unsigned, sample_count); - LILV_WRAP0_VOID(instance, deactivate); - - // TODO: get_extension_data - - inline const LV2_Descriptor* get_descriptor() { - return lilv_instance_get_descriptor(me); - } - - LilvInstance* me; -}; - -struct World { - inline World() : me(lilv_world_new()) {} - inline ~World() { lilv_world_free(me); } - - inline LilvNode* new_uri(const char* uri) { - return lilv_new_uri(me, uri); - } - inline LilvNode* new_string(const char* str) { - return lilv_new_string(me, str); - } - inline LilvNode* new_int(int val) { - return lilv_new_int(me, val); - } - inline LilvNode* new_float(float val) { - return lilv_new_float(me, val); - } - inline LilvNode* new_bool(bool val) { - return lilv_new_bool(me, val); - } - inline Nodes find_nodes(const LilvNode* subject, - const LilvNode* predicate, - const LilvNode* object) { - return lilv_world_find_nodes(me, subject, predicate, object); - } - - LILV_WRAP2_VOID(world, set_option, const char*, uri, LilvNode*, value); - LILV_WRAP0_VOID(world, load_all); - LILV_WRAP1_VOID(world, load_bundle, LilvNode*, bundle_uri); - LILV_WRAP0(const LilvPluginClass*, world, get_plugin_class); - LILV_WRAP0(const LilvPluginClasses*, world, get_plugin_classes); - LILV_WRAP0(const Plugins, world, get_all_plugins); - - LilvWorld* me; -}; - -} /* namespace Lilv */ - -#endif /* LILV_LILVMM_HPP */ diff --git a/src/carla-lilv/lilv-0.14.0/src/ui.c b/src/carla-lilv/lilv-0.14.0/src/ui.c index 5d2f066..6e08dee 100644 --- a/src/carla-lilv/lilv-0.14.0/src/ui.c +++ b/src/carla-lilv/lilv-0.14.0/src/ui.c @@ -128,3 +128,57 @@ lilv_ui_get_binary_uri(const LilvUI* ui) assert(ui->binary_uri); return ui->binary_uri; } + +static LilvNodes* +lilv_ui_get_value_internal(const LilvUI* ui, + const SordNode* predicate) +{ + return lilv_world_query_values_internal( + ui->world, ui->uri->val.uri_val, predicate, NULL); +} + +LILV_API +LilvNodes* +lilv_ui_get_supported_features(const LilvUI* ui) +{ + LilvNodes* optional = lilv_ui_get_optional_features(ui); + LilvNodes* required = lilv_ui_get_required_features(ui); + LilvNodes* result = lilv_nodes_new(); + + LILV_FOREACH(nodes, i, optional) + zix_tree_insert((ZixTree*)result, + lilv_node_duplicate(lilv_nodes_get(optional, i)), + NULL); + LILV_FOREACH(nodes, i, required) + zix_tree_insert((ZixTree*)result, + lilv_node_duplicate(lilv_nodes_get(required, i)), + NULL); + + lilv_nodes_free(optional); + lilv_nodes_free(required); + + return result; +} + +LILV_API +LilvNodes* +lilv_ui_get_required_features(const LilvUI* ui) +{ + return lilv_ui_get_value_internal( + ui, ui->world->uris.lv2_requiredFeature); +} + +LILV_API +LilvNodes* +lilv_ui_get_optional_features(const LilvUI* ui) +{ + return lilv_ui_get_value_internal( + ui, ui->world->uris.lv2_optionalFeature); +} + +LILV_API +LilvNodes* +lilv_ui_get_extension_data(const LilvUI* ui) +{ + return lilv_ui_get_value_internal(ui, ui->world->uris.lv2_extensionData); +} diff --git a/src/carla/carla_backend.cpp b/src/carla/carla_backend.cpp index 2a94de5..397a26c 100644 --- a/src/carla/carla_backend.cpp +++ b/src/carla/carla_backend.cpp @@ -18,9 +18,6 @@ #include "carla_plugin.h" #include "carla_threads.h" -//#include -//#include - // plugin specific short add_plugin_ladspa(const char* filename, const char* label, void* extra_stuff); short add_plugin_dssi(const char* filename, const char* label, void* extra_stuff); @@ -29,6 +26,8 @@ short add_plugin_vst(const char* filename, const char* label); short add_plugin_sf2(const char* filename, const char* label); short add_plugin_bridge(BinaryType btype, PluginType ptype, const char* filename, const char* label, void* extra_stuff); +void lv2_load_all(); + CarlaCheckThread carla_check_thread; // ------------------------------------------------------------------------------------------------------------------- @@ -1129,6 +1128,7 @@ void set_option(OptionsType option, int value, const char* value_str) break; case OPTION_PATH_LV2: setenv("LV2_PATH", value_str, 1); + lv2_load_all(); break; case OPTION_PATH_VST: setenv("VST_PATH", value_str, 1); diff --git a/src/carla/lv2.cpp b/src/carla/lv2.cpp index 092725a..87a000d 100644 --- a/src/carla/lv2.cpp +++ b/src/carla/lv2.cpp @@ -30,6 +30,8 @@ #include "lv2/instance-access.h" #include "lv2/midi.h" #include "lv2/port-props.h" +#include "lv2/presets.h" +#include "lv2/programs.h" #include "lv2/state.h" #include "lv2/time.h" #include "lv2/ui.h" @@ -42,21 +44,21 @@ #include "lv2/lv2_rtmempool.h" #include "lv2/lv2_external_ui.h" -#include "lilv/lilvmm.hpp" #include "lv2_rdf.h" extern "C" { #include "lv2-rtmempool/rtmempool.h" } -#define NS_dct "http://purl.org/dc/terms/" -#define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" -#define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#" +#if 1 +int main() +{ + Lv2World.load_all(); -#define LV2_MIDI_LL__MidiPort "http://ll-plugins.nongnu.org/lv2/ext/MidiPort" + lv2_rdf_free(lv2_rdf_new("http://drobilla.net/plugins/mda/Piano")); -#if 1 -int main() { return 0; } + return 0; +} #endif #include @@ -145,273 +147,6 @@ const char* lv2bridge2str(LV2_Property type) } } -class Lv2WorldClass : public Lilv::World -{ -public: - Lv2WorldClass() : Lilv::World(), - class_allpass (new_uri(LV2_CORE__AllpassPlugin)), - class_amplifier (new_uri(LV2_CORE__AmplifierPlugin)), - class_analyzer (new_uri(LV2_CORE__AnalyserPlugin)), - class_bandpass (new_uri(LV2_CORE__BandpassPlugin)), - class_chorus (new_uri(LV2_CORE__ChorusPlugin)), - class_comb (new_uri(LV2_CORE__CombPlugin)), - class_compressor (new_uri(LV2_CORE__CompressorPlugin)), - class_constant (new_uri(LV2_CORE__ConstantPlugin)), - class_converter (new_uri(LV2_CORE__ConverterPlugin)), - class_delay (new_uri(LV2_CORE__DelayPlugin)), - class_distortion (new_uri(LV2_CORE__DistortionPlugin)), - class_dynamics (new_uri(LV2_CORE__DynamicsPlugin)), - class_eq (new_uri(LV2_CORE__EQPlugin)), - class_expander (new_uri(LV2_CORE__ExpanderPlugin)), - class_filter (new_uri(LV2_CORE__FilterPlugin)), - class_flanger (new_uri(LV2_CORE__FlangerPlugin)), - class_function (new_uri(LV2_CORE__FunctionPlugin)), - class_gate (new_uri(LV2_CORE__GatePlugin)), - class_generator (new_uri(LV2_CORE__GeneratorPlugin)), - class_highpass (new_uri(LV2_CORE__HighpassPlugin)), - class_instrument (new_uri(LV2_CORE__InstrumentPlugin)), - class_limiter (new_uri(LV2_CORE__LimiterPlugin)), - class_lowpass (new_uri(LV2_CORE__LowpassPlugin)), - class_mixer (new_uri(LV2_CORE__MixerPlugin)), - class_modulator (new_uri(LV2_CORE__ModulatorPlugin)), - class_multi_eq (new_uri(LV2_CORE__MultiEQPlugin)), - class_oscillator (new_uri(LV2_CORE__OscillatorPlugin)), - class_para_eq (new_uri(LV2_CORE__ParaEQPlugin)), - class_phaser (new_uri(LV2_CORE__PhaserPlugin)), - class_pitch (new_uri(LV2_CORE__PitchPlugin)), - class_reverb (new_uri(LV2_CORE__ReverbPlugin)), - class_simulator (new_uri(LV2_CORE__SimulatorPlugin)), - class_spatial (new_uri(LV2_CORE__SpatialPlugin)), - class_spectral (new_uri(LV2_CORE__SpectralPlugin)), - class_utility (new_uri(LV2_CORE__UtilityPlugin)), - class_waveshaper (new_uri(LV2_CORE__WaveshaperPlugin)), - - port_input (new_uri(LV2_CORE__InputPort)), - port_output (new_uri(LV2_CORE__OutputPort)), - port_control (new_uri(LV2_CORE__ControlPort)), - port_audio (new_uri(LV2_CORE__AudioPort)), - port_cv (new_uri(LV2_CORE__CVPort)), - port_atom (new_uri(LV2_ATOM__AtomPort)), - port_event (new_uri(LV2_EVENT__EventPort)), - port_midi_ll (new_uri(LV2_MIDI_LL__MidiPort)), - - pprop_optional (new_uri(LV2_CORE__connectionOptional)), - pprop_enumeration (new_uri(LV2_CORE__enumeration)), - pprop_integer (new_uri(LV2_CORE__integer)), - pprop_sample_rate (new_uri(LV2_CORE__sampleRate)), - pprop_toggled (new_uri(LV2_CORE__toggled)), - pprop_artifacts (new_uri(LV2_PORT_PROPS__causesArtifacts)), - pprop_continuous_cv (new_uri(LV2_PORT_PROPS__continuousCV)), - pprop_discrete_cv (new_uri(LV2_PORT_PROPS__discreteCV)), - pprop_expensive (new_uri(LV2_PORT_PROPS__expensive)), - pprop_strict_bounds (new_uri(LV2_PORT_PROPS__hasStrictBounds)), - pprop_logarithmic (new_uri(LV2_PORT_PROPS__logarithmic)), - pprop_not_automatic (new_uri(LV2_PORT_PROPS__notAutomatic)), - pprop_not_on_gui (new_uri(LV2_PORT_PROPS__notOnGUI)), - pprop_trigger (new_uri(LV2_PORT_PROPS__trigger)), - - unit_unit (new_uri(LV2_UNITS__unit)), - unit_name (new_uri(LV2_UNITS__name)), - unit_render (new_uri(LV2_UNITS__render)), - unit_symbol (new_uri(LV2_UNITS__symbol)), - - unit_bar (new_uri(LV2_UNITS__bar)), - unit_beat (new_uri(LV2_UNITS__beat)), - unit_bpm (new_uri(LV2_UNITS__bpm)), - unit_cent (new_uri(LV2_UNITS__cent)), - unit_cm (new_uri(LV2_UNITS__cm)), - unit_coef (new_uri(LV2_UNITS__coef)), - unit_db (new_uri(LV2_UNITS__db)), - unit_degree (new_uri(LV2_UNITS__degree)), - unit_frame (new_uri(LV2_UNITS__frame)), - unit_hz (new_uri(LV2_UNITS__hz)), - unit_inch (new_uri(LV2_UNITS__inch)), - unit_khz (new_uri(LV2_UNITS__khz)), - unit_km (new_uri(LV2_UNITS__km)), - unit_m (new_uri(LV2_UNITS__m)), - unit_mhz (new_uri(LV2_UNITS__mhz)), - unit_midi_note (new_uri(LV2_UNITS__midiNote)), - unit_mile (new_uri(LV2_UNITS__mile)), - unit_min (new_uri(LV2_UNITS__min)), - unit_mm (new_uri(LV2_UNITS__mm)), - unit_ms (new_uri(LV2_UNITS__ms)), - unit_oct (new_uri(LV2_UNITS__oct)), - unit_pc (new_uri(LV2_UNITS__pc)), - unit_s (new_uri(LV2_UNITS__s)), - unit_semitone (new_uri(LV2_UNITS__semitone12TET)), - - ui_gtk2 (new_uri(LV2_UI__GtkUI)), - ui_qt4 (new_uri(LV2_UI__Qt4UI)), - ui_x11 (new_uri(LV2_UI__X11UI)), - ui_external (new_uri(LV2_EXTERNAL_UI_URI)), - ui_external_old (new_uri(LV2_EXTERNAL_UI_DEPRECATED_URI)), - - extension_data (new_uri(LV2_CORE_PREFIX "extensionData")), // FIXME - typo in lv2 ? - - value_default (new_uri(LV2_CORE__default)), - value_minimum (new_uri(LV2_CORE__minimum)), - value_maximum (new_uri(LV2_CORE__maximum)), - - atom_sequence (new_uri(LV2_ATOM__Sequence)), - atom_buffer_type (new_uri(LV2_ATOM__bufferType)), - atom_supports (new_uri(LV2_ATOM__supports)), - - midi_event (new_uri(LV2_MIDI__MidiEvent)), - - time_position (new_uri(LV2_TIME__Position)), - - mm_default_controller (new_uri(NS_llmm "defaultMidiController")), - mm_controller_type (new_uri(NS_llmm "controllerType")), - mm_controller_number (new_uri(NS_llmm "controllerNumber")), - - dct_replaces (new_uri(NS_dct "replaces")), - rdf_type (new_uri(NS_rdf "type")) - { - initiated = false; - } - - void Init() - { - if (initiated == false) - { - qDebug("Lv2World::Init()"); - initiated = true; - load_all(); - } - } - - // Plugin Types - Lilv::Node class_allpass; - Lilv::Node class_amplifier; - Lilv::Node class_analyzer; - Lilv::Node class_bandpass; - Lilv::Node class_chorus; - Lilv::Node class_comb; - Lilv::Node class_compressor; - Lilv::Node class_constant; - Lilv::Node class_converter; - Lilv::Node class_delay; - Lilv::Node class_distortion; - Lilv::Node class_dynamics; - Lilv::Node class_eq; - Lilv::Node class_expander; - Lilv::Node class_filter; - Lilv::Node class_flanger; - Lilv::Node class_function; - Lilv::Node class_gate; - Lilv::Node class_generator; - Lilv::Node class_highpass; - Lilv::Node class_instrument; - Lilv::Node class_limiter; - Lilv::Node class_lowpass; - Lilv::Node class_mixer; - Lilv::Node class_modulator; - Lilv::Node class_multi_eq; - Lilv::Node class_oscillator; - Lilv::Node class_para_eq; - Lilv::Node class_phaser; - Lilv::Node class_pitch; - Lilv::Node class_reverb; - Lilv::Node class_simulator; - Lilv::Node class_spatial; - Lilv::Node class_spectral; - Lilv::Node class_utility; - Lilv::Node class_waveshaper; - - // Port Types - Lilv::Node port_input; - Lilv::Node port_output; - Lilv::Node port_control; - Lilv::Node port_audio; - Lilv::Node port_cv; - Lilv::Node port_atom; - Lilv::Node port_event; - Lilv::Node port_midi_ll; - - // Port Properties - Lilv::Node pprop_optional; - Lilv::Node pprop_enumeration; - Lilv::Node pprop_integer; - Lilv::Node pprop_sample_rate; - Lilv::Node pprop_toggled; - Lilv::Node pprop_artifacts; - Lilv::Node pprop_continuous_cv; - Lilv::Node pprop_discrete_cv; - Lilv::Node pprop_expensive; - Lilv::Node pprop_strict_bounds; - Lilv::Node pprop_logarithmic; - Lilv::Node pprop_not_automatic; - Lilv::Node pprop_not_on_gui; - Lilv::Node pprop_trigger; - - // Port Unit - Lilv::Node unit_unit; - Lilv::Node unit_name; - Lilv::Node unit_render; - Lilv::Node unit_symbol; - - // Unit Types - Lilv::Node unit_bar; - Lilv::Node unit_beat; - Lilv::Node unit_bpm; - Lilv::Node unit_cent; - Lilv::Node unit_cm; - Lilv::Node unit_coef; - Lilv::Node unit_db; - Lilv::Node unit_degree; - Lilv::Node unit_frame; - Lilv::Node unit_hz; - Lilv::Node unit_inch; - Lilv::Node unit_khz; - Lilv::Node unit_km; - Lilv::Node unit_m; - Lilv::Node unit_mhz; - Lilv::Node unit_midi_note; - Lilv::Node unit_mile; - Lilv::Node unit_min; - Lilv::Node unit_mm; - Lilv::Node unit_ms; - Lilv::Node unit_oct; - Lilv::Node unit_pc; - Lilv::Node unit_s; - Lilv::Node unit_semitone; - - // UI Types - Lilv::Node ui_gtk2; - Lilv::Node ui_qt4; - Lilv::Node ui_x11; - Lilv::Node ui_external; - Lilv::Node ui_external_old; - - // LV2 stuff - Lilv::Node extension_data; - - Lilv::Node value_default; - Lilv::Node value_minimum; - Lilv::Node value_maximum; - - Lilv::Node atom_sequence; - Lilv::Node atom_buffer_type; - Lilv::Node atom_supports; - - Lilv::Node midi_event; - - Lilv::Node time_position; - - Lilv::Node mm_default_controller; - Lilv::Node mm_controller_type; - Lilv::Node mm_controller_number; - - // Other - Lilv::Node dct_replaces; - Lilv::Node rdf_type; - -private: - bool initiated; -}; - -static Lv2WorldClass Lv2World; - class Lv2Plugin : public CarlaPlugin { public: @@ -440,6 +175,9 @@ public: ui.descriptor = nullptr; ui.rdf_descriptor = nullptr; + programs.plugin = nullptr; + programs.ui = nullptr; + gui.type = GUI_NONE; gui.visible = false; gui.resizable = false; @@ -452,8 +190,6 @@ public: for (uint32_t i=0; i < lv2_feature_count+1; i++) features[i] = nullptr; - - Lv2World.Init(); } virtual ~Lv2Plugin() @@ -892,7 +628,7 @@ public: this, &ui.widget, features); - update_ui_ports(); + update_ui(); } break; @@ -901,6 +637,32 @@ public: } } + virtual void set_midi_program(int32_t index, bool gui_send, bool osc_send, bool callback_send, bool block) + { + if (! programs.plugin) + return; + + if (index >= 0) + { + // TODO - go for id -1 so we don't block audio + if (block) carla_proc_lock(); + programs.plugin->select_program(handle, midiprog.data[index].bank, midiprog.data[index].program); + if (block) carla_proc_unlock(); + +#ifndef BUILD_BRIDGE + if (gui_send) + { + if (gui.type == GUI_EXTERNAL_OSC) + osc_send_program_as_midi(&osc.data, midiprog.data[index].bank, midiprog.data[index].program); + else if (programs.ui) + programs.ui->select_program(ui.handle, midiprog.data[index].bank, midiprog.data[index].program); + } +#endif + } + + CarlaPlugin::set_midi_program(index, gui_send, osc_send, callback_send, block); + } + virtual void show_gui(bool yesno) { // FIXME - is gui.visible needed at all? @@ -1411,17 +1173,10 @@ public: } else if (LV2_IS_PORT_OUTPUT(PortType)) { - param.data[j].type = PARAMETER_OUTPUT; - param.data[j].hints |= PARAMETER_IS_ENABLED; - - if (LV2_IS_PORT_LATENCY(PortProps) == false) - { - param.data[j].hints |= PARAMETER_IS_AUTOMABLE; - needs_cout = true; - } - else + if (LV2_IS_PORT_LATENCY(PortProps)) { - // latency parameter + param.data[j].type = PARAMETER_LATENCY; + param.data[j].hints = 0; min = 0; max = get_sample_rate(); def = 0; @@ -1429,6 +1184,12 @@ public: step_small = 1; step_large = 1; } + else + { + param.data[j].type = PARAMETER_OUTPUT; + param.data[j].hints = PARAMETER_IS_ENABLED | PARAMETER_IS_AUTOMABLE; + needs_cout = true; + } } else { @@ -1531,6 +1292,108 @@ public: jack_activate(jack_client); } + virtual void reload_programs(bool init) + { + qDebug("Lv2Plugin::reload_programs(%s)", bool2str(init)); + uint32_t i, old_count = midiprog.count; + + // Delete old programs + if (midiprog.count > 0) + { + for (uint32_t i=0; i < midiprog.count; i++) + free((void*)midiprog.data[i].name); + + delete[] midiprog.data; + } + + midiprog.count = 0; + midiprog.data = nullptr; + + // Query new programs + if (descriptor->extension_data) + programs.plugin = (LV2_Programs_Plugin_Extension*)descriptor->extension_data(LV2_PROGRAMS_URI); + else + programs.plugin = nullptr; + + if (programs.plugin) + { + while (programs.plugin->get_program(handle, midiprog.count)) + midiprog.count += 1; + } + + if (midiprog.count > 0) + midiprog.data = new midi_program_t [midiprog.count]; + + // Update data + for (i=0; i < midiprog.count; i++) + { + const LV2_Program_Descriptor* pdesc = programs.plugin->get_program(handle, i); + if (pdesc) + { + midiprog.data[i].bank = pdesc->bank; + midiprog.data[i].program = pdesc->program; + midiprog.data[i].name = strdup(pdesc->name); + } + else + { + midiprog.data[i].bank = 0; + midiprog.data[i].program = 0; + midiprog.data[i].name = strdup("(error)"); + } + } + +#ifndef BUILD_BRIDGE + // Update OSC Names + osc_global_send_set_midi_program_count(m_id, midiprog.count); + + for (i=0; i < midiprog.count; i++) + osc_global_send_set_midi_program_data(m_id, i, midiprog.data[i].bank, midiprog.data[i].program, midiprog.data[i].name); +#endif + + callback_action(CALLBACK_RELOAD_PROGRAMS, m_id, 0, 0, 0.0); + + if (init) + { + if (midiprog.count > 0) + set_midi_program(0, false, false, false, true); + } + else + { + callback_action(CALLBACK_UPDATE, m_id, 0, 0, 0.0); + + // Check if current program is invalid + bool program_changed = false; + + if (midiprog.count == old_count+1) + { + // one midi program added, probably created by user + midiprog.current = old_count; + program_changed = true; + } + else if (midiprog.current >= (int32_t)midiprog.count) + { + // current midi program > count + midiprog.current = 0; + program_changed = true; + } + else if (midiprog.current < 0 && midiprog.count > 0) + { + // programs exist now, but not before + midiprog.current = 0; + program_changed = true; + } + else if (midiprog.current >= 0 && midiprog.count == 0) + { + // programs existed before, but not anymore + midiprog.current = -1; + program_changed = true; + } + + if (program_changed) + set_midi_program(midiprog.current, true, true, true, true); + } + } + virtual void prepare_for_save() { if ((m_hints & PLUGIN_HAS_EXTENSION_STATE) > 0 && descriptor->extension_data) @@ -1761,8 +1624,6 @@ public: uint32_t mbank_id = next_bank_id; uint32_t mprog_id = pin_event.buffer[1]; // & 0x7F; - // TODO ... - for (k=0; k < midiprog.count; k++) { if (midiprog.data[k].bank == mbank_id && midiprog.data[k].program == mprog_id) @@ -2188,6 +2049,10 @@ public: bool is_ui_bridgeable(uint32_t ui_id) { + return false; + + // FIXME + const LV2_RDF_UI* const rdf_ui = &rdf_descriptor->UIs[ui_id]; for (uint32_t i=0; i < rdf_ui->FeatureCount; i++) @@ -2208,7 +2073,7 @@ public: if (ui.handle && ui.widget) { - update_ui_ports(); + update_ui(); } else { @@ -2220,18 +2085,32 @@ public: } } - void update_ui_ports() + void update_ui() { - qDebug("Lv2Plugin::update_ui_ports()"); + qDebug("Lv2Plugin::update_ui()"); + programs.ui = nullptr; - if (ui.handle && ui.descriptor && ui.descriptor->port_event) + if (ui.handle && ui.descriptor) { - float value; - for (uint32_t i=0; i < param.count; i++) + if (ui.descriptor->extension_data) + { + programs.ui = (LV2_Programs_UI_Extension*)ui.descriptor->extension_data(LV2_PROGRAMS_URI); + + if (programs.ui) + programs.ui->select_program(ui.handle, midiprog.data[midiprog.current].bank, midiprog.data[midiprog.current].program); + } + + if (ui.descriptor->port_event) { - value = get_parameter_value(i); - ui.descriptor->port_event(ui.handle, param.data[i].rindex, sizeof(float), 0, &value); + float value; + for (uint32_t i=0; i < param.count; i++) + { + value = get_parameter_value(i); + ui.descriptor->port_event(ui.handle, param.data[i].rindex, sizeof(float), 0, &value); + } } + + qDebug("Lv2Plugin::update_ui() - %p", programs.ui); } } @@ -2259,562 +2138,7 @@ public: bool init(const char* bundle, const char* URI) { - const Lilv::Plugins Plugins = Lv2World.get_all_plugins(); - - LILV_FOREACH(plugins, i, Plugins) - { - Lilv::Plugin Plugin = Lilv::Plugin(lilv_plugins_get(Plugins, i)); - - if (strcmp(Plugin.get_uri().as_string(), URI) == 0) - { - rdf_descriptor = new LV2_RDF_Descriptor; - - // -------------------------------------------------- - // Set Plugin Type - - rdf_descriptor->Type = 0x0; - - Lilv::Nodes types(Plugin.get_value(Lv2World.rdf_type)); - - if (types.contains(Lv2World.class_allpass)) - rdf_descriptor->Type |= LV2_CLASS_ALLPASS; - if (types.contains(Lv2World.class_amplifier)) - rdf_descriptor->Type |= LV2_CLASS_AMPLIFIER; - if (types.contains(Lv2World.class_analyzer)) - rdf_descriptor->Type |= LV2_CLASS_ANALYSER; - if (types.contains(Lv2World.class_bandpass)) - rdf_descriptor->Type |= LV2_CLASS_BANDPASS; - if (types.contains(Lv2World.class_chorus)) - rdf_descriptor->Type |= LV2_CLASS_CHORUS; - if (types.contains(Lv2World.class_comb)) - rdf_descriptor->Type |= LV2_CLASS_COMB; - if (types.contains(Lv2World.class_compressor)) - rdf_descriptor->Type |= LV2_CLASS_COMPRESSOR; - if (types.contains(Lv2World.class_constant)) - rdf_descriptor->Type |= LV2_CLASS_CONSTANT; - if (types.contains(Lv2World.class_converter)) - rdf_descriptor->Type |= LV2_CLASS_CONVERTER; - if (types.contains(Lv2World.class_delay)) - rdf_descriptor->Type |= LV2_CLASS_DELAY; - if (types.contains(Lv2World.class_distortion)) - rdf_descriptor->Type |= LV2_CLASS_DISTORTION; - if (types.contains(Lv2World.class_dynamics)) - rdf_descriptor->Type |= LV2_CLASS_DYNAMICS; - if (types.contains(Lv2World.class_eq)) - rdf_descriptor->Type |= LV2_CLASS_EQ; - if (types.contains(Lv2World.class_expander)) - rdf_descriptor->Type |= LV2_CLASS_EXPANDER; - if (types.contains(Lv2World.class_filter)) - rdf_descriptor->Type |= LV2_CLASS_FILTER; - if (types.contains(Lv2World.class_flanger)) - rdf_descriptor->Type |= LV2_CLASS_FLANGER; - if (types.contains(Lv2World.class_function)) - rdf_descriptor->Type |= LV2_CLASS_FUNCTION; - if (types.contains(Lv2World.class_gate)) - rdf_descriptor->Type |= LV2_CLASS_GATE; - if (types.contains(Lv2World.class_generator)) - rdf_descriptor->Type |= LV2_CLASS_GENERATOR; - if (types.contains(Lv2World.class_highpass)) - rdf_descriptor->Type |= LV2_CLASS_HIGHPASS; - if (types.contains(Lv2World.class_instrument)) - rdf_descriptor->Type |= LV2_CLASS_INSTRUMENT; - if (types.contains(Lv2World.class_limiter)) - rdf_descriptor->Type |= LV2_CLASS_LIMITER; - if (types.contains(Lv2World.class_lowpass)) - rdf_descriptor->Type |= LV2_CLASS_LOWPASS; - if (types.contains(Lv2World.class_mixer)) - rdf_descriptor->Type |= LV2_CLASS_MIXER; - if (types.contains(Lv2World.class_modulator)) - rdf_descriptor->Type |= LV2_CLASS_MODULATOR; - if (types.contains(Lv2World.class_multi_eq)) - rdf_descriptor->Type |= LV2_CLASS_MULTI_EQ; - if (types.contains(Lv2World.class_oscillator)) - rdf_descriptor->Type |= LV2_CLASS_OSCILLATOR; - if (types.contains(Lv2World.class_para_eq)) - rdf_descriptor->Type |= LV2_CLASS_PARA_EQ; - if (types.contains(Lv2World.class_phaser)) - rdf_descriptor->Type |= LV2_CLASS_PHASER; - if (types.contains(Lv2World.class_pitch)) - rdf_descriptor->Type |= LV2_CLASS_PITCH; - if (types.contains(Lv2World.class_reverb)) - rdf_descriptor->Type |= LV2_CLASS_REVERB; - if (types.contains(Lv2World.class_simulator)) - rdf_descriptor->Type |= LV2_CLASS_SIMULATOR; - if (types.contains(Lv2World.class_spatial)) - rdf_descriptor->Type |= LV2_CLASS_SPATIAL; - if (types.contains(Lv2World.class_spectral)) - rdf_descriptor->Type |= LV2_CLASS_SPECTRAL; - if (types.contains(Lv2World.class_utility)) - rdf_descriptor->Type |= LV2_CLASS_UTILITY; - if (types.contains(Lv2World.class_waveshaper)) - rdf_descriptor->Type |= LV2_CLASS_WAVESHAPER; - - // -------------------------------------------------- - // Set Plugin Information - - // FIXME - get more values - - rdf_descriptor->URI = strdup(URI); - rdf_descriptor->Binary = strdup(lilv_uri_to_path(Plugin.get_library_uri().as_string())); - rdf_descriptor->Bundle = strdup(lilv_uri_to_path(Plugin.get_bundle_uri().as_string())); - - if (Plugin.get_name()) - rdf_descriptor->Name = strdup(Plugin.get_name().as_string()); - else - rdf_descriptor->Name = nullptr; - - if (Plugin.get_author_name()) - rdf_descriptor->Author = strdup(Plugin.get_author_name().as_string()); - else - rdf_descriptor->Author = nullptr; - - rdf_descriptor->License = nullptr; - - // -------------------------------------------------- - // Set Plugin UniqueID - - rdf_descriptor->UniqueID = 0; - - Lilv::Nodes replaces(Plugin.get_value(Lv2World.dct_replaces)); - - if (replaces.size() > 0) - { - Lilv::Node replace_value(lilv_nodes_get(replaces, replaces.begin())); - - if (replace_value.is_uri()) - { - QString replace_uri(replace_value.as_uri()); - - if (replace_uri.startsWith("urn:")) - { - QString replace_id = replace_uri.split(":").last(); - - bool ok; - int uniqueId = replace_id.toInt(&ok); - - if (ok && uniqueId > 0) - rdf_descriptor->UniqueID = uniqueId; - } - } - } - - // -------------------------------------------------- - // Set Plugin Ports - - rdf_descriptor->PortCount = Plugin.get_num_ports(); - - if (rdf_descriptor->PortCount > 0) - { - rdf_descriptor->Ports = new LV2_RDF_Port [rdf_descriptor->PortCount]; - - for (uint32_t j = 0; j < rdf_descriptor->PortCount; j++) - { - Lilv::Port Port = Plugin.get_port_by_index(j); - LV2_RDF_Port* RDF_Port = &rdf_descriptor->Ports[j]; - - // ------------------------------------------ - // Set Port Type - - RDF_Port->Type = 0x0; - - if (Port.is_a(Lv2World.port_input)) - RDF_Port->Type |= LV2_PORT_INPUT; - - if (Port.is_a(Lv2World.port_output)) - RDF_Port->Type |= LV2_PORT_OUTPUT; - - if (Port.is_a(Lv2World.port_control)) - RDF_Port->Type |= LV2_PORT_CONTROL; - - if (Port.is_a(Lv2World.port_audio)) - RDF_Port->Type |= LV2_PORT_AUDIO; - - if (Port.is_a(Lv2World.port_cv)) - RDF_Port->Type |= LV2_PORT_CV; - - if (Port.is_a(Lv2World.port_atom)) - { - RDF_Port->Type |= LV2_PORT_ATOM; - - Lilv::Nodes bufferTypes(Port.get_value(Lv2World.atom_buffer_type)); - if (bufferTypes.contains(Lv2World.atom_sequence)) - RDF_Port->Type |= LV2_PORT_ATOM_SEQUENCE; - - Lilv::Nodes supports(Port.get_value(Lv2World.atom_supports)); - if (supports.contains(Lv2World.midi_event)) - RDF_Port->Type |= LV2_PORT_SUPPORTS_MIDI; - if (supports.contains(Lv2World.time_position)) - RDF_Port->Type |= LV2_PORT_SUPPORTS_TIME; - } - - if (Port.is_a(Lv2World.port_event)) - { - RDF_Port->Type |= LV2_PORT_EVENT; - - if (Port.supports_event(Lv2World.midi_event)) - RDF_Port->Type |= LV2_PORT_SUPPORTS_MIDI; - if (Port.supports_event(Lv2World.time_position)) - RDF_Port->Type |= LV2_PORT_SUPPORTS_TIME; - } - - if (Port.is_a(Lv2World.port_midi_ll)) - { - RDF_Port->Type |= LV2_PORT_MIDI_LL; - RDF_Port->Type |= LV2_PORT_SUPPORTS_MIDI; - } - - // ------------------------------------------ - // Set Port Properties - - RDF_Port->Properties = 0x0; - - if (Port.has_property(Lv2World.pprop_optional)) - RDF_Port->Properties = LV2_PORT_OPTIONAL; - if (Port.has_property(Lv2World.pprop_enumeration)) - RDF_Port->Properties = LV2_PORT_ENUMERATION; - if (Port.has_property(Lv2World.pprop_integer)) - RDF_Port->Properties = LV2_PORT_INTEGER; - if (Port.has_property(Lv2World.pprop_sample_rate)) - RDF_Port->Properties = LV2_PORT_SAMPLE_RATE; - if (Port.has_property(Lv2World.pprop_toggled)) - RDF_Port->Properties = LV2_PORT_TOGGLED; - - if (Port.has_property(Lv2World.pprop_artifacts)) - RDF_Port->Properties = LV2_PORT_CAUSES_ARTIFACTS; - if (Port.has_property(Lv2World.pprop_continuous_cv)) - RDF_Port->Properties = LV2_PORT_CONTINUOUS_CV; - if (Port.has_property(Lv2World.pprop_discrete_cv)) - RDF_Port->Properties = LV2_PORT_DISCRETE_CV; - if (Port.has_property(Lv2World.pprop_expensive)) - RDF_Port->Properties = LV2_PORT_EXPENSIVE; - if (Port.has_property(Lv2World.pprop_strict_bounds)) - RDF_Port->Properties = LV2_PORT_HAS_STRICT_BOUNDS; - if (Port.has_property(Lv2World.pprop_logarithmic)) - RDF_Port->Properties = LV2_PORT_LOGARITHMIC; - if (Port.has_property(Lv2World.pprop_not_automatic)) - RDF_Port->Properties = LV2_PORT_NOT_AUTOMATIC; - if (Port.has_property(Lv2World.pprop_not_on_gui)) - RDF_Port->Properties = LV2_PORT_NOT_ON_GUI; - if (Port.has_property(Lv2World.pprop_trigger)) - RDF_Port->Properties = LV2_PORT_TRIGGER; - - // ------------------------------------------ - // Set Port Designation - - RDF_Port->Designation = 0; - - // ------------------------------------------ - // Set Port Information - - RDF_Port->Name = strdup(Lilv::Node(Port.get_name()).as_string()); - RDF_Port->Symbol = strdup(Lilv::Node(Port.get_symbol()).as_string()); - - // ------------------------------------------ - // Set Port MIDI Map - - RDF_Port->MidiMap.Type = 0x0; - RDF_Port->MidiMap.Number = 0; - -#if 0 - Lilv::Nodes midi_maps = Port.get_value(Lv2World.mm_default_controller); - - if (midi_maps.size() > 0) - { - qDebug("-------------------- has midi map"); - - Lilv::Node midi_map_node(lilv_nodes_get(midi_maps, midi_maps.begin())); - - midi_maps = Port.get_value(midi_map_node); - -// LILV_FOREACH(nodes, j, midi_maps) -// { -// Lilv::Node Node = Lilv::Node(lilv_nodes_get(midi_maps, j)); - -// if (Node.is_string()) -// qDebug("-------------------- has midi map -> S %s", Node.as_string()); -// else if (Node.is_int()) -// qDebug("-------------------- has midi map -> I %i", Node.as_int()); -// else if (Node.is_literal()) -// qDebug("-------------------- has midi map -> L"); -// else -// qDebug("-------------------- has midi map (Unknown)"); -// } - - //Lilv::Node midi_map_node(lilv_nodes_get(midi_maps, midi_maps.begin())); - - //Lilv::Nodes midi_map_nodes = Port.get_value(midi_map_node); - //if (midi_map_nodes.size() > 0) - // qDebug("-------------------- has midi map + control type"); - - //if (Lilv::Nodes(Port.get_value(Lv2World.mm_controller_type)).size() > 0) - //{ - - //} - } -#endif - - // ------------------------------------------ - // Set Port Points - - RDF_Port->Points.Hints = 0x0; - RDF_Port->Points.Default = 0.0f; - RDF_Port->Points.Minimum = 0.0f; - RDF_Port->Points.Maximum = 1.0f; - - Lilv::Nodes value = Port.get_value(Lv2World.value_default); - - if (value.size() > 0) - { - RDF_Port->Points.Hints |= LV2_PORT_POINT_DEFAULT; - RDF_Port->Points.Default = Lilv::Node(lilv_nodes_get(value, value.begin())).as_float(); - } - - value = Port.get_value(Lv2World.value_minimum); - - if (value.size() > 0) - { - RDF_Port->Points.Hints |= LV2_PORT_POINT_MINIMUM; - RDF_Port->Points.Minimum = Lilv::Node(lilv_nodes_get(value, value.begin())).as_float(); - } - - value = Port.get_value(Lv2World.value_maximum); - - if (value.size() > 0) - { - RDF_Port->Points.Hints |= LV2_PORT_POINT_MAXIMUM; - RDF_Port->Points.Maximum = Lilv::Node(lilv_nodes_get(value, value.begin())).as_float(); - } - - // ------------------------------------------ - // Set Port Unit - - RDF_Port->Unit.Type = 0x0; - RDF_Port->Unit.Hints = 0x0; - - Lilv::Nodes unit_units = Port.get_value(Lv2World.unit_unit); - - if (unit_units.size() > 0) - { - RDF_Port->Unit.Hints |= LV2_PORT_UNIT; - - if (unit_units.contains(Lv2World.unit_bar)) - RDF_Port->Unit.Type = LV2_UNIT_BAR; - else if (unit_units.contains(Lv2World.unit_beat)) - RDF_Port->Unit.Type = LV2_UNIT_BEAT; - else if (unit_units.contains(Lv2World.unit_bpm)) - RDF_Port->Unit.Type = LV2_UNIT_BPM; - else if (unit_units.contains(Lv2World.unit_cent)) - RDF_Port->Unit.Type = LV2_UNIT_CENT; - else if (unit_units.contains(Lv2World.unit_cm)) - RDF_Port->Unit.Type = LV2_UNIT_CM; - else if (unit_units.contains(Lv2World.unit_coef)) - RDF_Port->Unit.Type = LV2_UNIT_COEF; - else if (unit_units.contains(Lv2World.unit_db)) - RDF_Port->Unit.Type = LV2_UNIT_DB; - else if (unit_units.contains(Lv2World.unit_degree)) - RDF_Port->Unit.Type = LV2_UNIT_DEGREE; - else if (unit_units.contains(Lv2World.unit_frame)) - RDF_Port->Unit.Type = LV2_UNIT_FRAME; - else if (unit_units.contains(Lv2World.unit_hz)) - RDF_Port->Unit.Type = LV2_UNIT_HZ; - else if (unit_units.contains(Lv2World.unit_inch)) - RDF_Port->Unit.Type = LV2_UNIT_INCH; - else if (unit_units.contains(Lv2World.unit_khz)) - RDF_Port->Unit.Type = LV2_UNIT_KHZ; - else if (unit_units.contains(Lv2World.unit_km)) - RDF_Port->Unit.Type = LV2_UNIT_KM; - else if (unit_units.contains(Lv2World.unit_m)) - RDF_Port->Unit.Type = LV2_UNIT_M; - else if (unit_units.contains(Lv2World.unit_mhz)) - RDF_Port->Unit.Type = LV2_UNIT_MHZ; - else if (unit_units.contains(Lv2World.unit_midi_note)) - RDF_Port->Unit.Type = LV2_UNIT_MIDINOTE; - else if (unit_units.contains(Lv2World.unit_mile)) - RDF_Port->Unit.Type = LV2_UNIT_MILE; - else if (unit_units.contains(Lv2World.unit_min)) - RDF_Port->Unit.Type = LV2_UNIT_MIN; - else if (unit_units.contains(Lv2World.unit_mm)) - RDF_Port->Unit.Type = LV2_UNIT_MM; - else if (unit_units.contains(Lv2World.unit_ms)) - RDF_Port->Unit.Type = LV2_UNIT_MS; - else if (unit_units.contains(Lv2World.unit_oct)) - RDF_Port->Unit.Type = LV2_UNIT_OCT; - else if (unit_units.contains(Lv2World.unit_pc)) - RDF_Port->Unit.Type = LV2_UNIT_PC; - else if (unit_units.contains(Lv2World.unit_s)) - RDF_Port->Unit.Type = LV2_UNIT_S; - else if (unit_units.contains(Lv2World.unit_semitone)) - RDF_Port->Unit.Type = LV2_UNIT_SEMITONE; - } - - Lilv::Nodes unit_name = Port.get_value(Lv2World.unit_name); - Lilv::Nodes unit_render = Port.get_value(Lv2World.unit_render); - Lilv::Nodes unit_symbol = Port.get_value(Lv2World.unit_symbol); - - if (unit_name.size() > 0) - { - RDF_Port->Unit.Hints |= LV2_PORT_UNIT_NAME; - RDF_Port->Unit.Name = strdup(Lilv::Node(lilv_nodes_get(unit_name, unit_name.begin())).as_string()); - } - else - RDF_Port->Unit.Name = nullptr; - - if (unit_render.size() > 0) - { - RDF_Port->Unit.Hints |= LV2_PORT_UNIT_RENDER; - RDF_Port->Unit.Render = strdup(Lilv::Node(lilv_nodes_get(unit_render, unit_render.begin())).as_string()); - } - else - RDF_Port->Unit.Render = nullptr; - - if (unit_symbol.size() > 0) - { - RDF_Port->Unit.Hints |= LV2_PORT_UNIT_SYMBOL; - RDF_Port->Unit.Symbol = strdup(Lilv::Node(lilv_nodes_get(unit_symbol, unit_symbol.begin())).as_string()); - } - else - RDF_Port->Unit.Symbol = nullptr; - - // ------------------------------------------ - // Set Port Scale Points - - Lilv::ScalePoints scalepoints = Port.get_scale_points(); - - RDF_Port->ScalePointCount = scalepoints.size(); - - if (RDF_Port->ScalePointCount > 0) - { - RDF_Port->ScalePoints = new LV2_RDF_PortScalePoint [RDF_Port->ScalePointCount]; - - uint32_t h = 0; - LILV_FOREACH(scale_points, j, scalepoints) - { - Lilv::ScalePoint ScalePoint = lilv_scale_points_get(scalepoints, j); - - LV2_RDF_PortScalePoint* RDF_ScalePoint = &RDF_Port->ScalePoints[h++]; - RDF_ScalePoint->Label = strdup(Lilv::Node(ScalePoint.get_label()).as_string()); - RDF_ScalePoint->Value = Lilv::Node(ScalePoint.get_value()).as_float(); - } - } - else - RDF_Port->ScalePoints = nullptr; - } - - // Set Latency port - if (Plugin.has_latency()) - { - unsigned int index = Plugin.get_latency_port_index(); - if (index < rdf_descriptor->PortCount) - rdf_descriptor->Ports[index].Designation = LV2_PORT_LATENCY; - } - } - else - rdf_descriptor->Ports = nullptr; - - // -------------------------------------------------- - // Set Plugin Presets - - rdf_descriptor->PresetCount = 0; - - // -------------------------------------------------- - // Set Plugin Features - - Lilv::Nodes features = Plugin.get_supported_features(); - Lilv::Nodes featuresR = Plugin.get_required_features(); - - rdf_descriptor->FeatureCount = features.size(); - - if (rdf_descriptor->FeatureCount > 0) - { - rdf_descriptor->Features = new LV2_RDF_Feature [rdf_descriptor->FeatureCount]; - - uint32_t h = 0; - LILV_FOREACH(nodes, j, features) - { - Lilv::Node Node = Lilv::Node(lilv_nodes_get(features, j)); - - LV2_RDF_Feature* RDF_Feature = &rdf_descriptor->Features[h++]; - RDF_Feature->Type = featuresR.contains(Node) ? LV2_FEATURE_REQUIRED : LV2_FEATURE_OPTIONAL; - RDF_Feature->URI = strdup(Node.as_uri()); - } - } - else - rdf_descriptor->Features = nullptr; - - // -------------------------------------------------- - // Set Plugin Extensions - - Lilv::Nodes extensions = Plugin.get_value(Lv2World.extension_data); - - rdf_descriptor->ExtensionCount = extensions.size(); - - if (rdf_descriptor->ExtensionCount > 0) - { - rdf_descriptor->Extensions = new LV2_URI [rdf_descriptor->ExtensionCount]; - - uint32_t h = 0; - LILV_FOREACH(nodes, j, extensions) - { - Lilv::Node Node = Lilv::Node(lilv_nodes_get(extensions, j)); - - rdf_descriptor->Extensions[h++] = strdup(Node.as_uri()); - } - } - else - rdf_descriptor->Extensions = nullptr; - - // -------------------------------------------------- - // Set Plugin UIs - - Lilv::UIs uis = Plugin.get_uis(); - - rdf_descriptor->UICount = uis.size(); - - if (rdf_descriptor->UICount > 0) - { - rdf_descriptor->UIs = new LV2_RDF_UI [rdf_descriptor->UICount]; - - uint32_t h = 0; - LILV_FOREACH(uis, j, uis) - { - Lilv::UI UI = lilv_uis_get(uis, j); - - LV2_RDF_UI* RDF_UI = &rdf_descriptor->UIs[h++]; - - // ------------------------------------------ - // Set UI Type - - if (UI.is_a(Lv2World.ui_gtk2)) - RDF_UI->Type = LV2_UI_GTK2; - else if (UI.is_a(Lv2World.ui_qt4)) - RDF_UI->Type = LV2_UI_QT4; - else if (UI.is_a(Lv2World.ui_x11)) - RDF_UI->Type = LV2_UI_X11; - else if (UI.is_a(Lv2World.ui_external)) - RDF_UI->Type = LV2_UI_EXTERNAL; - else if (UI.is_a(Lv2World.ui_external_old)) - RDF_UI->Type = LV2_UI_OLD_EXTERNAL; - else - RDF_UI->Type = 0; - - // ------------------------------------------ - // Set UI Information - - RDF_UI->URI = strdup(UI.get_uri().as_uri()); - RDF_UI->Binary = strdup(lilv_uri_to_path(UI.get_binary_uri().as_string())); - RDF_UI->Bundle = strdup(lilv_uri_to_path(UI.get_bundle_uri().as_string())); - - // TODO - RDF_UI->FeatureCount = 0; - RDF_UI->ExtensionCount = 0; - } - } - else - rdf_descriptor->UIs = nullptr; - - break; - } - } + rdf_descriptor = lv2_rdf_new(URI); if (rdf_descriptor) { @@ -3080,7 +2404,7 @@ public: gui.resizable = is_ui_resizable(); ui.handle = ui.descriptor->instantiate(ui.descriptor, descriptor->URI, ui.rdf_descriptor->Bundle, carla_lv2_ui_write_function, this, &ui.widget, features); - update_ui_ports(); + update_ui(); break; @@ -3137,6 +2461,8 @@ public: m_hints |= PLUGIN_HAS_GUI; #endif + qDebug("-------------------------------------------- %p", programs.ui); + return true; } else @@ -3508,7 +2834,7 @@ public: private: LV2_Handle handle; const LV2_Descriptor* descriptor; - LV2_RDF_Descriptor* rdf_descriptor; + const LV2_RDF_Descriptor* rdf_descriptor; LV2_Feature* features[lv2_feature_count+1]; struct { @@ -3519,6 +2845,11 @@ private: const LV2_RDF_UI* rdf_descriptor; } ui; + struct { + LV2_Programs_Plugin_Extension* plugin; + LV2_Programs_UI_Extension* ui; + } programs; + struct { GuiType type; bool visible; @@ -3535,6 +2866,11 @@ private: QList custom_uri_ids; }; +void lv2_load_all() +{ + Lv2World.load_all(); +} + short add_plugin_lv2(const char* filename, const char* label) { qDebug("add_plugin_lv2(%s, %s)", filename, label); diff --git a/src/carla/lv2_rdf.h b/src/carla/lv2_rdf.h index aba8ec4..215b393 100644 --- a/src/carla/lv2_rdf.h +++ b/src/carla/lv2_rdf.h @@ -388,6 +388,965 @@ struct LV2_RDF_Descriptor { LV2_RDF_UI* UIs; }; +// ------------------------------------------------------------------------------------------------ + +#include "lilv/lilvmm.hpp" + +#include +#include + +#define NS_dct "http://purl.org/dc/terms/" +#define NS_doap "http://usefulinc.com/ns/doap#" +#define NS_rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#" +#define NS_rdfs "http://www.w3.org/2000/01/rdf-schema#" +#define NS_llmm "http://ll-plugins.nongnu.org/lv2/ext/midimap#" + +#define LV2_MIDI_LL__MidiPort "http://ll-plugins.nongnu.org/lv2/ext/MidiPort" + +class Lv2WorldClass : public Lilv::World +{ +public: + Lv2WorldClass() : Lilv::World(), + port (new_uri(LV2_CORE__port)), + symbol (new_uri(LV2_CORE__symbol)), + class_allpass (new_uri(LV2_CORE__AllpassPlugin)), + class_amplifier (new_uri(LV2_CORE__AmplifierPlugin)), + class_analyzer (new_uri(LV2_CORE__AnalyserPlugin)), + class_bandpass (new_uri(LV2_CORE__BandpassPlugin)), + class_chorus (new_uri(LV2_CORE__ChorusPlugin)), + class_comb (new_uri(LV2_CORE__CombPlugin)), + class_compressor (new_uri(LV2_CORE__CompressorPlugin)), + class_constant (new_uri(LV2_CORE__ConstantPlugin)), + class_converter (new_uri(LV2_CORE__ConverterPlugin)), + class_delay (new_uri(LV2_CORE__DelayPlugin)), + class_distortion (new_uri(LV2_CORE__DistortionPlugin)), + class_dynamics (new_uri(LV2_CORE__DynamicsPlugin)), + class_eq (new_uri(LV2_CORE__EQPlugin)), + class_expander (new_uri(LV2_CORE__ExpanderPlugin)), + class_filter (new_uri(LV2_CORE__FilterPlugin)), + class_flanger (new_uri(LV2_CORE__FlangerPlugin)), + class_function (new_uri(LV2_CORE__FunctionPlugin)), + class_gate (new_uri(LV2_CORE__GatePlugin)), + class_generator (new_uri(LV2_CORE__GeneratorPlugin)), + class_highpass (new_uri(LV2_CORE__HighpassPlugin)), + class_instrument (new_uri(LV2_CORE__InstrumentPlugin)), + class_limiter (new_uri(LV2_CORE__LimiterPlugin)), + class_lowpass (new_uri(LV2_CORE__LowpassPlugin)), + class_mixer (new_uri(LV2_CORE__MixerPlugin)), + class_modulator (new_uri(LV2_CORE__ModulatorPlugin)), + class_multi_eq (new_uri(LV2_CORE__MultiEQPlugin)), + class_oscillator (new_uri(LV2_CORE__OscillatorPlugin)), + class_para_eq (new_uri(LV2_CORE__ParaEQPlugin)), + class_phaser (new_uri(LV2_CORE__PhaserPlugin)), + class_pitch (new_uri(LV2_CORE__PitchPlugin)), + class_reverb (new_uri(LV2_CORE__ReverbPlugin)), + class_simulator (new_uri(LV2_CORE__SimulatorPlugin)), + class_spatial (new_uri(LV2_CORE__SpatialPlugin)), + class_spectral (new_uri(LV2_CORE__SpectralPlugin)), + class_utility (new_uri(LV2_CORE__UtilityPlugin)), + class_waveshaper (new_uri(LV2_CORE__WaveshaperPlugin)), + + port_input (new_uri(LV2_CORE__InputPort)), + port_output (new_uri(LV2_CORE__OutputPort)), + port_control (new_uri(LV2_CORE__ControlPort)), + port_audio (new_uri(LV2_CORE__AudioPort)), + port_cv (new_uri(LV2_CORE__CVPort)), + port_atom (new_uri(LV2_ATOM__AtomPort)), + port_event (new_uri(LV2_EVENT__EventPort)), + port_midi_ll (new_uri(LV2_MIDI_LL__MidiPort)), + + pprop_optional (new_uri(LV2_CORE__connectionOptional)), + pprop_enumeration (new_uri(LV2_CORE__enumeration)), + pprop_integer (new_uri(LV2_CORE__integer)), + pprop_sample_rate (new_uri(LV2_CORE__sampleRate)), + pprop_toggled (new_uri(LV2_CORE__toggled)), + pprop_artifacts (new_uri(LV2_PORT_PROPS__causesArtifacts)), + pprop_continuous_cv (new_uri(LV2_PORT_PROPS__continuousCV)), + pprop_discrete_cv (new_uri(LV2_PORT_PROPS__discreteCV)), + pprop_expensive (new_uri(LV2_PORT_PROPS__expensive)), + pprop_strict_bounds (new_uri(LV2_PORT_PROPS__hasStrictBounds)), + pprop_logarithmic (new_uri(LV2_PORT_PROPS__logarithmic)), + pprop_not_automatic (new_uri(LV2_PORT_PROPS__notAutomatic)), + pprop_not_on_gui (new_uri(LV2_PORT_PROPS__notOnGUI)), + pprop_trigger (new_uri(LV2_PORT_PROPS__trigger)), + + unit_unit (new_uri(LV2_UNITS__unit)), + unit_name (new_uri(LV2_UNITS__name)), + unit_render (new_uri(LV2_UNITS__render)), + unit_symbol (new_uri(LV2_UNITS__symbol)), + + unit_bar (new_uri(LV2_UNITS__bar)), + unit_beat (new_uri(LV2_UNITS__beat)), + unit_bpm (new_uri(LV2_UNITS__bpm)), + unit_cent (new_uri(LV2_UNITS__cent)), + unit_cm (new_uri(LV2_UNITS__cm)), + unit_coef (new_uri(LV2_UNITS__coef)), + unit_db (new_uri(LV2_UNITS__db)), + unit_degree (new_uri(LV2_UNITS__degree)), + unit_frame (new_uri(LV2_UNITS__frame)), + unit_hz (new_uri(LV2_UNITS__hz)), + unit_inch (new_uri(LV2_UNITS__inch)), + unit_khz (new_uri(LV2_UNITS__khz)), + unit_km (new_uri(LV2_UNITS__km)), + unit_m (new_uri(LV2_UNITS__m)), + unit_mhz (new_uri(LV2_UNITS__mhz)), + unit_midi_note (new_uri(LV2_UNITS__midiNote)), + unit_mile (new_uri(LV2_UNITS__mile)), + unit_min (new_uri(LV2_UNITS__min)), + unit_mm (new_uri(LV2_UNITS__mm)), + unit_ms (new_uri(LV2_UNITS__ms)), + unit_oct (new_uri(LV2_UNITS__oct)), + unit_pc (new_uri(LV2_UNITS__pc)), + unit_s (new_uri(LV2_UNITS__s)), + unit_semitone (new_uri(LV2_UNITS__semitone12TET)), + + ui_gtk2 (new_uri(LV2_UI__GtkUI)), + ui_qt4 (new_uri(LV2_UI__Qt4UI)), + ui_x11 (new_uri(LV2_UI__X11UI)), + ui_external (new_uri(LV2_EXTERNAL_UI_URI)), + ui_external_old (new_uri(LV2_EXTERNAL_UI_DEPRECATED_URI)), + + preset_preset (new_uri(LV2_PRESETS__Preset)), + preset_value (new_uri(LV2_PRESETS__value)), + + value_default (new_uri(LV2_CORE__default)), + value_minimum (new_uri(LV2_CORE__minimum)), + value_maximum (new_uri(LV2_CORE__maximum)), + + atom_sequence (new_uri(LV2_ATOM__Sequence)), + atom_buffer_type (new_uri(LV2_ATOM__bufferType)), + atom_supports (new_uri(LV2_ATOM__supports)), + + midi_event (new_uri(LV2_MIDI__MidiEvent)), + + time_position (new_uri(LV2_TIME__Position)), + + mm_default_controller (new_uri(NS_llmm "defaultMidiController")), + mm_controller_type (new_uri(NS_llmm "controllerType")), + mm_controller_number (new_uri(NS_llmm "controllerNumber")), + + dct_replaces (new_uri(NS_dct "replaces")), + doap_license (new_uri(NS_doap "license")), + rdf_type (new_uri(NS_rdf "type")), + rdfs_label (new_uri(NS_rdfs "label")) + {} + + // Base Types + Lilv::Node port; + Lilv::Node symbol; + + // Plugin Types + Lilv::Node class_allpass; + Lilv::Node class_amplifier; + Lilv::Node class_analyzer; + Lilv::Node class_bandpass; + Lilv::Node class_chorus; + Lilv::Node class_comb; + Lilv::Node class_compressor; + Lilv::Node class_constant; + Lilv::Node class_converter; + Lilv::Node class_delay; + Lilv::Node class_distortion; + Lilv::Node class_dynamics; + Lilv::Node class_eq; + Lilv::Node class_expander; + Lilv::Node class_filter; + Lilv::Node class_flanger; + Lilv::Node class_function; + Lilv::Node class_gate; + Lilv::Node class_generator; + Lilv::Node class_highpass; + Lilv::Node class_instrument; + Lilv::Node class_limiter; + Lilv::Node class_lowpass; + Lilv::Node class_mixer; + Lilv::Node class_modulator; + Lilv::Node class_multi_eq; + Lilv::Node class_oscillator; + Lilv::Node class_para_eq; + Lilv::Node class_phaser; + Lilv::Node class_pitch; + Lilv::Node class_reverb; + Lilv::Node class_simulator; + Lilv::Node class_spatial; + Lilv::Node class_spectral; + Lilv::Node class_utility; + Lilv::Node class_waveshaper; + + // Port Types + Lilv::Node port_input; + Lilv::Node port_output; + Lilv::Node port_control; + Lilv::Node port_audio; + Lilv::Node port_cv; + Lilv::Node port_atom; + Lilv::Node port_event; + Lilv::Node port_midi_ll; + + // Port Properties + Lilv::Node pprop_optional; + Lilv::Node pprop_enumeration; + Lilv::Node pprop_integer; + Lilv::Node pprop_sample_rate; + Lilv::Node pprop_toggled; + Lilv::Node pprop_artifacts; + Lilv::Node pprop_continuous_cv; + Lilv::Node pprop_discrete_cv; + Lilv::Node pprop_expensive; + Lilv::Node pprop_strict_bounds; + Lilv::Node pprop_logarithmic; + Lilv::Node pprop_not_automatic; + Lilv::Node pprop_not_on_gui; + Lilv::Node pprop_trigger; + + // Port Unit + Lilv::Node unit_unit; + Lilv::Node unit_name; + Lilv::Node unit_render; + Lilv::Node unit_symbol; + + // Unit Types + Lilv::Node unit_bar; + Lilv::Node unit_beat; + Lilv::Node unit_bpm; + Lilv::Node unit_cent; + Lilv::Node unit_cm; + Lilv::Node unit_coef; + Lilv::Node unit_db; + Lilv::Node unit_degree; + Lilv::Node unit_frame; + Lilv::Node unit_hz; + Lilv::Node unit_inch; + Lilv::Node unit_khz; + Lilv::Node unit_km; + Lilv::Node unit_m; + Lilv::Node unit_mhz; + Lilv::Node unit_midi_note; + Lilv::Node unit_mile; + Lilv::Node unit_min; + Lilv::Node unit_mm; + Lilv::Node unit_ms; + Lilv::Node unit_oct; + Lilv::Node unit_pc; + Lilv::Node unit_s; + Lilv::Node unit_semitone; + + // UI Types + Lilv::Node ui_gtk2; + Lilv::Node ui_qt4; + Lilv::Node ui_x11; + Lilv::Node ui_external; + Lilv::Node ui_external_old; + + Lilv::Node preset_preset; + Lilv::Node preset_value; + + // LV2 stuff + Lilv::Node value_default; + Lilv::Node value_minimum; + Lilv::Node value_maximum; + + Lilv::Node atom_sequence; + Lilv::Node atom_buffer_type; + Lilv::Node atom_supports; + + Lilv::Node midi_event; + + Lilv::Node time_position; + + Lilv::Node mm_default_controller; + Lilv::Node mm_controller_type; + Lilv::Node mm_controller_number; + + // Other + Lilv::Node dct_replaces; + Lilv::Node doap_license; + Lilv::Node rdf_type; + Lilv::Node rdfs_label; +}; + +static Lv2WorldClass Lv2World; + +// ------------------------------------------------------------------------------------------------ + +// Create new RDF object +inline const LV2_RDF_Descriptor* lv2_rdf_new(const char* URI) +{ + const Lilv::Plugins Plugins = Lv2World.get_all_plugins(); + + LILV_FOREACH(plugins, i, Plugins) + { + Lilv::Plugin Plugin = Lilv::Plugin(lilv_plugins_get(Plugins, i)); + + if (strcmp(Plugin.get_uri().as_string(), URI) == 0) + { + LV2_RDF_Descriptor* rdf_descriptor = new LV2_RDF_Descriptor; + + // -------------------------------------------------- + // Set Plugin Type + + rdf_descriptor->Type = 0x0; + + Lilv::Nodes types(Plugin.get_value(Lv2World.rdf_type)); + + if (types.contains(Lv2World.class_allpass)) + rdf_descriptor->Type |= LV2_CLASS_ALLPASS; + if (types.contains(Lv2World.class_amplifier)) + rdf_descriptor->Type |= LV2_CLASS_AMPLIFIER; + if (types.contains(Lv2World.class_analyzer)) + rdf_descriptor->Type |= LV2_CLASS_ANALYSER; + if (types.contains(Lv2World.class_bandpass)) + rdf_descriptor->Type |= LV2_CLASS_BANDPASS; + if (types.contains(Lv2World.class_chorus)) + rdf_descriptor->Type |= LV2_CLASS_CHORUS; + if (types.contains(Lv2World.class_comb)) + rdf_descriptor->Type |= LV2_CLASS_COMB; + if (types.contains(Lv2World.class_compressor)) + rdf_descriptor->Type |= LV2_CLASS_COMPRESSOR; + if (types.contains(Lv2World.class_constant)) + rdf_descriptor->Type |= LV2_CLASS_CONSTANT; + if (types.contains(Lv2World.class_converter)) + rdf_descriptor->Type |= LV2_CLASS_CONVERTER; + if (types.contains(Lv2World.class_delay)) + rdf_descriptor->Type |= LV2_CLASS_DELAY; + if (types.contains(Lv2World.class_distortion)) + rdf_descriptor->Type |= LV2_CLASS_DISTORTION; + if (types.contains(Lv2World.class_dynamics)) + rdf_descriptor->Type |= LV2_CLASS_DYNAMICS; + if (types.contains(Lv2World.class_eq)) + rdf_descriptor->Type |= LV2_CLASS_EQ; + if (types.contains(Lv2World.class_expander)) + rdf_descriptor->Type |= LV2_CLASS_EXPANDER; + if (types.contains(Lv2World.class_filter)) + rdf_descriptor->Type |= LV2_CLASS_FILTER; + if (types.contains(Lv2World.class_flanger)) + rdf_descriptor->Type |= LV2_CLASS_FLANGER; + if (types.contains(Lv2World.class_function)) + rdf_descriptor->Type |= LV2_CLASS_FUNCTION; + if (types.contains(Lv2World.class_gate)) + rdf_descriptor->Type |= LV2_CLASS_GATE; + if (types.contains(Lv2World.class_generator)) + rdf_descriptor->Type |= LV2_CLASS_GENERATOR; + if (types.contains(Lv2World.class_highpass)) + rdf_descriptor->Type |= LV2_CLASS_HIGHPASS; + if (types.contains(Lv2World.class_instrument)) + rdf_descriptor->Type |= LV2_CLASS_INSTRUMENT; + if (types.contains(Lv2World.class_limiter)) + rdf_descriptor->Type |= LV2_CLASS_LIMITER; + if (types.contains(Lv2World.class_lowpass)) + rdf_descriptor->Type |= LV2_CLASS_LOWPASS; + if (types.contains(Lv2World.class_mixer)) + rdf_descriptor->Type |= LV2_CLASS_MIXER; + if (types.contains(Lv2World.class_modulator)) + rdf_descriptor->Type |= LV2_CLASS_MODULATOR; + if (types.contains(Lv2World.class_multi_eq)) + rdf_descriptor->Type |= LV2_CLASS_MULTI_EQ; + if (types.contains(Lv2World.class_oscillator)) + rdf_descriptor->Type |= LV2_CLASS_OSCILLATOR; + if (types.contains(Lv2World.class_para_eq)) + rdf_descriptor->Type |= LV2_CLASS_PARA_EQ; + if (types.contains(Lv2World.class_phaser)) + rdf_descriptor->Type |= LV2_CLASS_PHASER; + if (types.contains(Lv2World.class_pitch)) + rdf_descriptor->Type |= LV2_CLASS_PITCH; + if (types.contains(Lv2World.class_reverb)) + rdf_descriptor->Type |= LV2_CLASS_REVERB; + if (types.contains(Lv2World.class_simulator)) + rdf_descriptor->Type |= LV2_CLASS_SIMULATOR; + if (types.contains(Lv2World.class_spatial)) + rdf_descriptor->Type |= LV2_CLASS_SPATIAL; + if (types.contains(Lv2World.class_spectral)) + rdf_descriptor->Type |= LV2_CLASS_SPECTRAL; + if (types.contains(Lv2World.class_utility)) + rdf_descriptor->Type |= LV2_CLASS_UTILITY; + if (types.contains(Lv2World.class_waveshaper)) + rdf_descriptor->Type |= LV2_CLASS_WAVESHAPER; + + // -------------------------------------------------- + // Set Plugin Information + + rdf_descriptor->URI = strdup(URI); + rdf_descriptor->Binary = strdup(lilv_uri_to_path(Plugin.get_library_uri().as_string())); + rdf_descriptor->Bundle = strdup(lilv_uri_to_path(Plugin.get_bundle_uri().as_string())); + + if (Plugin.get_name()) + rdf_descriptor->Name = strdup(Plugin.get_name().as_string()); + else + rdf_descriptor->Name = nullptr; + + if (Plugin.get_author_name()) + rdf_descriptor->Author = strdup(Plugin.get_author_name().as_string()); + else + rdf_descriptor->Author = nullptr; + + Lilv::Nodes license = Plugin.get_value(Lv2World.doap_license); + + if (license.size() > 0) + rdf_descriptor->License = strdup(Lilv::Node(lilv_nodes_get(license, license.begin())).as_string()); + else + rdf_descriptor->License = nullptr; + + // -------------------------------------------------- + // Set Plugin UniqueID + + rdf_descriptor->UniqueID = 0; + + Lilv::Nodes replaces = Plugin.get_value(Lv2World.dct_replaces); + + if (replaces.size() > 0) + { + Lilv::Node replace_value(lilv_nodes_get(replaces, replaces.begin())); + + if (replace_value.is_uri()) + { + QString replace_uri(replace_value.as_uri()); + + if (replace_uri.startsWith("urn:")) + { + QString replace_id = replace_uri.split(":").last(); + + bool ok; + int uniqueId = replace_id.toInt(&ok); + + if (ok && uniqueId > 0) + rdf_descriptor->UniqueID = uniqueId; + } + } + } + + // -------------------------------------------------- + // Set Plugin Ports + + rdf_descriptor->PortCount = Plugin.get_num_ports(); + + if (rdf_descriptor->PortCount > 0) + { + rdf_descriptor->Ports = new LV2_RDF_Port [rdf_descriptor->PortCount]; + + for (uint32_t j = 0; j < rdf_descriptor->PortCount; j++) + { + Lilv::Port Port = Plugin.get_port_by_index(j); + LV2_RDF_Port* RDF_Port = &rdf_descriptor->Ports[j]; + + // ------------------------------------------ + // Set Port Type + + RDF_Port->Type = 0x0; + + if (Port.is_a(Lv2World.port_input)) + RDF_Port->Type |= LV2_PORT_INPUT; + + if (Port.is_a(Lv2World.port_output)) + RDF_Port->Type |= LV2_PORT_OUTPUT; + + if (Port.is_a(Lv2World.port_control)) + RDF_Port->Type |= LV2_PORT_CONTROL; + + if (Port.is_a(Lv2World.port_audio)) + RDF_Port->Type |= LV2_PORT_AUDIO; + + if (Port.is_a(Lv2World.port_cv)) + RDF_Port->Type |= LV2_PORT_CV; + + if (Port.is_a(Lv2World.port_atom)) + { + RDF_Port->Type |= LV2_PORT_ATOM; + + Lilv::Nodes bufferTypes(Port.get_value(Lv2World.atom_buffer_type)); + if (bufferTypes.contains(Lv2World.atom_sequence)) + RDF_Port->Type |= LV2_PORT_ATOM_SEQUENCE; + + Lilv::Nodes supports(Port.get_value(Lv2World.atom_supports)); + if (supports.contains(Lv2World.midi_event)) + RDF_Port->Type |= LV2_PORT_SUPPORTS_MIDI; + if (supports.contains(Lv2World.time_position)) + RDF_Port->Type |= LV2_PORT_SUPPORTS_TIME; + } + + if (Port.is_a(Lv2World.port_event)) + { + RDF_Port->Type |= LV2_PORT_EVENT; + + if (Port.supports_event(Lv2World.midi_event)) + RDF_Port->Type |= LV2_PORT_SUPPORTS_MIDI; + if (Port.supports_event(Lv2World.time_position)) + RDF_Port->Type |= LV2_PORT_SUPPORTS_TIME; + } + + if (Port.is_a(Lv2World.port_midi_ll)) + { + RDF_Port->Type |= LV2_PORT_MIDI_LL; + RDF_Port->Type |= LV2_PORT_SUPPORTS_MIDI; + } + + // ------------------------------------------ + // Set Port Properties + + RDF_Port->Properties = 0x0; + + if (Port.has_property(Lv2World.pprop_optional)) + RDF_Port->Properties = LV2_PORT_OPTIONAL; + if (Port.has_property(Lv2World.pprop_enumeration)) + RDF_Port->Properties = LV2_PORT_ENUMERATION; + if (Port.has_property(Lv2World.pprop_integer)) + RDF_Port->Properties = LV2_PORT_INTEGER; + if (Port.has_property(Lv2World.pprop_sample_rate)) + RDF_Port->Properties = LV2_PORT_SAMPLE_RATE; + if (Port.has_property(Lv2World.pprop_toggled)) + RDF_Port->Properties = LV2_PORT_TOGGLED; + + if (Port.has_property(Lv2World.pprop_artifacts)) + RDF_Port->Properties = LV2_PORT_CAUSES_ARTIFACTS; + if (Port.has_property(Lv2World.pprop_continuous_cv)) + RDF_Port->Properties = LV2_PORT_CONTINUOUS_CV; + if (Port.has_property(Lv2World.pprop_discrete_cv)) + RDF_Port->Properties = LV2_PORT_DISCRETE_CV; + if (Port.has_property(Lv2World.pprop_expensive)) + RDF_Port->Properties = LV2_PORT_EXPENSIVE; + if (Port.has_property(Lv2World.pprop_strict_bounds)) + RDF_Port->Properties = LV2_PORT_HAS_STRICT_BOUNDS; + if (Port.has_property(Lv2World.pprop_logarithmic)) + RDF_Port->Properties = LV2_PORT_LOGARITHMIC; + if (Port.has_property(Lv2World.pprop_not_automatic)) + RDF_Port->Properties = LV2_PORT_NOT_AUTOMATIC; + if (Port.has_property(Lv2World.pprop_not_on_gui)) + RDF_Port->Properties = LV2_PORT_NOT_ON_GUI; + if (Port.has_property(Lv2World.pprop_trigger)) + RDF_Port->Properties = LV2_PORT_TRIGGER; + + // ------------------------------------------ + // Set Port Designation + + RDF_Port->Designation = 0; + + // ------------------------------------------ + // Set Port Information + + RDF_Port->Name = strdup(Lilv::Node(Port.get_name()).as_string()); + RDF_Port->Symbol = strdup(Lilv::Node(Port.get_symbol()).as_string()); + + // ------------------------------------------ + // Set Port MIDI Map + + RDF_Port->MidiMap.Type = 0x0; + RDF_Port->MidiMap.Number = 0; + +#if 0 + Lilv::Nodes midi_maps = Port.get_value(Lv2World.mm_default_controller); + + if (midi_maps.size() > 0) + { + qDebug("-------------------- has midi map"); + + Lilv::Node midi_map_node(lilv_nodes_get(midi_maps, midi_maps.begin())); + + midi_maps = Port.get_value(midi_map_node); + + // LILV_FOREACH(nodes, j, midi_maps) + // { + // Lilv::Node Node = Lilv::Node(lilv_nodes_get(midi_maps, j)); + + // if (Node.is_string()) + // qDebug("-------------------- has midi map -> S %s", Node.as_string()); + // else if (Node.is_int()) + // qDebug("-------------------- has midi map -> I %i", Node.as_int()); + // else if (Node.is_literal()) + // qDebug("-------------------- has midi map -> L"); + // else + // qDebug("-------------------- has midi map (Unknown)"); + // } + + //Lilv::Node midi_map_node(lilv_nodes_get(midi_maps, midi_maps.begin())); + + //Lilv::Nodes midi_map_nodes = Port.get_value(midi_map_node); + //if (midi_map_nodes.size() > 0) + // qDebug("-------------------- has midi map + control type"); + + //if (Lilv::Nodes(Port.get_value(Lv2World.mm_controller_type)).size() > 0) + //{ + + //} + } +#endif + + // ------------------------------------------ + // Set Port Points + + RDF_Port->Points.Hints = 0x0; + RDF_Port->Points.Default = 0.0f; + RDF_Port->Points.Minimum = 0.0f; + RDF_Port->Points.Maximum = 1.0f; + + Lilv::Nodes value = Port.get_value(Lv2World.value_default); + + if (value.size() > 0) + { + RDF_Port->Points.Hints |= LV2_PORT_POINT_DEFAULT; + RDF_Port->Points.Default = Lilv::Node(lilv_nodes_get(value, value.begin())).as_float(); + } + + value = Port.get_value(Lv2World.value_minimum); + + if (value.size() > 0) + { + RDF_Port->Points.Hints |= LV2_PORT_POINT_MINIMUM; + RDF_Port->Points.Minimum = Lilv::Node(lilv_nodes_get(value, value.begin())).as_float(); + } + + value = Port.get_value(Lv2World.value_maximum); + + if (value.size() > 0) + { + RDF_Port->Points.Hints |= LV2_PORT_POINT_MAXIMUM; + RDF_Port->Points.Maximum = Lilv::Node(lilv_nodes_get(value, value.begin())).as_float(); + } + + // ------------------------------------------ + // Set Port Unit + + RDF_Port->Unit.Type = 0x0; + RDF_Port->Unit.Hints = 0x0; + + Lilv::Nodes unit_units = Port.get_value(Lv2World.unit_unit); + + if (unit_units.size() > 0) + { + RDF_Port->Unit.Hints |= LV2_PORT_UNIT; + + if (unit_units.contains(Lv2World.unit_bar)) + RDF_Port->Unit.Type = LV2_UNIT_BAR; + else if (unit_units.contains(Lv2World.unit_beat)) + RDF_Port->Unit.Type = LV2_UNIT_BEAT; + else if (unit_units.contains(Lv2World.unit_bpm)) + RDF_Port->Unit.Type = LV2_UNIT_BPM; + else if (unit_units.contains(Lv2World.unit_cent)) + RDF_Port->Unit.Type = LV2_UNIT_CENT; + else if (unit_units.contains(Lv2World.unit_cm)) + RDF_Port->Unit.Type = LV2_UNIT_CM; + else if (unit_units.contains(Lv2World.unit_coef)) + RDF_Port->Unit.Type = LV2_UNIT_COEF; + else if (unit_units.contains(Lv2World.unit_db)) + RDF_Port->Unit.Type = LV2_UNIT_DB; + else if (unit_units.contains(Lv2World.unit_degree)) + RDF_Port->Unit.Type = LV2_UNIT_DEGREE; + else if (unit_units.contains(Lv2World.unit_frame)) + RDF_Port->Unit.Type = LV2_UNIT_FRAME; + else if (unit_units.contains(Lv2World.unit_hz)) + RDF_Port->Unit.Type = LV2_UNIT_HZ; + else if (unit_units.contains(Lv2World.unit_inch)) + RDF_Port->Unit.Type = LV2_UNIT_INCH; + else if (unit_units.contains(Lv2World.unit_khz)) + RDF_Port->Unit.Type = LV2_UNIT_KHZ; + else if (unit_units.contains(Lv2World.unit_km)) + RDF_Port->Unit.Type = LV2_UNIT_KM; + else if (unit_units.contains(Lv2World.unit_m)) + RDF_Port->Unit.Type = LV2_UNIT_M; + else if (unit_units.contains(Lv2World.unit_mhz)) + RDF_Port->Unit.Type = LV2_UNIT_MHZ; + else if (unit_units.contains(Lv2World.unit_midi_note)) + RDF_Port->Unit.Type = LV2_UNIT_MIDINOTE; + else if (unit_units.contains(Lv2World.unit_mile)) + RDF_Port->Unit.Type = LV2_UNIT_MILE; + else if (unit_units.contains(Lv2World.unit_min)) + RDF_Port->Unit.Type = LV2_UNIT_MIN; + else if (unit_units.contains(Lv2World.unit_mm)) + RDF_Port->Unit.Type = LV2_UNIT_MM; + else if (unit_units.contains(Lv2World.unit_ms)) + RDF_Port->Unit.Type = LV2_UNIT_MS; + else if (unit_units.contains(Lv2World.unit_oct)) + RDF_Port->Unit.Type = LV2_UNIT_OCT; + else if (unit_units.contains(Lv2World.unit_pc)) + RDF_Port->Unit.Type = LV2_UNIT_PC; + else if (unit_units.contains(Lv2World.unit_s)) + RDF_Port->Unit.Type = LV2_UNIT_S; + else if (unit_units.contains(Lv2World.unit_semitone)) + RDF_Port->Unit.Type = LV2_UNIT_SEMITONE; + } + + Lilv::Nodes unit_name = Port.get_value(Lv2World.unit_name); + Lilv::Nodes unit_render = Port.get_value(Lv2World.unit_render); + Lilv::Nodes unit_symbol = Port.get_value(Lv2World.unit_symbol); + + if (unit_name.size() > 0) + { + RDF_Port->Unit.Hints |= LV2_PORT_UNIT_NAME; + RDF_Port->Unit.Name = strdup(Lilv::Node(lilv_nodes_get(unit_name, unit_name.begin())).as_string()); + } + else + RDF_Port->Unit.Name = nullptr; + + if (unit_render.size() > 0) + { + RDF_Port->Unit.Hints |= LV2_PORT_UNIT_RENDER; + RDF_Port->Unit.Render = strdup(Lilv::Node(lilv_nodes_get(unit_render, unit_render.begin())).as_string()); + } + else + RDF_Port->Unit.Render = nullptr; + + if (unit_symbol.size() > 0) + { + RDF_Port->Unit.Hints |= LV2_PORT_UNIT_SYMBOL; + RDF_Port->Unit.Symbol = strdup(Lilv::Node(lilv_nodes_get(unit_symbol, unit_symbol.begin())).as_string()); + } + else + RDF_Port->Unit.Symbol = nullptr; + + // ------------------------------------------ + // Set Port Scale Points + + Lilv::ScalePoints scalepoints = Port.get_scale_points(); + + RDF_Port->ScalePointCount = scalepoints.size(); + + if (RDF_Port->ScalePointCount > 0) + { + RDF_Port->ScalePoints = new LV2_RDF_PortScalePoint [RDF_Port->ScalePointCount]; + + uint32_t h = 0; + LILV_FOREACH(scale_points, j, scalepoints) + { + Lilv::ScalePoint ScalePoint = lilv_scale_points_get(scalepoints, j); + + LV2_RDF_PortScalePoint* RDF_ScalePoint = &RDF_Port->ScalePoints[h++]; + RDF_ScalePoint->Label = strdup(Lilv::Node(ScalePoint.get_label()).as_string()); + RDF_ScalePoint->Value = Lilv::Node(ScalePoint.get_value()).as_float(); + } + } + else + RDF_Port->ScalePoints = nullptr; + } + + // Set Latency port + if (Plugin.has_latency()) + { + unsigned int index = Plugin.get_latency_port_index(); + if (index < rdf_descriptor->PortCount) + rdf_descriptor->Ports[index].Designation = LV2_PORT_LATENCY; + } + } + else + rdf_descriptor->Ports = nullptr; + + // -------------------------------------------------- + // Set Plugin Presets + + Lilv::Nodes Presets = Plugin.get_related(Lv2World.preset_preset); + + rdf_descriptor->PresetCount = Presets.size(); + + qDebug("-------------------- preset count %i", rdf_descriptor->PresetCount); + + if (rdf_descriptor->PresetCount > 0) + { + rdf_descriptor->Presets = new LV2_RDF_Preset [rdf_descriptor->PresetCount]; + + uint32_t h = 0; + LILV_FOREACH(nodes, j, Presets) + { + Lilv::Node Node = Lilv::Node(lilv_nodes_get(Presets, j)); + Lv2World.load_resource(Node); + + LV2_RDF_Preset* RDF_Preset = &rdf_descriptor->Presets[h++]; + + // ------------------------------------------ + // Set Preset Information + + Lilv::Nodes Label = Lv2World.find_nodes(Node, Lv2World.rdfs_label, nullptr); + + if (Node.is_uri()) + RDF_Preset->URI = strdup(Node.as_uri()); + else + RDF_Preset->URI = nullptr; + + if (Label.size() > 0) + RDF_Preset->Label = strdup(Lilv::Node(lilv_nodes_get(Label, Label.begin())).as_string()); + else + RDF_Preset->Label = nullptr; + + qDebug("-------------------- preset @%i -> %s | %s", h, RDF_Preset->URI, RDF_Preset->Label); + + // ------------------------------------------ + // Set Preset Ports + + Lilv::Nodes PresetPorts = Lv2World.find_nodes(Node, Lv2World.port, nullptr); + + RDF_Preset->PortCount = PresetPorts.size(); + + if (RDF_Preset->PortCount > 0) + { + RDF_Preset->Ports = new LV2_RDF_PresetPort[RDF_Preset->PortCount]; + + uint32_t g = 0; + LILV_FOREACH(nodes, k, PresetPorts) + { + Lilv::Node PresetPort = Lilv::Node(lilv_nodes_get(PresetPorts, k)); + + Lilv::Nodes PresetPortSymbol = Lv2World.find_nodes(PresetPort, Lv2World.symbol, nullptr); + Lilv::Nodes PresetPortValue = Lv2World.find_nodes(PresetPort, Lv2World.preset_value, nullptr); + + LV2_RDF_PresetPort* RDF_PresetPort = &RDF_Preset->Ports[g++]; + + RDF_PresetPort->Symbol = strdup(Lilv::Node(lilv_nodes_get(PresetPortSymbol, PresetPortSymbol.begin())).as_string()); + RDF_PresetPort->Value = Lilv::Node(lilv_nodes_get(PresetPortValue, PresetPortValue.begin())).as_float(); + } + } + else + RDF_Preset->Ports = nullptr; + + // ------------------------------------------ + // Set Preset States + + RDF_Preset->StateCount = 0; + } + } + else + rdf_descriptor->Presets = nullptr; + + // -------------------------------------------------- + // Set Plugin Features + + Lilv::Nodes features = Plugin.get_supported_features(); + Lilv::Nodes featuresR = Plugin.get_required_features(); + + rdf_descriptor->FeatureCount = features.size(); + + if (rdf_descriptor->FeatureCount > 0) + { + rdf_descriptor->Features = new LV2_RDF_Feature [rdf_descriptor->FeatureCount]; + + uint32_t h = 0; + LILV_FOREACH(nodes, j, features) + { + Lilv::Node Node = Lilv::Node(lilv_nodes_get(features, j)); + + LV2_RDF_Feature* RDF_Feature = &rdf_descriptor->Features[h++]; + RDF_Feature->Type = featuresR.contains(Node) ? LV2_FEATURE_REQUIRED : LV2_FEATURE_OPTIONAL; + RDF_Feature->URI = strdup(Node.as_uri()); + } + } + else + rdf_descriptor->Features = nullptr; + + // -------------------------------------------------- + // Set Plugin Extensions + + Lilv::Nodes extensions = Plugin.get_extension_data(); + + rdf_descriptor->ExtensionCount = extensions.size(); + + if (rdf_descriptor->ExtensionCount > 0) + { + rdf_descriptor->Extensions = new LV2_URI [rdf_descriptor->ExtensionCount]; + + uint32_t h = 0; + LILV_FOREACH(nodes, j, extensions) + { + Lilv::Node Node = Lilv::Node(lilv_nodes_get(extensions, j)); + + rdf_descriptor->Extensions[h++] = strdup(Node.as_uri()); + } + } + else + rdf_descriptor->Extensions = nullptr; + + // -------------------------------------------------- + // Set Plugin UIs + + Lilv::UIs uis = Plugin.get_uis(); + + rdf_descriptor->UICount = uis.size(); + + if (rdf_descriptor->UICount > 0) + { + rdf_descriptor->UIs = new LV2_RDF_UI [rdf_descriptor->UICount]; + + uint32_t h = 0; + LILV_FOREACH(uis, j, uis) + { + Lilv::UI UI = lilv_uis_get(uis, j); + + LV2_RDF_UI* RDF_UI = &rdf_descriptor->UIs[h++]; + + // ------------------------------------------ + // Set UI Type + + if (UI.is_a(Lv2World.ui_gtk2)) + RDF_UI->Type = LV2_UI_GTK2; + else if (UI.is_a(Lv2World.ui_qt4)) + RDF_UI->Type = LV2_UI_QT4; + else if (UI.is_a(Lv2World.ui_x11)) + RDF_UI->Type = LV2_UI_X11; + else if (UI.is_a(Lv2World.ui_external)) + RDF_UI->Type = LV2_UI_EXTERNAL; + else if (UI.is_a(Lv2World.ui_external_old)) + RDF_UI->Type = LV2_UI_OLD_EXTERNAL; + else + RDF_UI->Type = 0; + + // ------------------------------------------ + // Set UI Information + + RDF_UI->URI = strdup(UI.get_uri().as_uri()); + RDF_UI->Binary = strdup(lilv_uri_to_path(UI.get_binary_uri().as_string())); + RDF_UI->Bundle = strdup(lilv_uri_to_path(UI.get_bundle_uri().as_string())); + + // ------------------------------------------ + // Set UI Features + + Lilv::Nodes features = UI.get_supported_features(); + Lilv::Nodes featuresR = UI.get_required_features(); + + RDF_UI->FeatureCount = features.size(); + + if (RDF_UI->FeatureCount > 0) + { + RDF_UI->Features = new LV2_RDF_Feature [RDF_UI->FeatureCount]; + + uint32_t h = 0; + LILV_FOREACH(nodes, k, features) + { + Lilv::Node Node = Lilv::Node(lilv_nodes_get(features, k)); + + LV2_RDF_Feature* RDF_Feature = &RDF_UI->Features[h++]; + RDF_Feature->Type = featuresR.contains(Node) ? LV2_FEATURE_REQUIRED : LV2_FEATURE_OPTIONAL; + RDF_Feature->URI = strdup(Node.as_uri()); + } + } + else + RDF_UI->Features = nullptr; + + // ------------------------------------------ + // Set UI Extensions + + Lilv::Nodes extensions = UI.get_extension_data(); + + RDF_UI->ExtensionCount = extensions.size(); + + if (RDF_UI->ExtensionCount > 0) + { + RDF_UI->Extensions = new LV2_URI [RDF_UI->ExtensionCount]; + + uint32_t h = 0; + LILV_FOREACH(nodes, k, extensions) + { + Lilv::Node Node = Lilv::Node(lilv_nodes_get(extensions, k)); + + RDF_UI->Extensions[h++] = strdup(Node.as_uri()); + } + } + else + RDF_UI->Extensions = nullptr; + } + } + else + rdf_descriptor->UIs = nullptr; + + return rdf_descriptor; + } + } + + return nullptr; +} // Copy RDF object inline const LV2_RDF_Descriptor* lv2_rdf_dup(LV2_RDF_Descriptor* rdf_descriptor) @@ -621,7 +1580,7 @@ inline const LV2_RDF_Descriptor* lv2_rdf_dup(LV2_RDF_Descriptor* rdf_descriptor) return new_descriptor; } -// Delete copied object +// Delete object inline void lv2_rdf_free(const LV2_RDF_Descriptor* rdf_descriptor) { uint32_t i, j; @@ -736,6 +1695,8 @@ inline void lv2_rdf_free(const LV2_RDF_Descriptor* rdf_descriptor) delete rdf_descriptor; } +// ------------------------------------------------------------------------------------------------ + inline bool is_lv2_feature_supported(const char* uri) { if (strcmp(uri, LV2_CORE__hardRTCapable) == 0) @@ -800,12 +1761,8 @@ inline bool is_lv2_ui_feature_supported(const char* uri) return false; // TODO else if (strcmp(uri, LV2_UI__touch) == 0) return false; // TODO - //else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#Events") == 0) - //return true; else if (strcmp(uri, LV2_UI_PREFIX "makeResident") == 0) return true; - //else if (strcmp(uri, "http://lv2plug.in/ns/extensions/ui#makeSONameResident") == 0) - //return true; else if (strcmp(uri, LV2_EXTERNAL_UI_URI) == 0) return true; else if (strcmp(uri, LV2_EXTERNAL_UI_DEPRECATED_URI) == 0) @@ -833,4 +1790,4 @@ inline const char* lv2_get_ui_uri(int UiType) } } -#endif /* #ifndef LV2_RDF_INCLUDED */ +#endif /* LV2_RDF_INCLUDED */