|
20 | 20 | #include <lv2/state/state.h> |
21 | 21 | #include <lv2/units/units.h> |
22 | 22 |
|
| 23 | +#include <lv2/port-groups/port-groups.h> |
| 24 | + |
23 | 25 | // do not enable external-ui support in embed targets |
24 | 26 | #if !(defined(_MOD_DEVICE_DUO) || defined(_MOD_DEVICE_DUOX) || defined(_MOD_DEVICE_DWARF)) |
25 | 27 | #define WITH_EXTERNAL_UI_SUPPORT |
@@ -210,6 +212,7 @@ static const bool kOnlyShowPluginsWithMODGUI = getenv("MOD_UI_ONLY_SHOW_PLUGINS_ |
210 | 212 | { nullptr, nullptr } \ |
211 | 213 | }, \ |
212 | 214 | nullptr, \ |
| 215 | + nullptr, \ |
213 | 216 | nullptr \ |
214 | 217 | } |
215 | 218 |
|
@@ -295,10 +298,12 @@ inline void fill_iotype(PInfo* const info, |
295 | 298 |
|
296 | 299 | // -------------------------------------------------------------------------------------------------------- |
297 | 300 |
|
298 | | -#define LILV_NS_INGEN "http://drobilla.net/ns/ingen#" |
299 | | -#define LILV_NS_MOD "http://moddevices.com/ns/mod#" |
300 | | -#define LILV_NS_MODGUI "http://moddevices.com/ns/modgui#" |
301 | | -#define LILV_NS_MODPEDAL "http://moddevices.com/ns/modpedal#" |
| 301 | +#define LILV_NS_INGEN "http://drobilla.net/ns/ingen#" |
| 302 | +#define LILV_NS_MOD "http://moddevices.com/ns/mod#" |
| 303 | +#define LILV_NS_MODGUI "http://moddevices.com/ns/modgui#" |
| 304 | +#define LILV_NS_MODPEDAL "http://moddevices.com/ns/modpedal#" |
| 305 | + |
| 306 | +#define LV2_NS_PORT_GROUPS "http://lv2plug.in/ns/ext/port-groups#" |
302 | 307 |
|
303 | 308 | #define MOD__CVPort LILV_NS_MOD "CVPort" |
304 | 309 |
|
@@ -366,6 +371,9 @@ struct NamespaceDefinitions { |
366 | 371 | LilvNode* units_render; |
367 | 372 | LilvNode* units_symbol; |
368 | 373 | LilvNode* units_unit; |
| 374 | + LilvNode* port_groups_inputgroup; |
| 375 | + LilvNode* port_groups_outputgroup; |
| 376 | + LilvNode* port_groups_groupName; |
369 | 377 | bool initialized; |
370 | 378 |
|
371 | 379 | NamespaceDefinitions(LilvWorld* const w) |
@@ -459,6 +467,9 @@ struct NamespaceDefinitions { |
459 | 467 | units_render = lilv_new_uri(w, LV2_UNITS__render); |
460 | 468 | units_symbol = lilv_new_uri(w, LV2_UNITS__symbol); |
461 | 469 | units_unit = lilv_new_uri(w, LV2_UNITS__unit); |
| 470 | + port_groups_inputgroup = lilv_new_uri(w, LV2_PORT_GROUPS__InputGroup); |
| 471 | + port_groups_outputgroup = lilv_new_uri(w, LV2_PORT_GROUPS__OutputGroup); |
| 472 | + port_groups_groupName = lilv_new_uri(w, LV2_PORT_GROUPS__group); |
462 | 473 | } |
463 | 474 |
|
464 | 475 | void cleanup() |
@@ -530,6 +541,9 @@ struct NamespaceDefinitions { |
530 | 541 | lilv_node_free(units_render); |
531 | 542 | lilv_node_free(units_symbol); |
532 | 543 | lilv_node_free(units_unit); |
| 544 | + lilv_node_free(port_groups_inputgroup); |
| 545 | + lilv_node_free(port_groups_outputgroup); |
| 546 | + lilv_node_free(port_groups_groupName); |
533 | 547 | } |
534 | 548 |
|
535 | 549 | static NamespaceDefinitions& getStaticInstance(LilvWorld* const w) |
@@ -1963,6 +1977,58 @@ static void _fill_units(LilvWorld* const w, |
1963 | 1977 |
|
1964 | 1978 | } |
1965 | 1979 |
|
| 1980 | +const PluginPortGroup _get_port_group(LilvWorld* const w, const LilvNode* const group, const NamespaceDefinitions& ns) |
| 1981 | +{ |
| 1982 | + PluginPortGroup port_group; |
| 1983 | + |
| 1984 | + memset(&port_group, 0, sizeof(PluginPortGroup)); |
| 1985 | + if (LilvNode* const group_type = lilv_world_get(w, group, ns.rdf_type, NULL)) |
| 1986 | + { |
| 1987 | + if (lilv_node_equals(group_type, ns.port_groups_inputgroup) || lilv_node_equals(group_type, ns.port_groups_outputgroup)) |
| 1988 | + { |
| 1989 | + if (LilvNode* const group_symbol = lilv_world_get(w, group, ns.lv2core_symbol, nullptr)) |
| 1990 | + { |
| 1991 | + const char* const groupsymbol = lilv_node_as_string(group_symbol); |
| 1992 | + if (groupsymbol != nullptr && strlen(groupsymbol) > 0) |
| 1993 | + { |
| 1994 | + // get description |
| 1995 | + LilvNode* const group_name = lilv_world_get(w, group, ns.lv2core_name, nullptr); |
| 1996 | + const char* const groupname = (group_name != nullptr) ? lilv_node_as_string(group_name) : nullptr; |
| 1997 | + |
| 1998 | + // create a new port group |
| 1999 | + port_group.valid = true; |
| 2000 | + port_group.symbol = strdup(groupsymbol); |
| 2001 | + port_group.name = groupname == nullptr ? strdup(groupsymbol) : strdup(groupname); |
| 2002 | + |
| 2003 | + lilv_node_free(group_name); |
| 2004 | + } |
| 2005 | + else |
| 2006 | + { |
| 2007 | + // symbol must be defined for groups |
| 2008 | + printf("WARNING: invalid group lv2:symbol is empty\n"); |
| 2009 | + } |
| 2010 | + lilv_node_free(group_symbol); |
| 2011 | + } |
| 2012 | + else |
| 2013 | + { |
| 2014 | + printf("WARNING: invalid group no lv2:symbol defined\n"); |
| 2015 | + } |
| 2016 | + |
| 2017 | + lilv_node_free(group_type); |
| 2018 | + } |
| 2019 | + else |
| 2020 | + { |
| 2021 | + printf("WARNING: invalid group no required port type\n"); |
| 2022 | + } |
| 2023 | + } |
| 2024 | + else |
| 2025 | + { |
| 2026 | + printf("WARNING: invalid group no rdf:type defined\n"); |
| 2027 | + } |
| 2028 | + |
| 2029 | + return port_group; |
| 2030 | +} |
| 2031 | + |
1966 | 2032 | const PluginInfo& _get_plugin_info(LilvWorld* const w, |
1967 | 2033 | const LilvPlugin* const p, |
1968 | 2034 | const NamespaceDefinitions& ns) |
@@ -2611,6 +2677,7 @@ const PluginInfo& _get_plugin_info(LilvWorld* const w, |
2611 | 2677 | uint32_t countControlInput=0, countControlOutput=0; |
2612 | 2678 | uint32_t countCvInput=0, countCvOutput=0; |
2613 | 2679 | uint32_t countMidiInput=0, countMidiOutput=0; |
| 2680 | + std::map<std::string, PluginPortGroup> usedGroups; |
2614 | 2681 |
|
2615 | 2682 | // precalculate port counts first |
2616 | 2683 | for (uint32_t i=0; i<count; ++i) |
@@ -2851,6 +2918,36 @@ const PluginInfo& _get_plugin_info(LilvWorld* const w, |
2851 | 2918 | portinfo.designation = nc; |
2852 | 2919 | } |
2853 | 2920 |
|
| 2921 | + // ---------------------------------------------------------------------------------------------------- |
| 2922 | + // groups |
| 2923 | + portinfo.groupSymbol = nc; |
| 2924 | + if (LilvNode* symbolnode = lilv_port_get(p, port, ns.port_groups_groupName)) |
| 2925 | + { |
| 2926 | + const char* groupName = lilv_node_as_string(symbolnode); |
| 2927 | + if (!contains(usedGroups, groupName)) |
| 2928 | + { |
| 2929 | + const PluginPortGroup& group = _get_port_group(w, symbolnode, ns); |
| 2930 | + |
| 2931 | + if (group.valid) |
| 2932 | + { |
| 2933 | + // read the group definition |
| 2934 | + usedGroups[groupName] = group; |
| 2935 | + portinfo.groupSymbol = strdup(group.symbol); |
| 2936 | + } |
| 2937 | + else |
| 2938 | + { |
| 2939 | + printf("WARNING: Group definition not found for %s\n", groupName); |
| 2940 | + } |
| 2941 | + } |
| 2942 | + else |
| 2943 | + { |
| 2944 | + // already cached |
| 2945 | + portinfo.groupSymbol = strdup(usedGroups[groupName].symbol); |
| 2946 | + } |
| 2947 | + |
| 2948 | + lilv_free(symbolnode); |
| 2949 | + } |
| 2950 | + |
2854 | 2951 | // ---------------------------------------------------------------------------------------------------- |
2855 | 2952 | // range steps |
2856 | 2953 |
|
@@ -3063,6 +3160,22 @@ const PluginInfo& _get_plugin_info(LilvWorld* const w, |
3063 | 3160 |
|
3064 | 3161 | // also iotype |
3065 | 3162 | fill_iotype(&info, countAudioInput, countAudioOutput, countMidiInput, countMidiOutput); |
| 3163 | + |
| 3164 | + // -------------------------------------------------------------------------------------------------------- |
| 3165 | + // groups |
| 3166 | + |
| 3167 | + if (size_t countGroups = usedGroups.size()) |
| 3168 | + { |
| 3169 | + PluginPortGroup* const groups = new PluginPortGroup[countGroups+1]; |
| 3170 | + |
| 3171 | + countGroups = 0; |
| 3172 | + for (auto& group : usedGroups) |
| 3173 | + groups[countGroups++] = group.second; |
| 3174 | + |
| 3175 | + memset(&groups[countGroups], 0, sizeof(PluginPortGroup)); |
| 3176 | + |
| 3177 | + info.portGroups = groups; |
| 3178 | + } |
3066 | 3179 | } |
3067 | 3180 | else |
3068 | 3181 | { |
@@ -3413,6 +3526,8 @@ static void _clear_port_info(PluginPort& portinfo) |
3413 | 3526 | free((void*)portinfo.designation); |
3414 | 3527 | if (portinfo.shortName != nc) |
3415 | 3528 | free((void*)portinfo.shortName); |
| 3529 | + if (portinfo.groupSymbol != nc) |
| 3530 | + free((void*)portinfo.groupSymbol); |
3416 | 3531 |
|
3417 | 3532 | if (portinfo.properties != nullptr) |
3418 | 3533 | { |
@@ -3441,6 +3556,12 @@ static void _clear_port_info(PluginPort& portinfo) |
3441 | 3556 | memset(&portinfo, 0, sizeof(PluginPort)); |
3442 | 3557 | } |
3443 | 3558 |
|
| 3559 | +static void _clear_port_group_info(const PluginPortGroup& portGroup) |
| 3560 | +{ |
| 3561 | + free((void*)portGroup.symbol); |
| 3562 | + free((void*)portGroup.name); |
| 3563 | +} |
| 3564 | + |
3444 | 3565 | static void _clear_parameter_info(const PluginParameter& parameter) |
3445 | 3566 | { |
3446 | 3567 | free((void*)parameter.uri); |
@@ -3610,6 +3731,13 @@ static void _clear_plugin_info(PluginInfo& info) |
3610 | 3731 | delete[] info.ports.midi.output; |
3611 | 3732 | } |
3612 | 3733 |
|
| 3734 | + if (info.portGroups != nullptr) |
| 3735 | + { |
| 3736 | + for (int i=0; info.portGroups[i].valid; ++i) |
| 3737 | + _clear_port_group_info(info.portGroups[i]); |
| 3738 | + delete[] info.portGroups; |
| 3739 | + } |
| 3740 | + |
3613 | 3741 | if (info.parameters != nullptr) |
3614 | 3742 | { |
3615 | 3743 | for (int i=0; info.parameters[i].valid; ++i) |
|
0 commit comments