diff options
author | Stefan Sauer <ensonic@users.sf.net> | 2016-05-15 22:05:43 -0700 |
---|---|---|
committer | Stefan Sauer <ensonic@users.sf.net> | 2016-05-15 22:05:43 -0700 |
commit | 04a957c9b8664df5c853dffd462970216f15109a (patch) | |
tree | d1b6fbd07856227e698b2b6c4d28f49f5b139aa2 /ext/lv2 | |
parent | 5aee046876786bfffc6651d53b63516a9e63a337 (diff) |
lv2: generate enums from scalepoints
Plugins can provide a set of named values for a control port. Ideally only those
values are set for the property. Check if all scalepoints are integers and if so
generate an enum type.
Diffstat (limited to 'ext/lv2')
-rw-r--r-- | ext/lv2/README | 4 | ||||
-rw-r--r-- | ext/lv2/gstlv2utils.c | 98 |
2 files changed, 94 insertions, 8 deletions
diff --git a/ext/lv2/README b/ext/lv2/README index 8d0393b18..0e456db28 100644 --- a/ext/lv2/README +++ b/ext/lv2/README @@ -9,6 +9,7 @@ Features: The plugin wrapper support the following plugin features: http://lv2plug.in/ns/lv2core +http://lv2plug.in/ns/ext/event http://lv2plug.in/ns/ext/port-groups and these host features: @@ -37,10 +38,11 @@ TODO - these ports need a buffer with the property value - we should sync, then fill the buffer and connect the port * support presets + for pl in $(lv2ls); do if test "$(lv2info "$pl" | grep -A1 "Presets:" | tail -n1)" != ""; then echo "$pl"; fi; done * support more host features GST_DEBUG="lv2:4" GST_DEBUG_FILE=/tmp/gst.log gst-inspect lv2 grep -o "needs host feature: .*$" /tmp/gst.log | sort | uniq -c | sort -n -* samples sources: +* example sources: http://svn.drobilla.net/lad/trunk/lilv/utils/lv2info.c http://svn.drobilla.net/lad/trunk/jalv/src/jalv.c diff --git a/ext/lv2/gstlv2utils.c b/ext/lv2/gstlv2utils.c index 0224a84e6..2bae97e43 100644 --- a/ext/lv2/gstlv2utils.c +++ b/ext/lv2/gstlv2utils.c @@ -23,6 +23,7 @@ #endif #include "string.h" +#include "stdlib.h" #include "gstlv2.h" #include "gstlv2utils.h" @@ -212,14 +213,18 @@ void gst_lv2_object_set_property (GstLV2 * lv2, GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { + GType base, type = pspec->value_type; /* remember, properties have an offset */ prop_id -= lv2->klass->properties; /* only input ports */ g_return_if_fail (prop_id < lv2->klass->control_in_ports->len); + while ((base = g_type_parent (type))) + type = base; + /* now see what type it is */ - switch (pspec->value_type) { + switch (type) { case G_TYPE_BOOLEAN: lv2->ports.control.in[prop_id] = g_value_get_boolean (value) ? 0.0f : 1.0f; @@ -230,6 +235,9 @@ gst_lv2_object_set_property (GstLV2 * lv2, GObject * object, case G_TYPE_FLOAT: lv2->ports.control.in[prop_id] = g_value_get_float (value); break; + case G_TYPE_ENUM: + lv2->ports.control.in[prop_id] = g_value_get_enum (value); + break; default: GST_WARNING_OBJECT (object, "unhandled type: %s", g_type_name (pspec->value_type)); @@ -241,6 +249,7 @@ void gst_lv2_object_get_property (GstLV2 * lv2, GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { + GType base, type = pspec->value_type; gfloat *controls; /* remember, properties have an offset */ @@ -256,8 +265,11 @@ gst_lv2_object_get_property (GstLV2 * lv2, GObject * object, g_return_if_reached (); } + while ((base = g_type_parent (type))) + type = base; + /* now see what type it is */ - switch (pspec->value_type) { + switch (type) { case G_TYPE_BOOLEAN: g_value_set_boolean (value, controls[prop_id] > 0.0f); break; @@ -267,6 +279,9 @@ gst_lv2_object_get_property (GstLV2 * lv2, GObject * object, case G_TYPE_FLOAT: g_value_set_float (value, controls[prop_id]); break; + case G_TYPE_ENUM: + g_value_set_enum (value, (gint) controls[prop_id]); + break; default: GST_WARNING_OBJECT (object, "unhandled type: %s", g_type_name (pspec->value_type)); @@ -321,6 +336,12 @@ gst_lv2_class_get_param_nick (GstLV2Class * klass, const LilvPort * port) return g_strdup (lilv_node_as_string (lilv_port_get_name (lv2plugin, port))); } +static int +enum_val_cmp (GEnumValue * p1, GEnumValue * p2) +{ + return p1->value - p2->value; +} + static GParamSpec * gst_lv2_class_get_param_spec (GstLV2Class * klass, GObjectClass * object_class, gint portnum) @@ -328,10 +349,12 @@ gst_lv2_class_get_param_spec (GstLV2Class * klass, GObjectClass * object_class, const LilvPlugin *lv2plugin = klass->plugin; const LilvPort *port = lilv_plugin_get_port_by_index (lv2plugin, portnum); LilvNode *lv2def, *lv2min, *lv2max; + LilvScalePoints *points; GParamSpec *ret; gchar *name, *nick; gint perms; gfloat lower = 0.0f, upper = 1.0f, def = 0.0f; + GType enum_type = G_TYPE_INVALID; nick = gst_lv2_class_get_param_nick (klass, port); name = gst_lv2_class_get_param_name (klass, object_class, port); @@ -365,21 +388,82 @@ gst_lv2_class_get_param_spec (GstLV2Class * klass, GObjectClass * object_class, if (def < lower) { if (lv2def && lv2min) { - GST_WARNING ("%s has lower bound %f > default %f", - lilv_node_as_string (lilv_plugin_get_uri (lv2plugin)), lower, def); + GST_WARNING ("%s:%s has lower bound %f > default %f", + lilv_node_as_string (lilv_plugin_get_uri (lv2plugin)), name, lower, + def); } lower = def; } if (def > upper) { if (lv2def && lv2max) { - GST_WARNING ("%s has upper bound %f < default %f", - lilv_node_as_string (lilv_plugin_get_uri (lv2plugin)), upper, def); + GST_WARNING ("%s:%s has upper bound %f < default %f", + lilv_node_as_string (lilv_plugin_get_uri (lv2plugin)), name, upper, + def); } upper = def; } - if (lilv_port_has_property (lv2plugin, port, integer_prop)) + if ((points = lilv_port_get_scale_points (lv2plugin, port))) { + GEnumValue *enums; + LilvIter *i; + gint j = 0, n, def_ix = -1; + + n = lilv_scale_points_size (points); + enums = g_new (GEnumValue, n + 1); + + for (i = lilv_scale_points_begin (points); + !lilv_scale_points_is_end (points, i); + i = lilv_scale_points_next (points, i)) { + const LilvScalePoint *point = lilv_scale_points_get (points, i); + gfloat v = lilv_node_as_float (lilv_scale_point_get_value (point)); + const gchar *l = lilv_node_as_string (lilv_scale_point_get_label (point)); + + /* check if value can be safely converted to int */ + if (v != (gint) v) { + GST_DEBUG ("non integer scale point %lf, %s", v, l); + break; + } + if (v == def) { + def_ix = j; + } + enums[j].value = (gint) v; + enums[j].value_nick = enums[j].value_name = l; + GST_DEBUG ("%s:%s enum: %lf, %s", + lilv_node_as_string (lilv_plugin_get_uri (lv2plugin)), name, v, l); + j++; + } + if (j == n) { + gchar *type_name; + + /* scalepoints are not sorted */ + qsort (enums, n, sizeof (GEnumValue), + (int (*)(const void *, const void *)) enum_val_cmp); + + if (def_ix == -1) { + if (lv2def) { + GST_WARNING ("%s:%s has default %f outside of scalepoints", + lilv_node_as_string (lilv_plugin_get_uri (lv2plugin)), name, def); + } + def = enums[0].value; + } + /* terminator */ + enums[j].value = 0; + enums[j].value_name = enums[j].value_nick = NULL; + + type_name = g_strdup_printf ("%s%s", + g_type_name (G_TYPE_FROM_CLASS (object_class)), name); + enum_type = g_enum_register_static (type_name, enums); + g_free (type_name); + } else { + g_free (enums); + } + lilv_scale_points_free (points); + } + + if (enum_type != G_TYPE_INVALID) { + ret = g_param_spec_enum (name, nick, nick, enum_type, def, perms); + } else if (lilv_port_has_property (lv2plugin, port, integer_prop)) ret = g_param_spec_int (name, nick, nick, lower, upper, def, perms); else ret = g_param_spec_float (name, nick, nick, lower, upper, def, perms); |