Skip to content

Commit a8d326f

Browse files
committed
Port groups
Squashed commit of the following: commit 3b2e3a0 Author: falkTX <[email protected]> Date: Sat Oct 18 13:48:38 2025 +0200 Cleanup Signed-off-by: falkTX <[email protected]> commit 2b46a5e Author: Andrea Del Signore <[email protected]> Date: Thu Oct 16 17:40:33 2025 +0200 Update python binding to cpp utils in order to support port groups commit f05f891 Author: Andrea Del Signore <[email protected]> Date: Thu Oct 16 17:34:27 2025 +0200 Add support for lv2 group extension to lilv backend Signed-off-by: falkTX <[email protected]>
1 parent 4ee3723 commit a8d326f

File tree

3 files changed

+103
-2
lines changed

3 files changed

+103
-2
lines changed

modtools/utils.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,13 @@ class PluginGUI_Mini(Structure):
221221
("thumbnail", c_char_p),
222222
]
223223

224+
class PluginPortGroup(Structure):
225+
_fields_ = [
226+
("valid", c_bool),
227+
("symbol", c_char_p),
228+
("name", c_char_p),
229+
]
230+
224231
class PluginPortRanges(Structure):
225232
_fields_ = [
226233
("minimum", c_float),
@@ -253,6 +260,7 @@ class PluginPort(Structure):
253260
("units", PluginPortUnits),
254261
("comment", c_char_p),
255262
("designation", c_char_p),
263+
("group", c_char_p),
256264
("properties", POINTER(c_char_p)),
257265
("rangeSteps", c_int),
258266
("scalePoints", POINTER(PluginPortScalePoint)),
@@ -343,6 +351,7 @@ class PluginInfo(Structure):
343351
("bundles", POINTER(c_char_p)),
344352
("gui", PluginGUI),
345353
("ports", PluginPorts),
354+
("portGroups", POINTER(PluginPortGroup)),
346355
("parameters", POINTER(PluginParameter)),
347356
("presets", POINTER(PluginPreset)),
348357
]
@@ -532,6 +541,7 @@ class JackData(Structure):
532541
POINTER(PluginPortScalePoint),
533542
POINTER(PluginPort),
534543
POINTER(PluginParameter),
544+
POINTER(PluginPortGroup),
535545
POINTER(PluginPreset),
536546
POINTER(PedalboardPlugin),
537547
POINTER(PedalboardConnection),

utils/utils.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2012-2023 MOD Audio UG
1+
// SPDX-FileCopyrightText: 2012-2025 MOD Audio UG
22
// SPDX-License-Identifier: AGPL-3.0-or-later
33

44
#ifndef MOD_UTILS_H_INCLUDED
@@ -76,6 +76,13 @@ typedef struct {
7676
const char* thumbnail;
7777
} PluginGUI_Mini;
7878

