summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/lv2/README3
-rw-r--r--ext/lv2/gstlv2.c19
-rw-r--r--ext/lv2/gstlv2.h5
-rw-r--r--ext/lv2/gstlv2filter.c32
-rw-r--r--ext/lv2/gstlv2source.c29
-rw-r--r--ext/lv2/gstlv2utils.c103
-rw-r--r--ext/lv2/gstlv2utils.h15
7 files changed, 169 insertions, 37 deletions
diff --git a/ext/lv2/README b/ext/lv2/README
index 0e456db28..98fab5513 100644
--- a/ext/lv2/README
+++ b/ext/lv2/README
@@ -34,9 +34,6 @@ gst-launch-1.0 calf-sourceforge-net-plugins-Organ event-in="C-3" name=s ! interl
TODO
-* support http://lv2plug.in/ns/lv2core/#CVPort
- - 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
diff --git a/ext/lv2/gstlv2.c b/ext/lv2/gstlv2.c
index de8f4bedb..6ad833055 100644
--- a/ext/lv2/gstlv2.c
+++ b/ext/lv2/gstlv2.c
@@ -42,6 +42,7 @@
#include <gst/audio/audio-channels.h>
#include <lv2/lv2plug.in/ns/ext/port-groups/port-groups.h>
+#include "lv2/lv2plug.in/ns/ext/event/event.h"
GST_DEBUG_CATEGORY (lv2_debug);
#define GST_CAT_DEFAULT lv2_debug
@@ -198,8 +199,19 @@ plugin_init (GstPlugin * plugin)
world = lilv_world_new ();
lilv_world_load_all (world);
+/* have been added after lilv-0.22.0, which is the last release */
+#ifndef LILV_URI_ATOM_PORT
+#define LILV_URI_ATOM_PORT "http://lv2plug.in/ns/ext/atom#AtomPort"
+#endif
+#ifndef LILV_URI_CV_PORT
+#define LILV_URI_CV_PORT "http://lv2plug.in/ns/lv2core#CVPort"
+#endif
+
+ atom_class = lilv_new_uri (world, LILV_URI_ATOM_PORT);
audio_class = lilv_new_uri (world, LILV_URI_AUDIO_PORT);
control_class = lilv_new_uri (world, LILV_URI_CONTROL_PORT);
+ cv_class = lilv_new_uri (world, LILV_URI_CV_PORT);
+ event_class = lilv_new_uri (world, LILV_URI_EVENT_PORT);
input_class = lilv_new_uri (world, LILV_URI_INPUT_PORT);
output_class = lilv_new_uri (world, LILV_URI_OUTPUT_PORT);
@@ -207,7 +219,9 @@ plugin_init (GstPlugin * plugin)
toggled_prop = lilv_new_uri (world, LV2_CORE__toggled);
designation_pred = lilv_new_uri (world, LV2_CORE__designation);
in_place_broken_pred = lilv_new_uri (world, LV2_CORE__inPlaceBroken);
+ optional_pred = lilv_new_uri (world, LV2_CORE__optionalFeature);
group_pred = lilv_new_uri (world, LV2_PORT_GROUPS__group);
+ supports_event_pred = lilv_new_uri (world, LV2_EVENT__supportsEvent);
center_role = lilv_new_uri (world, LV2_PORT_GROUPS__center);
left_role = lilv_new_uri (world, LV2_PORT_GROUPS__left);
@@ -275,8 +289,11 @@ __attribute__ ((destructor))
#endif
static void plugin_cleanup (GstPlugin * plugin)
{
+ lilv_node_free (atom_class);
lilv_node_free (audio_class);
lilv_node_free (control_class);
+ lilv_node_free (cv_class);
+ lilv_node_free (event_class);
lilv_node_free (input_class);
lilv_node_free (output_class);
@@ -284,7 +301,9 @@ __attribute__ ((destructor))
lilv_node_free (toggled_prop);
lilv_node_free (designation_pred);
lilv_node_free (in_place_broken_pred);
+ lilv_node_free (optional_pred);
lilv_node_free (group_pred);
+ lilv_node_free (supports_event_pred);
lilv_node_free (center_role);
lilv_node_free (left_role);
diff --git a/ext/lv2/gstlv2.h b/ext/lv2/gstlv2.h
index 340752a93..2a98885ab 100644
--- a/ext/lv2/gstlv2.h
+++ b/ext/lv2/gstlv2.h
@@ -29,15 +29,20 @@
#include "gstlv2utils.h"
LilvWorld *world;
+LilvNode *atom_class;
LilvNode *audio_class;
LilvNode *control_class;
+LilvNode *cv_class;
+LilvNode *event_class;
LilvNode *input_class;
LilvNode *output_class;
LilvNode *integer_prop;
LilvNode *toggled_prop;
LilvNode *designation_pred;
LilvNode *in_place_broken_pred;
+LilvNode *optional_pred;
LilvNode *group_pred;
+LilvNode *supports_event_pred;
LilvNode *center_role;
LilvNode *left_role;
diff --git a/ext/lv2/gstlv2filter.c b/ext/lv2/gstlv2filter.c
index 0f9846390..dc7ea9049 100644
--- a/ext/lv2/gstlv2filter.c
+++ b/ext/lv2/gstlv2filter.c
@@ -305,18 +305,19 @@ static GstFlowReturn
gst_lv2_filter_transform_data (GstLV2Filter * self,
GstMapInfo * in_map, GstMapInfo * out_map)
{
- GstLV2FilterClass *lv2_class;
+ GstLV2FilterClass *klass =
+ (GstLV2FilterClass *) GST_AUDIO_FILTER_GET_CLASS (self);
+ GstLV2Class *lv2_class = &klass->lv2;
GstLV2Group *lv2_group;
GstLV2Port *lv2_port;
- guint j, nframes, samples, out_samples;
- gfloat *in = NULL, *out = NULL;
+ guint j, k, l, nframes, samples, out_samples;
+ gfloat *in = NULL, *out = NULL, *cv = NULL, *mem;
+ gfloat val;
nframes = in_map->size / sizeof (float);
- lv2_class = (GstLV2FilterClass *) GST_AUDIO_FILTER_GET_CLASS (self);
-
/* multi channel inputs */
- lv2_group = &lv2_class->lv2.in_group;
+ lv2_group = &lv2_class->in_group;
samples = nframes / lv2_group->ports->len;
in = g_new0 (gfloat, nframes);
GST_LOG_OBJECT (self, "in : samples=%u, nframes=%u, ports=%d", samples,
@@ -333,7 +334,7 @@ gst_lv2_filter_transform_data (GstLV2Filter * self,
}
/* multi channel outputs */
- lv2_group = &lv2_class->lv2.out_group;
+ lv2_group = &lv2_class->out_group;
out_samples = nframes / lv2_group->ports->len;
out = g_new0 (gfloat, samples * lv2_group->ports->len);
GST_LOG_OBJECT (self, "out: samples=%u, nframes=%u, ports=%d", out_samples,
@@ -344,6 +345,22 @@ gst_lv2_filter_transform_data (GstLV2Filter * self,
out + (j * out_samples));
}
+ /* cv ports */
+ cv = g_new (gfloat, samples * lv2_class->num_cv_in);
+ for (j = k = 0; j < lv2_class->control_in_ports->len; j++) {
+ lv2_port = &g_array_index (lv2_class->control_in_ports, GstLV2Port, j);
+ if (lv2_port->type != GST_LV2_PORT_CV)
+ continue;
+
+ mem = cv + (k * samples);
+ val = self->lv2.ports.control.in[j];
+ /* FIXME: use gst_control_binding_get_value_array */
+ for (l = 0; l < samples; l++)
+ mem[l] = val;
+ lilv_instance_connect_port (self->lv2.instance, lv2_port->index, mem);
+ k++;
+ }
+
lilv_instance_run (self->lv2.instance, samples);
if (lv2_group->ports->len > 1)
@@ -351,6 +368,7 @@ gst_lv2_filter_transform_data (GstLV2Filter * self,
(gfloat *) out_map->data, out_samples, out);
g_free (out);
g_free (in);
+ g_free (cv);
return GST_FLOW_OK;
}
diff --git a/ext/lv2/gstlv2source.c b/ext/lv2/gstlv2source.c
index 23317a21b..3d41c0420 100644
--- a/ext/lv2/gstlv2source.c
+++ b/ext/lv2/gstlv2source.c
@@ -292,8 +292,8 @@ gst_lv2_source_fill (GstBaseSrc * base, guint64 offset,
guint length, GstBuffer * buffer)
{
GstLV2Source *lv2 = (GstLV2Source *) base;
- GstLV2SourceClass *lv2_class =
- (GstLV2SourceClass *) GST_BASE_SRC_GET_CLASS (lv2);
+ GstLV2SourceClass *klass = (GstLV2SourceClass *) GST_BASE_SRC_GET_CLASS (lv2);
+ GstLV2Class *lv2_class = &klass->lv2;
GstLV2Group *lv2_group;
GstLV2Port *lv2_port;
GstClockTime next_time;
@@ -302,8 +302,9 @@ gst_lv2_source_fill (GstBaseSrc * base, guint64 offset,
GstElementClass *eclass;
GstMapInfo map;
gint samplerate, bpf;
- guint j;
- gfloat *out = NULL;
+ guint j, k, l;
+ gfloat *out = NULL, *cv = NULL, *mem;
+ gfloat val;
/* example for tagging generated data */
if (!lv2->tags_pushed) {
@@ -399,7 +400,7 @@ gst_lv2_source_fill (GstBaseSrc * base, guint64 offset,
gst_buffer_map (buffer, &map, GST_MAP_WRITE);
/* multi channel outputs */
- lv2_group = &lv2_class->lv2.out_group;
+ lv2_group = &lv2_class->out_group;
if (lv2_group->ports->len > 1) {
out = g_new0 (gfloat, samples * lv2_group->ports->len);
for (j = 0; j < lv2_group->ports->len; ++j) {
@@ -415,6 +416,22 @@ gst_lv2_source_fill (GstBaseSrc * base, guint64 offset,
GST_LOG_OBJECT (lv2, "connected port 0");
}
+ /* cv ports */
+ cv = g_new (gfloat, samples * lv2_class->num_cv_in);
+ for (j = k = 0; j < lv2_class->control_in_ports->len; j++) {
+ lv2_port = &g_array_index (lv2_class->control_in_ports, GstLV2Port, j);
+ if (lv2_port->type != GST_LV2_PORT_CV)
+ continue;
+
+ mem = cv + (k * samples);
+ val = lv2->lv2.ports.control.in[j];
+ /* FIXME: use gst_control_binding_get_value_array */
+ for (l = 0; l < samples; l++)
+ mem[l] = val;
+ lilv_instance_connect_port (lv2->lv2.instance, lv2_port->index, mem);
+ k++;
+ }
+
lilv_instance_run (lv2->lv2.instance, samples);
if (lv2_group->ports->len > 1) {
@@ -423,6 +440,8 @@ gst_lv2_source_fill (GstBaseSrc * base, guint64 offset,
g_free (out);
}
+ g_free (cv);
+
gst_buffer_unmap (buffer, &map);
return GST_FLOW_OK;
diff --git a/ext/lv2/gstlv2utils.c b/ext/lv2/gstlv2utils.c
index cedd6bc4e..08d9d94cd 100644
--- a/ext/lv2/gstlv2utils.c
+++ b/ext/lv2/gstlv2utils.c
@@ -158,6 +158,8 @@ gboolean
gst_lv2_setup (GstLV2 * lv2, unsigned long rate)
{
GstLV2Class *lv2_class = lv2->klass;
+ GstLV2Port *port;
+ GArray *ports;
gint i;
if (lv2->instance)
@@ -168,15 +170,22 @@ gst_lv2_setup (GstLV2 * lv2, unsigned long rate)
return FALSE;
/* connect the control ports */
- for (i = 0; i < lv2_class->control_in_ports->len; i++)
- lilv_instance_connect_port (lv2->instance,
- g_array_index (lv2_class->control_in_ports, GstLV2Port, i).index,
+ ports = lv2_class->control_in_ports;
+ for (i = 0; i < ports->len; i++) {
+ port = &g_array_index (ports, GstLV2Port, i);
+ if (port->type != GST_LV2_PORT_CONTROL)
+ continue;
+ lilv_instance_connect_port (lv2->instance, port->index,
&(lv2->ports.control.in[i]));
-
- for (i = 0; i < lv2_class->control_out_ports->len; i++)
- lilv_instance_connect_port (lv2->instance,
- g_array_index (lv2_class->control_out_ports, GstLV2Port, i).index,
+ }
+ ports = lv2_class->control_out_ports;
+ for (i = 0; i < ports->len; i++) {
+ port = &g_array_index (ports, GstLV2Port, i);
+ if (port->type != GST_LV2_PORT_CONTROL)
+ continue;
+ lilv_instance_connect_port (lv2->instance, port->index,
&(lv2->ports.control.out[i]));
+ }
lilv_instance_activate (lv2->instance);
lv2->activated = TRUE;
@@ -365,7 +374,8 @@ gst_lv2_class_get_param_spec (GstLV2Class * klass, GObjectClass * object_class,
perms = G_PARAM_READABLE;
if (lilv_port_is_a (lv2plugin, port, input_class))
perms |= G_PARAM_WRITABLE | G_PARAM_CONSTRUCT;
- if (lilv_port_is_a (lv2plugin, port, control_class))
+ if (lilv_port_is_a (lv2plugin, port, control_class) ||
+ lilv_port_is_a (lv2plugin, port, cv_class))
perms |= GST_PARAM_CONTROLLABLE;
if (lilv_port_has_property (lv2plugin, port, toggled_prop)) {
@@ -547,8 +557,6 @@ gst_lv2_class_init (GstLV2Class * lv2_class, GType type)
gst_structure_get_value (lv2_meta_all, g_type_name (type));
GstStructure *lv2_meta = g_value_get_boxed (value);
const LilvPlugin *lv2plugin;
- /* FIXME Handle channels positionning
- * GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_INVALID; */
guint j, in_pad_index = 0, out_pad_index = 0;
const LilvPlugins *plugins = lilv_world_get_all_plugins (world);
LilvNode *plugin_uri;
@@ -573,8 +581,12 @@ gst_lv2_class_init (GstLV2Class * lv2_class, GType type)
for (j = 0; j < lilv_plugin_get_num_ports (lv2plugin); j++) {
const LilvPort *port = lilv_plugin_get_port_by_index (lv2plugin, j);
const gboolean is_input = lilv_port_is_a (lv2plugin, port, input_class);
- struct _GstLV2Port desc = { j, 0, };
+ const gboolean is_optional = lilv_port_has_property (lv2plugin, port,
+ optional_pred);
+ GstLV2Port desc = { j, GST_LV2_PORT_AUDIO, -1, };
LilvNodes *lv2group = lilv_port_get (lv2plugin, port, group_pred);
+ /* FIXME Handle channels positionning
+ * GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_INVALID; */
if (lv2group) {
/* port is part of a group */
@@ -590,7 +602,7 @@ gst_lv2_class_init (GstLV2Class * lv2_class, GType type)
/* FIXME Handle channels positionning
position = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
- sub_values = lilv_port_get_value (lv2plugin, port, has_role_pred);
+ sub_values = lilv_port_get_value (lv2plugin, port, designation_pred);
if (lilv_nodes_size (sub_values) > 0) {
LilvNode *role = lilv_nodes_get_at (sub_values, 0);
position = gst_lv2_filter_role_to_position (role);
@@ -606,21 +618,70 @@ gst_lv2_class_init (GstLV2Class * lv2_class, GType type)
/* port is not part of a group, or it is part of a group but that group
* is illegal so we just ignore it */
if (lilv_port_is_a (lv2plugin, port, audio_class)) {
- desc.pad = is_input ? in_pad_index++ : out_pad_index++;
- if (is_input)
+ if (is_input) {
+ desc.pad = in_pad_index++;
g_array_append_val (lv2_class->in_group.ports, desc);
- else
+ } else {
+ desc.pad = out_pad_index++;
g_array_append_val (lv2_class->out_group.ports, desc);
+ }
} else if (lilv_port_is_a (lv2plugin, port, control_class)) {
- if (is_input)
+ desc.type = GST_LV2_PORT_CONTROL;
+ if (is_input) {
+ lv2_class->num_control_in++;
+ g_array_append_val (lv2_class->control_in_ports, desc);
+ } else {
+ lv2_class->num_control_out++;
+ g_array_append_val (lv2_class->control_out_ports, desc);
+ }
+ } else if (lilv_port_is_a (lv2plugin, port, cv_class)) {
+ desc.type = GST_LV2_PORT_CV;
+ if (is_input) {
+ lv2_class->num_cv_in++;
g_array_append_val (lv2_class->control_in_ports, desc);
- else
+ } else {
+ lv2_class->num_cv_out++;
g_array_append_val (lv2_class->control_out_ports, desc);
+ }
+ } else if (lilv_port_is_a (lv2plugin, port, event_class)) {
+ LilvNodes *supported = lilv_port_get_value (lv2plugin, port,
+ supports_event_pred);
+
+ GST_INFO ("%s: unhandled event port %d: %s, optional=%d, input=%d",
+ element_uri, j,
+ lilv_node_as_string (lilv_port_get_symbol (lv2plugin, port)),
+ is_optional, is_input);
+
+ if (lilv_nodes_size (supported) > 0) {
+ LilvIter *i;
+
+ for (i = lilv_nodes_begin (supported);
+ !lilv_nodes_is_end (supported, i);
+ i = lilv_nodes_next (supported, i)) {
+ const LilvNode *value = lilv_nodes_get (supported, i);
+ GST_INFO (" type = %s", lilv_node_as_uri (value));
+ }
+ }
+ lilv_nodes_free (supported);
+ // FIXME: handle them
} else {
- /* unknown port type */
- GST_INFO ("unhandled port %d: %s", j,
- lilv_node_as_string (lilv_port_get_symbol (lv2plugin, port)));
- continue;
+ /* unhandled port type */
+ const LilvNodes *classes = lilv_port_get_classes (lv2plugin, port);
+ GST_INFO ("%s: unhandled port %d: %s, optional=%d, input=%d",
+ element_uri, j,
+ lilv_node_as_string (lilv_port_get_symbol (lv2plugin, port)),
+ is_optional, is_input);
+ if (classes && lilv_nodes_size (classes) > 0) {
+ LilvIter *i;
+
+ // FIXME: we getting the same classe multiple times
+ for (i = lilv_nodes_begin (classes);
+ !lilv_nodes_is_end (classes, i);
+ i = lilv_nodes_next (classes, i)) {
+ const LilvNode *value = lilv_nodes_get (classes, i);
+ GST_INFO (" class = %s", lilv_node_as_uri (value));
+ }
+ }
}
}
}
diff --git a/ext/lv2/gstlv2utils.h b/ext/lv2/gstlv2utils.h
index 6ff648271..e5213b2aa 100644
--- a/ext/lv2/gstlv2utils.h
+++ b/ext/lv2/gstlv2utils.h
@@ -43,13 +43,23 @@ struct _GstLV2Group
guint pad; /**< Gst pad index */
gchar *symbol; /**< Gst pad name / LV2 group symbol */
GArray *ports; /**< Array of GstLV2Port */
+ /* FIXME: not set as of now */
gboolean has_roles; /**< TRUE iff all ports have a known role */
};
+typedef enum {
+ GST_LV2_PORT_AUDIO = 0,
+ GST_LV2_PORT_CONTROL,
+ GST_LV2_PORT_CV
+} GstLV2PortType;
+
struct _GstLV2Port
{
gint index; /**< LV2 port index (on LV2 plugin) */
- gint pad; /**< Gst pad index (iff not part of a group) */
+ GstLV2PortType type; /**< Port type */
+ /**< Gst pad index (iff not part of a group), only for audio ports */
+ gint pad;
+ /* FIXME: not set as of now */
LilvNode *role; /**< Channel position / port role */
GstAudioChannelPosition position; /**< Channel position */
};
@@ -79,6 +89,9 @@ struct _GstLV2Class
const LilvPlugin *plugin;
+ gint num_control_in, num_control_out;
+ gint num_cv_in, num_cv_out;
+
GstLV2Group in_group; /**< Array of GstLV2Group */
GstLV2Group out_group; /**< Array of GstLV2Group */
GArray *control_in_ports; /**< Array of GstLV2Port */