diff options
Diffstat (limited to 'ext/lv2/gstlv2.c')
-rw-r--r-- | ext/lv2/gstlv2.c | 487 |
1 files changed, 347 insertions, 140 deletions
diff --git a/ext/lv2/gstlv2.c b/ext/lv2/gstlv2.c index a7617071..7c6e1c3b 100644 --- a/ext/lv2/gstlv2.c +++ b/ext/lv2/gstlv2.c @@ -19,13 +19,28 @@ * Boston, MA 02111-1307, USA. */ +/** + * SECTION:element-lv2 + * @short_description: bridge for LV2. + * + * LV2 is a standard for plugins and matching host applications, + * mainly targeted at audio processing and generation. It is intended as + * a successor to LADSPA (Linux Audio Developer's Simple Plugin API). + * + * The LV2 element is a bridge for plugins using the + * <ulink url="http://www.lv2plug.in/">LV2</ulink> API. It scans all + * installed LV2 plugins and registers them as gstreamer elements. + */ + #ifdef HAVE_CONFIG_H #include "config.h" #endif #include <string.h> #include <math.h> +#include <glib.h> #include <gst/audio/audio.h> #include <gst/controller/gstcontroller.h> +#include <gst/audio/multichannel.h> #include "gstlv2.h" #include <slv2/slv2.h> @@ -51,6 +66,22 @@ SLV2Value input_class; SLV2Value output_class; SLV2Value integer_prop; SLV2Value toggled_prop; +SLV2Value in_place_broken_pred; +SLV2Value in_group_pred; +SLV2Value has_role_pred; +SLV2Value lv2_symbol_pred; + +SLV2Value center_role; +SLV2Value left_role; +SLV2Value right_role; +SLV2Value rear_center_role; +SLV2Value rear_left_role; +SLV2Value rear_right_role; +SLV2Value lfe_role; +SLV2Value center_left_role; +SLV2Value center_right_role; +SLV2Value side_left_role; +SLV2Value side_right_role; static GstSignalProcessorClass *parent_class; @@ -59,6 +90,82 @@ static GstPlugin *gst_lv2_plugin; GST_DEBUG_CATEGORY_STATIC (lv2_debug); #define GST_CAT_DEFAULT lv2_debug +/** Convert an LV2 port role to a Gst channel positon + * WARNING: If the group has only a single port, + * GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER will be returned for pg:centerRole + * (which is used by LV2 for mono groups), but this is not correct. In this + * case the value must be changed to GST_AUDIO_CHANNEL_POSITION_FRONT_MONO + * (this can't be done by this function because this information isn't known + * at the time it is used). + */ +static GstAudioChannelPosition +gst_lv2_role_to_position (SLV2Value role) +{ + /* Front. Mono and left/right are mututally exclusive */ + if (slv2_value_equals (role, center_role)) { + + return GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER; + } else if (slv2_value_equals (role, left_role)) { + return GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT; + } else if (slv2_value_equals (role, right_role)) { + return GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; + + /* Rear. Left/right and center are mututally exclusive */ + } else if (slv2_value_equals (role, rear_center_role)) { + return GST_AUDIO_CHANNEL_POSITION_REAR_CENTER; + } else if (slv2_value_equals (role, rear_left_role)) { + return GST_AUDIO_CHANNEL_POSITION_REAR_LEFT; + } else if (slv2_value_equals (role, rear_right_role)) { + return GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT; + + /* Subwoofer/low-frequency-effects */ + } else if (slv2_value_equals (role, lfe_role)) { + return GST_AUDIO_CHANNEL_POSITION_LFE; + + /* Center front speakers. Center and left/right_of_center + * are mutually exclusive */ + } else if (slv2_value_equals (role, center_left_role)) { + return GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER; + } else if (slv2_value_equals (role, center_right_role)) { + return GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER; + + /* sides */ + } else if (slv2_value_equals (role, side_left_role)) { + return GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT; + } else if (slv2_value_equals (role, side_right_role)) { + return GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT; + } + + return GST_AUDIO_CHANNEL_POSITION_INVALID; +} + +/** Find and return the group @a uri in @a groups, or NULL if not found */ +static GstLV2Group * +gst_lv2_class_find_group (GArray * groups, SLV2Value uri) +{ + int i = 0; + for (; i < groups->len; ++i) + if (slv2_value_equals (g_array_index (groups, GstLV2Group, i).uri, uri)) + return &g_array_index (groups, GstLV2Group, i); + return NULL; +} + +static GstAudioChannelPosition * +gst_lv2_build_positions (GstLV2Group * group) +{ + int i; + GstAudioChannelPosition *positions = NULL; + if (group->has_roles) { + positions = malloc (group->ports->len * sizeof (GstAudioChannelPosition)); + for (i = 0; i < group->ports->len; ++i) + positions[i] = g_array_index (group->ports, GstLV2Port, i).position; + + // Fix up mono groups (see WARNING above) + if (group->ports->len == 1) + positions[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO; + } + return positions; +} static void gst_lv2_base_init (gpointer g_class) @@ -69,7 +176,12 @@ gst_lv2_base_init (gpointer g_class) GstElementDetails *details; SLV2Plugin lv2plugin; SLV2Value val; - guint j, audio_in_count, audio_out_count, control_in_count, control_out_count; + SLV2Values values, sub_values; + GstLV2Group *group = NULL; + GstAudioChannelPosition position = GST_AUDIO_CHANNEL_POSITION_INVALID; + GstAudioChannelPosition mono_position = GST_AUDIO_CHANNEL_POSITION_FRONT_MONO; + GstAudioChannelPosition *positions = NULL; + guint j, in_pad_index = 0, out_pad_index = 0; gchar *klass_tags; GST_DEBUG ("base_init %p", g_class); @@ -79,39 +191,147 @@ gst_lv2_base_init (gpointer g_class) g_assert (lv2plugin); - /* pad templates */ + gsp_class->num_group_in = 0; + gsp_class->num_group_out = 0; gsp_class->num_audio_in = 0; gsp_class->num_audio_out = 0; - /* properties */ gsp_class->num_control_in = 0; gsp_class->num_control_out = 0; + klass->in_groups = g_array_new (FALSE, TRUE, sizeof (GstLV2Group)); + klass->out_groups = g_array_new (FALSE, TRUE, sizeof (GstLV2Group)); + klass->audio_in_ports = g_array_new (FALSE, TRUE, sizeof (GstLV2Port)); + klass->audio_out_ports = g_array_new (FALSE, TRUE, sizeof (GstLV2Port)); + klass->control_in_ports = g_array_new (FALSE, TRUE, sizeof (GstLV2Port)); + klass->control_out_ports = g_array_new (FALSE, TRUE, sizeof (GstLV2Port)); + + /* find ports and groups */ for (j = 0; j < slv2_plugin_get_num_ports (lv2plugin); j++) { - SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, j); - if (slv2_port_is_a (lv2plugin, port, audio_class)) { - gchar *name = - g_strdup (slv2_value_as_string (slv2_port_get_symbol (lv2plugin, - port))); - - GST_DEBUG ("LV2 port name: \"%s\"", name); - - if (slv2_port_is_a (lv2plugin, port, input_class)) - gst_signal_processor_class_add_pad_template (gsp_class, name, - GST_PAD_SINK, gsp_class->num_audio_in++); - else if (slv2_port_is_a (lv2plugin, port, output_class)) - gst_signal_processor_class_add_pad_template (gsp_class, name, - GST_PAD_SRC, gsp_class->num_audio_out++); - /* TODO: else ignore plugin */ - - g_free (name); - } else if (slv2_port_is_a (lv2plugin, port, control_class)) { - if (slv2_port_is_a (lv2plugin, port, input_class)) - gsp_class->num_control_in++; - else if (slv2_port_is_a (lv2plugin, port, output_class)) - gsp_class->num_control_out++; - /* TODO: else ignore plugin */ + const SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, j); + const gboolean is_input = slv2_port_is_a (lv2plugin, port, input_class); + struct _GstLV2Port desc = { j, 0 }; + values = slv2_port_get_value (lv2plugin, port, in_group_pred); + + if (slv2_values_size (values) > 0) { + /* port is part of a group */ + SLV2Value group_uri = slv2_values_get_at (values, 0); + GArray *groups = is_input ? klass->in_groups : klass->out_groups; + GstLV2Group *group = gst_lv2_class_find_group (groups, group_uri); + if (group == NULL) { + GstLV2Group g; + g.uri = slv2_value_duplicate (group_uri); + g.pad = is_input ? in_pad_index++ : out_pad_index++; + g.ports = g_array_new (FALSE, TRUE, sizeof (GstLV2Port)); + g.has_roles = TRUE; + sub_values = slv2_plugin_get_value_for_subject (lv2plugin, group_uri, + lv2_symbol_pred); + if (slv2_values_size (sub_values) > 0) + g.symbol = slv2_value_duplicate (slv2_values_get_at (sub_values, 0)); + else + g.symbol = NULL; + slv2_values_free (sub_values); + + g_array_append_val (groups, g); + group = &g_array_index (groups, GstLV2Group, groups->len - 1); + } + + position = GST_AUDIO_CHANNEL_POSITION_INVALID; + sub_values = slv2_port_get_value (lv2plugin, port, has_role_pred); + if (slv2_values_size (sub_values) > 0) { + SLV2Value role = slv2_values_get_at (sub_values, 0); + position = gst_lv2_role_to_position (role); + slv2_values_free (sub_values); + } + if (position != GST_AUDIO_CHANNEL_POSITION_INVALID) { + desc.position = position; + } else { + group->has_roles = FALSE; + } + + g_array_append_val (group->ports, desc); + + } else { + /* port is not part of a group */ + if (slv2_port_is_a (lv2plugin, port, audio_class)) { + desc.pad = is_input ? in_pad_index++ : out_pad_index++; + if (is_input) + g_array_append_val (klass->audio_in_ports, desc); + else + g_array_append_val (klass->audio_out_ports, desc); + } else if (slv2_port_is_a (lv2plugin, port, control_class)) { + if (is_input) + g_array_append_val (klass->control_in_ports, desc); + else + g_array_append_val (klass->control_out_ports, desc); + } else { + /* unknown port type */ + continue; + } } - /* TODO: else ignore plugin */ + slv2_values_free (values); + } + + gsp_class->num_group_in = klass->in_groups->len; + gsp_class->num_group_out = klass->out_groups->len; + gsp_class->num_audio_in = klass->audio_in_ports->len; + gsp_class->num_audio_out = klass->audio_out_ports->len; + gsp_class->num_control_in = klass->control_in_ports->len; + gsp_class->num_control_out = klass->control_out_ports->len; + + /* add input group pad templates */ + for (j = 0; j < gsp_class->num_group_in; ++j) { + group = &g_array_index (klass->in_groups, GstLV2Group, j); + if (group->has_roles) { + positions = gst_lv2_build_positions (group); + } + + gst_signal_processor_class_add_pad_template (gsp_class, + slv2_value_as_string (group->symbol), + GST_PAD_SINK, j, group->ports->len, positions); + + if (group->has_roles) { + free (positions); + positions = NULL; + } + } + + /* add output group pad templates */ + for (j = 0; j < gsp_class->num_group_out; ++j) { + group = &g_array_index (klass->out_groups, GstLV2Group, j); + if (group->has_roles) { + positions = gst_lv2_build_positions (group); + } + + gst_signal_processor_class_add_pad_template (gsp_class, + slv2_value_as_string (group->symbol), + GST_PAD_SRC, j, group->ports->len, positions); + + if (group->has_roles) { + free (positions); + positions = NULL; + } + } + + /* add non-grouped input port pad templates */ + for (j = 0; j < gsp_class->num_audio_in; ++j) { + struct _GstLV2Port *desc = + &g_array_index (klass->audio_in_ports, GstLV2Port, j); + SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, desc->index); + const gchar *name = + slv2_value_as_string (slv2_port_get_symbol (lv2plugin, port)); + gst_signal_processor_class_add_pad_template (gsp_class, name, GST_PAD_SINK, + j, 1, &mono_position); + } + + /* add non-grouped output port pad templates */ + for (j = 0; j < gsp_class->num_audio_out; ++j) { + struct _GstLV2Port *desc = + &g_array_index (klass->audio_out_ports, GstLV2Port, j); + SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, desc->index); + const gchar *name = + slv2_value_as_string (slv2_port_get_symbol (lv2plugin, port)); + gst_signal_processor_class_add_pad_template (gsp_class, name, GST_PAD_SINK, + j, 1, &mono_position); } /* construct the element details struct */ @@ -149,36 +369,8 @@ gst_lv2_base_init (gpointer g_class) g_free (details->author); g_free (details); - klass->audio_in_portnums = g_new0 (gint, gsp_class->num_audio_in); - klass->audio_out_portnums = g_new0 (gint, gsp_class->num_audio_out); - klass->control_in_portnums = g_new0 (gint, gsp_class->num_control_in); - klass->control_out_portnums = g_new0 (gint, gsp_class->num_control_out); - - audio_in_count = audio_out_count = control_in_count = control_out_count = 0; - - for (j = 0; j < slv2_plugin_get_num_ports (lv2plugin); j++) { - SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, j); - gboolean is_input = slv2_port_is_a (lv2plugin, port, input_class); - if (slv2_port_is_a (lv2plugin, port, audio_class)) { - if (is_input) - klass->audio_in_portnums[audio_in_count++] = j; - else - klass->audio_out_portnums[audio_out_count++] = j; - } else if (slv2_port_is_a (lv2plugin, port, control_class)) { - if (is_input) - klass->control_in_portnums[control_in_count++] = j; - else - klass->control_out_portnums[control_out_count++] = j; - } - } - - g_assert (audio_in_count == gsp_class->num_audio_in); - g_assert (audio_out_count == gsp_class->num_audio_out); - g_assert (control_in_count == gsp_class->num_control_in); - g_assert (control_out_count == gsp_class->num_control_out); - - /*if (!LV2_IS_INPLACE_BROKEN (desc->Properties)) - GST_SIGNAL_PROCESSOR_CLASS_SET_CAN_PROCESS_IN_PLACE (klass); */ + if (!slv2_plugin_has_feature (lv2plugin, in_place_broken_pred)) + GST_SIGNAL_PROCESSOR_CLASS_SET_CAN_PROCESS_IN_PLACE (klass); klass->plugin = lv2plugin; } @@ -225,6 +417,10 @@ gst_lv2_class_get_param_spec (GstLV2Class * klass, gint portnum) if (lv2max) upper = slv2_value_as_float (lv2max); + slv2_value_free (lv2def); + slv2_value_free (lv2min); + slv2_value_free (lv2max); + if (def < lower) { GST_WARNING ("%s has lower bound %f > default %f\n", slv2_value_as_string (slv2_plugin_get_uri (lv2plugin)), lower, def); @@ -274,7 +470,8 @@ gst_lv2_class_init (GstLV2Class * klass, SLV2Plugin lv2plugin) for (i = 0; i < gsp_class->num_control_in; i++) { GParamSpec *p; - p = gst_lv2_class_get_param_spec (klass, klass->control_in_portnums[i]); + p = gst_lv2_class_get_param_spec (klass, + g_array_index (klass->control_in_ports, GstLV2Port, i).index); /* properties have an offset of 1 */ g_object_class_install_property (G_OBJECT_CLASS (klass), i + 1, p); @@ -283,7 +480,8 @@ gst_lv2_class_init (GstLV2Class * klass, SLV2Plugin lv2plugin) for (i = 0; i < gsp_class->num_control_out; i++) { GParamSpec *p; - p = gst_lv2_class_get_param_spec (klass, klass->control_out_portnums[i]); + p = gst_lv2_class_get_param_spec (klass, + g_array_index (klass->control_out_ports, GstLV2Port, i).index); /* properties have an offset of 1, and we already added num_control_in */ g_object_class_install_property (G_OBJECT_CLASS (klass), @@ -294,19 +492,15 @@ gst_lv2_class_init (GstLV2Class * klass, SLV2Plugin lv2plugin) static void gst_lv2_init (GstLV2 * lv2, GstLV2Class * klass) { -#if 0 lv2->plugin = klass->plugin; lv2->instance = NULL; lv2->activated = FALSE; - lv2->inplace_broken = LV2_IS_INPLACE_BROKEN (lv2->descriptor->Properties); -#endif } static void gst_lv2_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { -#if 0 GstSignalProcessor *gsp; GstSignalProcessorClass *gsp_class; @@ -322,7 +516,7 @@ gst_lv2_set_property (GObject * object, guint prop_id, const GValue * value, /* now see what type it is */ switch (pspec->value_type) { case G_TYPE_BOOLEAN: - gsp->control_in[prop_id] = g_value_get_boolean (value) ? 1.f : 0.f; + gsp->control_in[prop_id] = g_value_get_boolean (value) ? 0.0f : 1.0f; break; case G_TYPE_INT: gsp->control_in[prop_id] = g_value_get_int (value); @@ -333,14 +527,12 @@ gst_lv2_set_property (GObject * object, guint prop_id, const GValue * value, default: g_assert_not_reached (); } -#endif } static void gst_lv2_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { -#if 0 GstSignalProcessor *gsp; GstSignalProcessorClass *gsp_class; gfloat *controls; @@ -363,7 +555,7 @@ gst_lv2_get_property (GObject * object, guint prop_id, GValue * value, /* now see what type it is */ switch (pspec->value_type) { case G_TYPE_BOOLEAN: - g_value_set_boolean (value, controls[prop_id] > 0.5); + g_value_set_boolean (value, controls[prop_id] > 0.0f); break; case G_TYPE_INT: g_value_set_int (value, CLAMP (controls[prop_id], G_MININT, G_MAXINT)); @@ -374,64 +566,54 @@ gst_lv2_get_property (GObject * object, guint prop_id, GValue * value, default: g_return_if_reached (); } -#endif } static gboolean gst_lv2_setup (GstSignalProcessor * gsp, guint sample_rate) { -#if 0 - GstLV2 *ladspa; + GstLV2 *lv2; GstLV2Class *oclass; GstSignalProcessorClass *gsp_class; - LV2_Descriptor *desc; - int i; + gint i; gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (gsp); - ladspa = (GstLV2 *) gsp; + lv2 = (GstLV2 *) gsp; oclass = (GstLV2Class *) gsp_class; - desc = ladspa->descriptor; - g_return_val_if_fail (ladspa->handle == NULL, FALSE); - g_return_val_if_fail (ladspa->activated == FALSE, FALSE); + g_return_val_if_fail (lv2->activated == FALSE, FALSE); - GST_DEBUG_OBJECT (ladspa, "instantiating the plugin at %d Hz", sample_rate); + GST_DEBUG_OBJECT (lv2, "instantiating the plugin at %d Hz", sample_rate); - ladspa->handle = desc->instantiate (desc, sample_rate); + lv2->instance = slv2_plugin_instantiate (oclass->plugin, sample_rate, NULL); - g_return_val_if_fail (ladspa->handle != NULL, FALSE); + g_return_val_if_fail (lv2->instance != NULL, FALSE); /* connect the control ports */ for (i = 0; i < gsp_class->num_control_in; i++) - desc->connect_port (ladspa->handle, - oclass->control_in_portnums[i], &(gsp->control_in[i])); + slv2_instance_connect_port (lv2->instance, + g_array_index (oclass->control_in_ports, GstLV2Port, i).index, + &(gsp->control_in[i])); for (i = 0; i < gsp_class->num_control_out; i++) - desc->connect_port (ladspa->handle, - oclass->control_out_portnums[i], &(gsp->control_out[i])); -#endif + slv2_instance_connect_port (lv2->instance, + g_array_index (oclass->control_out_ports, GstLV2Port, i).index, + &(gsp->control_out[i])); + return TRUE; } static gboolean gst_lv2_start (GstSignalProcessor * gsp) { -#if 0 - GstLV2 *ladspa; - LV2_Descriptor *desc; + GstLV2 *lv2 = (GstLV2 *) gsp; - ladspa = (GstLV2 *) gsp; - desc = ladspa->descriptor; + g_return_val_if_fail (lv2->activated == FALSE, FALSE); + g_return_val_if_fail (lv2->instance != NULL, FALSE); - g_return_val_if_fail (ladspa->activated == FALSE, FALSE); - g_return_val_if_fail (ladspa->handle != NULL, FALSE); + GST_DEBUG_OBJECT (lv2, "activating"); - GST_DEBUG_OBJECT (ladspa, "activating"); + slv2_instance_activate (lv2->instance); - if (desc->activate) - desc->activate (ladspa->handle); - - ladspa->activated = TRUE; -#endif + lv2->activated = TRUE; return TRUE; } @@ -439,71 +621,78 @@ gst_lv2_start (GstSignalProcessor * gsp) static void gst_lv2_stop (GstSignalProcessor * gsp) { -#if 0 - GstLV2 *ladspa; - LV2_Descriptor *desc; + GstLV2 *lv2 = (GstLV2 *) gsp; - ladspa = (GstLV2 *) gsp; - desc = ladspa->descriptor; + g_return_if_fail (lv2->activated == TRUE); + g_return_if_fail (lv2->instance != NULL); - g_return_if_fail (ladspa->activated == TRUE); - g_return_if_fail (ladspa->handle != NULL); + GST_DEBUG_OBJECT (lv2, "deactivating"); - GST_DEBUG_OBJECT (ladspa, "deactivating"); + slv2_instance_deactivate (lv2->instance); - if (desc->activate) - desc->activate (ladspa->handle); - - ladspa->activated = FALSE; -#endif + lv2->activated = FALSE; } static void gst_lv2_cleanup (GstSignalProcessor * gsp) { -#if 0 - GstLV2 *ladspa; - LV2_Descriptor *desc; - - ladspa = (GstLV2 *) gsp; - desc = ladspa->descriptor; + GstLV2 *lv2 = (GstLV2 *) gsp; - g_return_if_fail (ladspa->activated == FALSE); - g_return_if_fail (ladspa->handle != NULL); + g_return_if_fail (lv2->activated == FALSE); + g_return_if_fail (lv2->instance != NULL); - GST_DEBUG_OBJECT (ladspa, "cleaning up"); + GST_DEBUG_OBJECT (lv2, "cleaning up"); - if (desc->cleanup) - desc->cleanup (ladspa->handle); + slv2_instance_free (lv2->instance); - ladspa->handle = NULL; -#endif + lv2->instance = NULL; } static void gst_lv2_process (GstSignalProcessor * gsp, guint nframes) { -#if 0 GstSignalProcessorClass *gsp_class; - GstLV2 *ladspa; + GstLV2 *lv2; GstLV2Class *oclass; - LV2_Descriptor *desc; - guint i; + GstLV2Group *lv2_group; + GstLV2Port *lv2_port; + GstSignalProcessorGroup *gst_group; + guint i, j; gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (gsp); - ladspa = (GstLV2 *) gsp; + lv2 = (GstLV2 *) gsp; oclass = (GstLV2Class *) gsp_class; - desc = ladspa->descriptor; - for (i = 0; i < gsp_class->num_audio_in; i++) - desc->connect_port (ladspa->handle, oclass->audio_in_portnums[i], + for (i = 0; i < gsp_class->num_group_in; i++) { + lv2_group = &g_array_index (oclass->in_groups, GstLV2Group, i); + gst_group = &gsp->group_in[i]; + for (j = 0; j < lv2_group->ports->len; ++j) { + lv2_port = &g_array_index (lv2_group->ports, GstLV2Port, j); + slv2_instance_connect_port (lv2->instance, lv2_port->index, + gst_group->buffer + (j * nframes)); + } + } + for (i = 0; i < gsp_class->num_audio_in; i++) { + lv2_port = &g_array_index (oclass->audio_in_ports, GstLV2Port, i); + slv2_instance_connect_port (lv2->instance, lv2_port->index, gsp->audio_in[i]); - for (i = 0; i < gsp_class->num_audio_out; i++) - desc->connect_port (ladspa->handle, oclass->audio_out_portnums[i], + } + for (i = 0; i < gsp_class->num_group_out; i++) { + lv2_group = &g_array_index (oclass->out_groups, GstLV2Group, i); + gst_group = &gsp->group_out[i]; + for (j = 0; j < lv2_group->ports->len; ++j) { + lv2_port = &g_array_index (lv2_group->ports, GstLV2Port, j); + slv2_instance_connect_port (lv2->instance, lv2_port->index, + gst_group->buffer + (j * nframes)); + } + } + for (i = 0; i < gsp_class->num_audio_out; i++) { + lv2_port = &g_array_index (oclass->audio_out_ports, GstLV2Port, i); + slv2_instance_connect_port (lv2->instance, lv2_port->index, gsp->audio_out[i]); + } - desc->run (ladspa->handle, nframes); -#endif + slv2_instance_run (lv2->instance, nframes); } /* search the plugin path @@ -511,7 +700,7 @@ gst_lv2_process (GstSignalProcessor * gsp, guint nframes) static gboolean lv2_plugin_discover (void) { - unsigned i; + guint i; SLV2Plugins plugins = slv2_world_get_all_plugins (world); for (i = 0; i < slv2_plugins_size (plugins); ++i) { SLV2Plugin lv2plugin = slv2_plugins_get_at (plugins, i); @@ -569,10 +758,28 @@ plugin_init (GstPlugin * plugin) control_class = slv2_value_new_uri (world, SLV2_PORT_CLASS_CONTROL); input_class = slv2_value_new_uri (world, SLV2_PORT_CLASS_INPUT); output_class = slv2_value_new_uri (world, SLV2_PORT_CLASS_OUTPUT); - integer_prop = - slv2_value_new_uri (world, "http://lv2plug.in/ns/lv2core#integer"); - toggled_prop = - slv2_value_new_uri (world, "http://lv2plug.in/ns/lv2core#toggled"); + +#define NS_LV2 "http://lv2plug.in/ns/lv2core#" +#define NS_PG "http://lv2plug.in/ns/dev/port-groups#" + + integer_prop = slv2_value_new_uri (world, NS_LV2 "integer"); + toggled_prop = slv2_value_new_uri (world, NS_LV2 "toggled"); + in_place_broken_pred = slv2_value_new_uri (world, NS_LV2 "inPlaceBroken"); + in_group_pred = slv2_value_new_uri (world, NS_PG "inGroup"); + has_role_pred = slv2_value_new_uri (world, NS_PG "role"); + lv2_symbol_pred = slv2_value_new_string (world, NS_LV2 "symbol"); + + center_role = slv2_value_new_uri (world, NS_PG "centerChannel"); + left_role = slv2_value_new_uri (world, NS_PG "leftChannel"); + right_role = slv2_value_new_uri (world, NS_PG "rightChannel"); + rear_center_role = slv2_value_new_uri (world, NS_PG "rearCenterChannel"); + rear_left_role = slv2_value_new_uri (world, NS_PG "rearLeftChannel"); + rear_right_role = slv2_value_new_uri (world, NS_PG "rearRightChannel"); + lfe_role = slv2_value_new_uri (world, NS_PG "lfeChannel"); + center_left_role = slv2_value_new_uri (world, NS_PG "centerLeftChannel"); + center_right_role = slv2_value_new_uri (world, NS_PG "centerRightChannel"); + side_left_role = slv2_value_new_uri (world, NS_PG "sideLeftChannel"); + side_right_role = slv2_value_new_uri (world, NS_PG "sideRightChannel"); parent_class = g_type_class_ref (GST_TYPE_SIGNAL_PROCESSOR); |