79+
typedef struct {
80+
bool valid;
81+
const char* uri;
82+
const char* symbol;
83+
const char* name;
84+
} PluginPortGroup;
85+
7986
typedef struct {
8087
float min;
8188
float max;
@@ -104,6 +111,7 @@ typedef struct {
104111
PluginPortUnits units;
105112
const char* comment;
106113
const char* designation;
114+
const char* group;
107115
const char* const* properties;
108116
int rangeSteps;
109117
const PluginPortScalePoint* scalePoints;
@@ -185,6 +193,7 @@ typedef struct {
185193
const char* const* bundles;
186194
PluginGUI gui;
187195
PluginPorts ports;
196+
const PluginPortGroup* portGroups;
188197
const PluginParameter* parameters;
189198
const PluginPreset* presets;
190199
} PluginInfo;

utils/utils_lilv.cpp

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2012-2023 MOD Audio UG
1+
// SPDX-FileCopyrightText: 2012-2025 MOD Audio UG
22
// SPDX-License-Identifier: AGPL-3.0-or-later
33

44
#include "utils.h"
@@ -15,6 +15,7 @@
1515
#include <lv2/midi/midi.h>
1616
#include <lv2/morph/morph.h>
1717
#include <lv2/patch/patch.h>
18+
#include <lv2/port-groups/port-groups.h>
1819
#include <lv2/port-props/port-props.h>
1920
#include <lv2/presets/presets.h>
2021
#include <lv2/state/state.h>
@@ -210,6 +211,7 @@ static const bool kOnlyShowPluginsWithMODGUI = getenv("MOD_UI_ONLY_SHOW_PLUGINS_
210211
{ nullptr, nullptr } \
211212
}, \
212213
nullptr, \
214+
nullptr, \
213215
nullptr \
214216
}
215217

@@ -358,6 +360,7 @@ struct NamespaceDefinitions {
358360
LilvNode* atom_bufferType;
359361
LilvNode* atom_Sequence;
360362
LilvNode* midi_MidiEvent;
363+
LilvNode* pgroups_group;
361364
LilvNode* pprops_rangeSteps;
362365
LilvNode* patch_readable;
363366
LilvNode* patch_writable;
@@ -451,6 +454,7 @@ struct NamespaceDefinitions {
451454
atom_bufferType = lilv_new_uri(w, LV2_ATOM__bufferType);
452455
atom_Sequence = lilv_new_uri(w, LV2_ATOM__Sequence);
453456
midi_MidiEvent = lilv_new_uri(w, LV2_MIDI__MidiEvent);
457+
pgroups_group = lilv_new_uri(w, LV2_PORT_GROUPS__group);
454458
pprops_rangeSteps = lilv_new_uri(w, LV2_PORT_PROPS__rangeSteps);
455459
patch_readable = lilv_new_uri(w, LV2_PATCH__readable);
456460
patch_writable = lilv_new_uri(w, LV2_PATCH__writable);
@@ -522,6 +526,7 @@ struct NamespaceDefinitions {
522526
lilv_node_free(atom_bufferType);
523527
lilv_node_free(atom_Sequence);
524528
lilv_node_free(midi_MidiEvent);
529+
lilv_node_free(pgroups_group);
525530
lilv_node_free(pprops_rangeSteps);
526531
lilv_node_free(patch_readable);
527532
lilv_node_free(patch_writable);
@@ -2605,6 +2610,8 @@ const PluginInfo& _get_plugin_info(LilvWorld* const w,
26052610
// --------------------------------------------------------------------------------------------------------
26062611
// ports
26072612

2613+
std::unordered_map<std::string, PluginPortGroup> portGroups;
2614+
26082615
if (const uint32_t count = lilv_plugin_get_num_ports(p))
26092616
{
26102617
uint32_t countAudioInput=0, countAudioOutput=0;
@@ -2851,6 +2858,47 @@ const PluginInfo& _get_plugin_info(LilvWorld* const w,
28512858
portinfo.designation = nc;
28522859
}
28532860

2861+
// ----------------------------------------------------------------------------------------------------
2862+
// group
2863+
2864+
if (LilvNodes* const nodes = lilv_port_get_value(p, port, ns.pgroups_group))
2865+
{
2866+
LilvNode* const group = lilv_nodes_get_first(nodes);
2867+
portinfo.group = strdup(lilv_node_as_string(group));
2868+
2869+
if (! contains(portGroups, portinfo.group))
2870+
{
2871+
PluginPortGroup& portGroup = portGroups[portinfo.group] = {
2872+
true,
2873+
portinfo.group,
2874+
nc,
2875+
nc,
2876+
};
2877+
2878+
if (LilvNode* const group_symbol = lilv_world_get(w, group, ns.lv2core_symbol, nullptr))
2879+
{
2880+
if (const char* const symbolstr = lilv_node_as_string(group_symbol))
2881+
portGroup.symbol = strdup(symbolstr);
2882+
2883+
lilv_node_free(group_symbol);
2884+
}
2885+
2886+
if (LilvNode* const group_name = lilv_world_get(w, group, ns.lv2core_name, nullptr))
2887+
{
2888+
if (const char* const namestr = lilv_node_as_string(group_name))
2889+
portGroup.symbol = strdup(namestr);
2890+
2891+
lilv_node_free(group_name);
2892+
}
2893+
}
2894+
2895+
lilv_nodes_free(nodes);
2896+
}
2897+
else
2898+
{
2899+
portinfo.group = nc;
2900+
}
2901+
28542902
// ----------------------------------------------------------------------------------------------------
28552903
// range steps
28562904

@@ -3069,6 +3117,22 @@ const PluginInfo& _get_plugin_info(LilvWorld* const w,
30693117
info.iotype = kPluginIONull;
30703118
}
30713119

3120+
// --------------------------------------------------------------------------------------------------------
3121+
// port groups
3122+
3123+
if (size_t count = portGroups.size())
3124+
{
3125+
PluginPortGroup* const groups = new PluginPortGroup[count+1];
3126+
3127+
count = 0;
3128+
for (auto& group : portGroups)
3129+
groups[count++] = group.second;
3130+
3131+
memset(&groups[count], 0, sizeof(PluginPortGroup));
3132+
3133+
info.portGroups = groups;
3134+
}
3135+
30723136
// --------------------------------------------------------------------------------------------------------
30733137
// parameters
30743138

@@ -3411,6 +3475,8 @@ static void _clear_port_info(PluginPort& portinfo)
34113475
free((void*)portinfo.comment);
34123476
if (portinfo.designation != nc)
34133477
free((void*)portinfo.designation);
3478+
if (portinfo.group != nc)
3479+
free((void*)portinfo.group);
34143480
if (portinfo.shortName != nc)
34153481
free((void*)portinfo.shortName);
34163482

@@ -3441,6 +3507,15 @@ static void _clear_port_info(PluginPort& portinfo)
34413507
memset(&portinfo, 0, sizeof(PluginPort));
34423508
}
34433509

3510+
static void _clear_port_group_info(const PluginPortGroup& portGroup)
3511+
{
3512+
// NOTE portGroup.uri points to port.group
3513+
if (portGroup.symbol != nc)
3514+
free((void*)portGroup.symbol);
3515+
if (portGroup.name != nc)
3516+
free((void*)portGroup.name);
3517+
}
3518+
34443519
static void _clear_parameter_info(const PluginParameter& parameter)
34453520
{
34463521
free((void*)parameter.uri);
@@ -3610,6 +3685,13 @@ static void _clear_plugin_info(PluginInfo& info)
36103685
delete[] info.ports.midi.output;
36113686
}
36123687

3688+
if (info.portGroups != nullptr)
3689+
{
3690+
for (int i=0; info.portGroups[i].valid; ++i)
3691+
_clear_port_group_info(info.portGroups[i]);
3692+
delete[] info.portGroups;
3693+
}
3694+
36133695
if (info.parameters != nullptr)
36143696
{
36153697
for (int i=0; info.parameters[i].valid; ++i)

0 commit comments

Comments
 (0)