summaryrefslogtreecommitdiffstats
path: root/ext
diff options
context:
space:
mode:
authorDave Robillard <dave@drobilla.net>2009-04-28 23:24:45 -0400
committerStefan Kost <ensonic@users.sf.net>2009-06-22 22:25:03 +0300
commitea184d72f532e4178221d7aa8881481f7f76798d (patch)
tree5e7a09e3172abcf609097e2e6d061f2f1a8ac652 /ext
parent1d464a7eddeb2a3b2f2d024a4ce121d288ea54db (diff)
downloadgst-plugins-bad-ea184d72f532e4178221d7aa8881481f7f76798d.tar.gz
gst-plugins-bad-ea184d72f532e4178221d7aa8881481f7f76798d.tar.bz2
gst-plugins-bad-ea184d72f532e4178221d7aa8881481f7f76798d.zip
Working LV2 plugin discovery.
- Separate gstsignalprocessor into a separate library (not sure if this is in the right place, but it works for now anyway) - Create LV2 element based on LADSPA element, port most discovery functionality
Diffstat (limited to 'ext')
-rw-r--r--ext/Makefile.am7
-rw-r--r--ext/ladspa/Makefile.am6
-rw-r--r--ext/ladspa/gstladspa.h2
-rw-r--r--ext/ladspa/gstsignalprocessor.c1024
-rw-r--r--ext/ladspa/gstsignalprocessor.h124
-rw-r--r--ext/lv2/Makefile.am9
-rw-r--r--ext/lv2/gstlv2.c588
-rw-r--r--ext/lv2/gstlv2.h76
8 files changed, 684 insertions, 1152 deletions
diff --git a/ext/Makefile.am b/ext/Makefile.am
index f96337f9..8d395057 100644
--- a/ext/Makefile.am
+++ b/ext/Makefile.am
@@ -154,6 +154,12 @@ else
LADSPA_DIR =
endif
+if USE_LV2
+LV2_DIR = lv2
+else
+LV2_DIR =
+endif
+
# if USE_LCS
# LCS_DIR=lcs
# else
@@ -351,6 +357,7 @@ SUBDIRS=\
$(JACK_DIR) \
$(JP2K_DIR) \
$(LADSPA_DIR) \
+ $(LV2_DIR) \
$(LCS_DIR) \
$(LIBFAME_DIR) \
$(LIBMMS_DIR) \
diff --git a/ext/ladspa/Makefile.am b/ext/ladspa/Makefile.am
index 0ea92746..00582ed7 100644
--- a/ext/ladspa/Makefile.am
+++ b/ext/ladspa/Makefile.am
@@ -1,9 +1,9 @@
plugin_LTLIBRARIES = libgstladspa.la
-libgstladspa_la_SOURCES = gstsignalprocessor.c gstladspa.c
+libgstladspa_la_SOURCES = gstladspa.c
libgstladspa_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CONTROLLER_CFLAGS) $(GST_CFLAGS) $(LRDF_CFLAGS)
-libgstladspa_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(LIBM) $(LRDF_LIBS)
+libgstladspa_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(LIBM) $(LRDF_LIBS) ../../gst-libs/gst/signalprocessor/libgstsignalprocessor.la
libgstladspa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstladspa_la_LIBTOOLFLAGS = --tag=disable-static
-noinst_HEADERS = gstsignalprocessor.h gstladspa.h
+noinst_HEADERS = gstladspa.h
diff --git a/ext/ladspa/gstladspa.h b/ext/ladspa/gstladspa.h
index 7ab94791..f51d6233 100644
--- a/ext/ladspa/gstladspa.h
+++ b/ext/ladspa/gstladspa.h
@@ -28,7 +28,7 @@
#include <gst/gst.h>
-#include "gstsignalprocessor.h"
+#include "../../gst-libs/gst/signalprocessor/gstsignalprocessor.h"
G_BEGIN_DECLS
diff --git a/ext/ladspa/gstsignalprocessor.c b/ext/ladspa/gstsignalprocessor.c
deleted file mode 100644
index c46ae7a8..00000000
--- a/ext/ladspa/gstsignalprocessor.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2000 Wim Taymans <wtay@chello.be>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstsignalprocessor.c:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-/*
- * SECTION:gstsignalprocessor
- *
- * This baseclass allows to write elements that need data on all pads before
- * their processing function can run.
- *
- * In push mode (gst_signal_processor_chain) it operates as follows:
- * 1. store each received buffer on the pad and decrement pending_in
- * 2. when pending_in==0, process as much as we can and push outputs
- *
- * In pull mode (gst_signal_processor_getrange) is operates as follows:
- * 1. if there is an output ready, deliver
- * 2. otherwise pull from each sink-pad, process requested frames and deliver
- * the buffer
- */
-
-#include <stdlib.h>
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <gst/audio/audio.h>
-#include "gstsignalprocessor.h"
-
-
-GST_DEBUG_CATEGORY_STATIC (gst_signal_processor_debug);
-#define GST_CAT_DEFAULT gst_signal_processor_debug
-
-/* FIXME: this is mono only */
-static GstStaticCaps template_caps =
-GST_STATIC_CAPS (GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS);
-
-#define GST_TYPE_SIGNAL_PROCESSOR_PAD_TEMPLATE \
- (gst_signal_processor_pad_template_get_type ())
-#define GST_SIGNAL_PROCESSOR_PAD_TEMPLATE(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SIGNAL_PROCESSOR_PAD_TEMPLATE,\
- GstSignalProcessorPadTemplate))
-typedef struct _GstSignalProcessorPadTemplate GstSignalProcessorPadTemplate;
-typedef GstPadTemplateClass GstSignalProcessorPadTemplateClass;
-
-struct _GstSignalProcessorPadTemplate
-{
- GstPadTemplate parent;
-
- guint index;
-};
-
-static GType
-gst_signal_processor_pad_template_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof (GstSignalProcessorPadTemplateClass), NULL, NULL, NULL, NULL,
- NULL, sizeof (GstSignalProcessorPadTemplate), 0, NULL
- };
-
- type = g_type_register_static (GST_TYPE_PAD_TEMPLATE,
- "GstSignalProcessorPadTemplate", &info, 0);
- }
- return type;
-}
-
-/*
- * gst_signal_processor_class_add_pad_template:
- * @klass: element class
- * @name: pad name
- * @direction: pad direction (src/sink)
- * @index: index for the pad per direction (starting from 0)
- *
- */
-void
-gst_signal_processor_class_add_pad_template (GstSignalProcessorClass * klass,
- const gchar * name, GstPadDirection direction, guint index)
-{
- GstPadTemplate *new;
- GstCaps *caps;
-
- g_return_if_fail (GST_IS_SIGNAL_PROCESSOR_CLASS (klass));
- g_return_if_fail (name != NULL);
- g_return_if_fail (direction == GST_PAD_SRC || direction == GST_PAD_SINK);
-
- /* FIXME: would be nice to have the template as a parameter, right now this can
- * only create mono pads */
- caps = gst_caps_copy (gst_static_caps_get (&template_caps));
-
- new = g_object_new (gst_signal_processor_pad_template_get_type (),
- "name", name, "name-template", name,
- "direction", direction, "presence", GST_PAD_ALWAYS, "caps", caps, NULL);
-
- GST_SIGNAL_PROCESSOR_PAD_TEMPLATE (new)->index = index;
-
- gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass), new);
-}
-
-
-#define GST_TYPE_SIGNAL_PROCESSOR_PAD (gst_signal_processor_pad_get_type ())
-#define GST_SIGNAL_PROCESSOR_PAD(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SIGNAL_PROCESSOR_PAD,\
- GstSignalProcessorPad))
-typedef struct _GstSignalProcessorPad GstSignalProcessorPad;
-typedef GstPadClass GstSignalProcessorPadClass;
-
-struct _GstSignalProcessorPad
-{
- GstPad parent;
-
- GstBuffer *pen;
-
- /* index for the pad per direction (starting from 0) */
- guint index;
-
- /* these are only used for sink pads */
- guint samples_avail; /* available mono sample frames */
- gfloat *data; /* data pointer to read from / write to */
-};
-
-static GType
-gst_signal_processor_pad_get_type (void)
-{
- static GType type = 0;
-
- if (!type) {
- static const GTypeInfo info = {
- sizeof (GstSignalProcessorPadClass), NULL, NULL, NULL, NULL,
- NULL, sizeof (GstSignalProcessorPad), 0, NULL
- };
-
- type = g_type_register_static (GST_TYPE_PAD,
- "GstSignalProcessorPad", &info, 0);
- }
- return type;
-}
-
-
-GST_BOILERPLATE (GstSignalProcessor, gst_signal_processor, GstElement,
- GST_TYPE_ELEMENT);
-
-
-static void gst_signal_processor_finalize (GObject * object);
-static gboolean gst_signal_processor_src_activate_pull (GstPad * pad,
- gboolean active);
-static gboolean gst_signal_processor_sink_activate_push (GstPad * pad,
- gboolean active);
-static GstStateChangeReturn gst_signal_processor_change_state (GstElement *
- element, GstStateChange transition);
-
-static gboolean gst_signal_processor_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_signal_processor_getrange (GstPad * pad,
- guint64 offset, guint length, GstBuffer ** buffer);
-static GstFlowReturn gst_signal_processor_chain (GstPad * pad,
- GstBuffer * buffer);
-static gboolean gst_signal_processor_setcaps (GstPad * pad, GstCaps * caps);
-
-
-static void
-gst_signal_processor_base_init (gpointer g_class)
-{
- GST_DEBUG_CATEGORY_INIT (gst_signal_processor_debug, "gst-dsp", 0,
- "signalprocessor element");
-}
-
-static void
-gst_signal_processor_class_init (GstSignalProcessorClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = G_OBJECT_CLASS (klass);
- gstelement_class = GST_ELEMENT_CLASS (klass);
-
- gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_signal_processor_finalize);
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_signal_processor_change_state);
-}
-
-static void
-gst_signal_processor_add_pad_from_template (GstSignalProcessor * self,
- GstPadTemplate * templ)
-{
- GstPad *new;
-
- new = g_object_new (GST_TYPE_SIGNAL_PROCESSOR_PAD,
- "name", GST_OBJECT_NAME (templ), "direction", templ->direction,
- "template", templ, NULL);
- GST_SIGNAL_PROCESSOR_PAD (new)->index =
- GST_SIGNAL_PROCESSOR_PAD_TEMPLATE (templ)->index;
-
- gst_pad_set_setcaps_function (new,
- GST_DEBUG_FUNCPTR (gst_signal_processor_setcaps));
-
- if (templ->direction == GST_PAD_SINK) {
- GST_DEBUG ("added new sink pad");
-
- gst_pad_set_event_function (new,
- GST_DEBUG_FUNCPTR (gst_signal_processor_event));
- gst_pad_set_chain_function (new,
- GST_DEBUG_FUNCPTR (gst_signal_processor_chain));
- gst_pad_set_activatepush_function (new,
- GST_DEBUG_FUNCPTR (gst_signal_processor_sink_activate_push));
- } else {
- GST_DEBUG ("added new src pad");
-
- gst_pad_set_getrange_function (new,
- GST_DEBUG_FUNCPTR (gst_signal_processor_getrange));
- gst_pad_set_activatepull_function (new,
- GST_DEBUG_FUNCPTR (gst_signal_processor_src_activate_pull));
- }
-
- gst_element_add_pad (GST_ELEMENT (self), new);
-}
-
-static void
-gst_signal_processor_init (GstSignalProcessor * self,
- GstSignalProcessorClass * klass)
-{
- GList *templates;
-
- templates =
- gst_element_class_get_pad_template_list (GST_ELEMENT_CLASS (klass));
-
- while (templates) {
- GstPadTemplate *templ = GST_PAD_TEMPLATE (templates->data);
-
- gst_signal_processor_add_pad_from_template (self, templ);
- templates = templates->next;
- }
-
- self->state = GST_SIGNAL_PROCESSOR_STATE_NULL;
-
- self->audio_in = g_new0 (gfloat *, klass->num_audio_in);
- self->control_in = g_new0 (gfloat, klass->num_control_in);
- self->audio_out = g_new0 (gfloat *, klass->num_audio_out);
- self->control_out = g_new0 (gfloat, klass->num_control_out);
-
- /* init */
- self->pending_in = klass->num_audio_in;
- self->pending_out = 0;
-
- self->sample_rate = 0;
-}
-
-static void
-gst_signal_processor_finalize (GObject * object)
-{
- GstSignalProcessor *self = GST_SIGNAL_PROCESSOR (object);
-
- g_free (self->audio_in);
- self->audio_in = NULL;
- g_free (self->control_in);
- self->control_in = NULL;
- g_free (self->audio_out);
- self->audio_out = NULL;
- g_free (self->control_out);
- self->control_out = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static gboolean
-gst_signal_processor_setup (GstSignalProcessor * self, guint sample_rate)
-{
- GstSignalProcessorClass *klass;
- gboolean ret = TRUE;
-
- klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- GST_INFO_OBJECT (self, "setup()");
-
- g_return_val_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_NULL, FALSE);
-
- if (klass->setup)
- ret = klass->setup (self, sample_rate);
-
- if (!ret)
- goto setup_failed;
-
- self->state = GST_SIGNAL_PROCESSOR_STATE_INITIALIZED;
-
- return ret;
-
-setup_failed:
- {
- GST_INFO_OBJECT (self, "setup() failed at %u Hz", sample_rate);
- return ret;
- }
-}
-
-static gboolean
-gst_signal_processor_start (GstSignalProcessor * self)
-{
- GstSignalProcessorClass *klass;
- gboolean ret = TRUE;
-
- klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- g_return_val_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_INITIALIZED,
- FALSE);
-
- GST_INFO_OBJECT (self, "start()");
-
- if (klass->start)
- ret = klass->start (self);
-
- if (!ret)
- goto start_failed;
-
- self->state = GST_SIGNAL_PROCESSOR_STATE_RUNNING;
-
- return ret;
-
-start_failed:
- {
- GST_INFO_OBJECT (self, "start() failed");
- return ret;
- }
-}
-
-static void
-gst_signal_processor_stop (GstSignalProcessor * self)
-{
- GstSignalProcessorClass *klass;
- GstElement *elem;
- GList *sinks;
-
- klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
- elem = GST_ELEMENT (self);
-
- GST_INFO_OBJECT (self, "stop()");
-
- g_return_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_RUNNING);
-
- if (klass->stop)
- klass->stop (self);
-
- for (sinks = elem->sinkpads; sinks; sinks = sinks->next)
- /* force set_caps when going to RUNNING, see note in _setcaps () */
- gst_pad_set_caps (GST_PAD (sinks->data), NULL);
-
- /* should also flush our buffers perhaps? */
-
- self->state = GST_SIGNAL_PROCESSOR_STATE_INITIALIZED;
-}
-
-static void
-gst_signal_processor_cleanup (GstSignalProcessor * self)
-{
- GstSignalProcessorClass *klass;
-
- klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- GST_INFO_OBJECT (self, "cleanup()");
-
- g_return_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_INITIALIZED);
-
- if (klass->cleanup)
- klass->cleanup (self);
-
- self->state = GST_SIGNAL_PROCESSOR_STATE_NULL;
-}
-
-static gboolean
-gst_signal_processor_setcaps_pull (GstSignalProcessor * self, GstPad * pad,
- GstCaps * caps)
-{
- if (GST_PAD_IS_SRC (pad)) {
- GList *l;
-
- for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next)
- if (!gst_pad_set_caps (GST_PAD (l->data), caps))
- goto src_setcaps_failed;
- } else {
- GstPad *peer;
- gboolean res;
-
- peer = gst_pad_get_peer (pad);
- if (!peer)
- goto unlinked_sink;
-
- res = gst_pad_set_caps (peer, caps);
- gst_object_unref (peer);
-
- if (!res)
- goto peer_setcaps_failed;
- }
-
- return TRUE;
-
-src_setcaps_failed:
- {
- /* not logging, presumably the sink pad already logged */
- return FALSE;
- }
-unlinked_sink:
- {
- GST_WARNING_OBJECT (self, "unlinked sink pad %" GST_PTR_FORMAT ", I wonder "
- "how we passed activate_pull()", pad);
- return FALSE;
- }
-peer_setcaps_failed:
- {
- GST_INFO_OBJECT (self, "peer of %" GST_PTR_FORMAT " did not accept caps",
- pad);
- return FALSE;
- }
-}
-
-static gboolean
-gst_signal_processor_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstSignalProcessor *self;
-
- self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
-
- if (self->mode == GST_ACTIVATE_PULL && !gst_caps_is_equal (caps, self->caps)
- && !gst_signal_processor_setcaps_pull (self, pad, caps))
- goto setcaps_pull_failed;
-
- /* the whole processor has one caps; if the sample rate changes, let subclass
- implementations know */
- if (!gst_caps_is_equal (caps, self->caps)) {
- GstStructure *s;
- gint sample_rate;
-
- GST_DEBUG_OBJECT (pad, "got caps %" GST_PTR_FORMAT, caps);
-
- s = gst_caps_get_structure (caps, 0);
- if (!gst_structure_get_int (s, "rate", &sample_rate)) {
- GST_WARNING ("got no sample-rate");
- goto impossible;
- }
-
- GST_DEBUG_OBJECT (self, "Got rate=%d", sample_rate);
-
- if (GST_SIGNAL_PROCESSOR_IS_RUNNING (self))
- gst_signal_processor_stop (self);
- if (GST_SIGNAL_PROCESSOR_IS_INITIALIZED (self))
- gst_signal_processor_cleanup (self);
-
- if (!gst_signal_processor_setup (self, sample_rate))
- goto start_or_setup_failed;
-
- self->sample_rate = sample_rate;
- gst_caps_replace (&self->caps, caps);
- } else {
- GST_DEBUG_OBJECT (self, "skipping, have caps already");
- }
-
- /* we use this method to manage the processor's state, hence the caps clearing
- in stop(). so it can be that we enter here just to manage the processor's
- state, to take it to RUNNING from already being INITIALIZED with the right
- sample rate (e.g., when having gone PLAYING->READY->PLAYING). make sure
- when we leave that the processor is RUNNING. */
- if (!GST_SIGNAL_PROCESSOR_IS_INITIALIZED (self)
- && !gst_signal_processor_setup (self, self->sample_rate))
- goto start_or_setup_failed;
- if (!GST_SIGNAL_PROCESSOR_IS_RUNNING (self)
- && !gst_signal_processor_start (self))
- goto start_or_setup_failed;
-
- gst_object_unref (self);
-
- return TRUE;
-
-start_or_setup_failed:
- {
- gst_object_unref (self);
- return FALSE;
- }
-setcaps_pull_failed:
- {
- gst_object_unref (self);
- return FALSE;
- }
-impossible:
- {
- g_critical ("something impossible happened");
- gst_object_unref (self);
- return FALSE;
- }
-}
-
-static gboolean
-gst_signal_processor_event (GstPad * pad, GstEvent * event)
-{
- GstSignalProcessor *self;
- GstSignalProcessorClass *bclass;
- gboolean ret;
-
- self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
- bclass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- /* FIXME, this probably isn't the correct interface: what about return values,
- * what about overriding event_default
- * Sync with GstBaseTransform::gst_base_transform_sink_event */
- if (bclass->event)
- bclass->event (self, event);
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- break;
- case GST_EVENT_FLUSH_STOP:
- /* clear errors now */
- self->flow_state = GST_FLOW_OK;
- break;
- default:
- break;
- }
- ret = gst_pad_event_default (pad, event);
-
- gst_object_unref (self);
-
- return ret;
-}
-
-static guint
-gst_signal_processor_prepare (GstSignalProcessor * self, guint nframes)
-{
- GstElement *elem = (GstElement *) self;
- GstSignalProcessorClass *klass;
- GList *sinks, *srcs;
- guint samples_avail = nframes;
-
- klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- /* first, assign audio_in pointers, and determine the number of samples that
- * we can process */
- for (sinks = elem->sinkpads; sinks; sinks = sinks->next) {
- GstSignalProcessorPad *sinkpad;
-
- sinkpad = (GstSignalProcessorPad *) sinks->data;
- g_assert (sinkpad->samples_avail > 0);
- samples_avail = MIN (samples_avail, sinkpad->samples_avail);
- self->audio_in[sinkpad->index] = sinkpad->data;
- }
-
- /* FIXME: return if samples_avail==0 ? */
-
- /* now assign output buffers. we can avoid allocation by reusing input
- buffers, but only if process() can work in place, and if the input buffer
- is the exact size of the number of samples we are processing. */
- sinks = elem->sinkpads;
- srcs = elem->srcpads;
- if (GST_SIGNAL_PROCESSOR_CLASS_CAN_PROCESS_IN_PLACE (klass)) {
- while (sinks && srcs) {
- GstSignalProcessorPad *sinkpad, *srcpad;
-
- sinkpad = (GstSignalProcessorPad *) sinks->data;
- srcpad = (GstSignalProcessorPad *) srcs->data;
-
- if (GST_BUFFER_SIZE (sinkpad->pen) == samples_avail * sizeof (gfloat)) {
- /* reusable, yay */
- g_assert (sinkpad->samples_avail == samples_avail);
- srcpad->pen = sinkpad->pen;
- sinkpad->pen = NULL;
- self->audio_out[srcpad->index] = sinkpad->data;
- self->pending_out++;
-
- srcs = srcs->next;
- }
-
- sinks = sinks->next;
- }
- }
-
- g_return_val_if_fail (GST_SIGNAL_PROCESSOR_IS_RUNNING (self), 0);
-
- /* now allocate for any remaining outputs */
- while (srcs) {
- GstSignalProcessorPad *srcpad;
- GstFlowReturn ret;
-
- srcpad = (GstSignalProcessorPad *) srcs->data;
-
- ret =
- gst_pad_alloc_buffer_and_set_caps (GST_PAD (srcpad), -1,
- samples_avail * sizeof (gfloat), self->caps, &srcpad->pen);
-
- if (ret != GST_FLOW_OK) {
- self->flow_state = ret;
- return 0;
- } else {
- self->audio_out[srcpad->index] = (gfloat *) GST_BUFFER_DATA (srcpad->pen);
- self->pending_out++;
- }
-
- srcs = srcs->next;
- }
-
- return samples_avail;
-}
-
-static void
-gst_signal_processor_update_inputs (GstSignalProcessor * self, guint nprocessed)
-{
- GstElement *elem = (GstElement *) self;
- GList *sinks;
-
- for (sinks = elem->sinkpads; sinks; sinks = sinks->next) {
- GstSignalProcessorPad *sinkpad;
-
- sinkpad = (GstSignalProcessorPad *) sinks->data;
- g_assert (sinkpad->samples_avail >= nprocessed);
-
- if (sinkpad->pen && sinkpad->samples_avail == nprocessed) {
- /* used up this buffer, unpen */
- gst_buffer_unref (sinkpad->pen);
- sinkpad->pen = NULL;
- }
-
- if (!sinkpad->pen) {
- /* this buffer was used up */
- self->pending_in++;
- sinkpad->data = NULL;
- sinkpad->samples_avail = 0;
- } else {
- /* advance ->data pointers and decrement ->samples_avail, unreffing buffer
- if no samples are left */
- sinkpad->samples_avail -= nprocessed;
- sinkpad->data += nprocessed; /* gfloat* arithmetic */
- }
- }
-}
-
-static void
-gst_signal_processor_process (GstSignalProcessor * self, guint nframes)
-{
- GstElement *elem;
- GstSignalProcessorClass *klass;
-
- /* check if we have buffers enqueued */
- g_return_if_fail (self->pending_in == 0);
- g_return_if_fail (self->pending_out == 0);
-
- elem = GST_ELEMENT (self);
-
- /* check how much input is available and prepare output buffers */
- nframes = gst_signal_processor_prepare (self, nframes);
- if (G_UNLIKELY (nframes == 0))
- goto flow_error;
-
- klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- GST_LOG_OBJECT (self, "process(%u)", nframes);
-
- klass->process (self, nframes);
-
- gst_signal_processor_update_inputs (self, nframes);
-
- return;
-
-flow_error:
- {
- GST_WARNING ("gst_pad_alloc_buffer_and_set_caps() returned %d",
- self->flow_state);
- return;
- }
-}
-
-static void
-gst_signal_processor_pen_buffer (GstSignalProcessor * self, GstPad * pad,
- GstBuffer * buffer)
-{
- GstSignalProcessorPad *spad = (GstSignalProcessorPad *) pad;
-
- if (spad->pen)
- goto had_buffer;
-
- /* keep the reference */
- spad->pen = buffer;
- spad->data = (gfloat *) GST_BUFFER_DATA (buffer);
- spad->samples_avail = GST_BUFFER_SIZE (buffer) / sizeof (float);
-
- g_assert (self->pending_in != 0);
-
- self->pending_in--;
-
- return;
-
- /* ERRORS */
-had_buffer:
- {
- GST_WARNING ("Pad %s:%s already has penned buffer",
- GST_DEBUG_PAD_NAME (pad));
- gst_buffer_unref (buffer);
- return;
- }
-}
-
-static void
-gst_signal_processor_flush (GstSignalProcessor * self)
-{
- GList *pads;
- GstSignalProcessorClass *klass;
-
- klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- GST_INFO_OBJECT (self, "flush()");
-
- /* release enqueued buffers */
- for (pads = GST_ELEMENT (self)->pads; pads; pads = pads->next) {
- GstSignalProcessorPad *spad = (GstSignalProcessorPad *) pads->data;
-
- if (spad->pen) {
- gst_buffer_unref (spad->pen);
- spad->pen = NULL;
- spad->data = NULL;
- spad->samples_avail = 0;
- }
- }
-
- /* no outputs prepared and inputs for each pad needed */
- self->pending_out = 0;
- self->pending_in = klass->num_audio_in;
-}
-
-static void
-gst_signal_processor_do_pulls (GstSignalProcessor * self, guint nframes)
-{
- GList *sinkpads;
-
- /* FIXME: not threadsafe atm */
-
- sinkpads = GST_ELEMENT (self)->sinkpads;
-
- for (; sinkpads; sinkpads = sinkpads->next) {
- GstSignalProcessorPad *spad = (GstSignalProcessorPad *) sinkpads->data;
- GstFlowReturn ret = GST_FLOW_OK;
- GstBuffer *buf;
-
- if (spad->pen) {
- g_warning ("Unexpectedly full buffer pen for pad %s:%s",
- GST_DEBUG_PAD_NAME (spad));
- continue;
- }
-
- ret =
- gst_pad_pull_range (GST_PAD (spad), -1, nframes * sizeof (gfloat),
- &buf);
-
- if (ret != GST_FLOW_OK) {
- gst_signal_processor_flush (self);
- self->flow_state = ret;
- return;
- } else if (!buf) {
- g_critical ("Pull failed to make a buffer!");
- self->flow_state = GST_FLOW_ERROR;
- return;
- } else {
- gst_signal_processor_pen_buffer (self, GST_PAD (spad), buf);
- }
- }
-
- if (self->pending_in != 0) {
- g_critical ("Something wierd happened...");
- self->flow_state = GST_FLOW_ERROR;
- } else {
- gst_signal_processor_process (self, nframes);
- }
-}
-
-static GstFlowReturn
-gst_signal_processor_getrange (GstPad * pad, guint64 offset,
- guint length, GstBuffer ** buffer)
-{
- GstSignalProcessor *self;
- GstSignalProcessorPad *spad = (GstSignalProcessorPad *) pad;
- GstFlowReturn ret = GST_FLOW_ERROR;
-
- self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
-
- if (spad->pen) {
- *buffer = spad->pen;
- spad->pen = NULL;
- g_assert (self->pending_out != 0);
- self->pending_out--;
- ret = GST_FLOW_OK;
- } else {
- gst_signal_processor_do_pulls (self, length / sizeof (gfloat));
- if (!spad->pen) {
- /* this is an error condition */
- *buffer = NULL;
- ret = self->flow_state;
- } else {
- *buffer = spad->pen;
- spad->pen = NULL;
- self->pending_out--;
- ret = GST_FLOW_OK;
- }
- }
-
- GST_DEBUG_OBJECT (self, "returns %s", gst_flow_get_name (ret));
-
- gst_object_unref (self);
-
- return ret;
-}
-
-static void
-gst_signal_processor_do_pushes (GstSignalProcessor * self)
-{
- GList *srcpads;
-
- /* not threadsafe atm */
-
- srcpads = GST_ELEMENT (self)->srcpads;
-
- for (; srcpads; srcpads = srcpads->next) {
- GstSignalProcessorPad *spad = (GstSignalProcessorPad *) srcpads->data;
- GstFlowReturn ret = GST_FLOW_OK;
- GstBuffer *buffer;
-
- if (!spad->pen) {
- g_warning ("Unexpectedly empty buffer pen for pad %s:%s",
- GST_DEBUG_PAD_NAME (spad));
- continue;
- }
-
- /* take buffer from pen */
- buffer = spad->pen;
- spad->pen = NULL;
-
- ret = gst_pad_push (GST_PAD (spad), buffer);
-
- if (ret != GST_FLOW_OK) {
- gst_signal_processor_flush (self);
- self->flow_state = ret;
- return;
- } else {
- g_assert (self->pending_out > 0);
- self->pending_out--;
- }
- }
-
- if (self->pending_out != 0) {
- g_critical ("Something wierd happened...");
- self->flow_state = GST_FLOW_ERROR;
- }
-}
-
-static GstFlowReturn
-gst_signal_processor_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstSignalProcessor *self;
-
- self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
-
- gst_signal_processor_pen_buffer (self, pad, buffer);
-
- if (self->pending_in == 0) {
- gst_signal_processor_process (self, G_MAXUINT);
-
- gst_signal_processor_do_pushes (self);
- }
-
- gst_object_unref (self);
-
- return self->flow_state;
-}
-
-static gboolean
-gst_signal_processor_sink_activate_push (GstPad * pad, gboolean active)
-{
- gboolean result = TRUE;
- GstSignalProcessor *self;
- GstSignalProcessorClass *bclass;
-
- self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
- bclass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- if (active) {
- if (self->mode == GST_ACTIVATE_NONE) {
- self->mode = GST_ACTIVATE_PUSH;
- result = TRUE;
- } else if (self->mode == GST_ACTIVATE_PUSH) {
- result = TRUE;
- } else {
- g_warning ("foo");
- result = FALSE;
- }
- } else {
- if (self->mode == GST_ACTIVATE_NONE) {
- result = TRUE;
- } else if (self->mode == GST_ACTIVATE_PUSH) {
- self->mode = GST_ACTIVATE_NONE;
- result = TRUE;
- } else {
- g_warning ("foo");
- result = FALSE;
- }
- }
-
- GST_DEBUG_OBJECT (self, "result : %d", result);
-
- gst_object_unref (self);
-
- return result;
-}
-
-static gboolean
-gst_signal_processor_src_activate_pull (GstPad * pad, gboolean active)
-{
- gboolean result = TRUE;
- GstSignalProcessor *self;
- GstSignalProcessorClass *bclass;
-
- self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
- bclass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
-
- if (active) {
- if (self->mode == GST_ACTIVATE_NONE) {
- GList *l;
-
- for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next)
- result &= gst_pad_activate_pull (pad, active);
- if (result)
- self->mode = GST_ACTIVATE_PULL;
- } else if (self->mode == GST_ACTIVATE_PULL) {
- result = TRUE;
- } else {
- g_warning ("foo");
- result = FALSE;
- }
- } else {
- if (self->mode == GST_ACTIVATE_NONE) {
- result = TRUE;
- } else if (self->mode == GST_ACTIVATE_PULL) {
- GList *l;
-
- for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next)
- result &= gst_pad_activate_pull (pad, active);
- if (result)
- self->mode = GST_ACTIVATE_NONE;
- result = TRUE;
- } else {
- g_warning ("foo");
- result = FALSE;
- }
- }
-
- GST_DEBUG_OBJECT (self, "result : %d", result);
-
- gst_object_unref (self);
-
- return result;
-}
-
-static GstStateChangeReturn
-gst_signal_processor_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstSignalProcessor *self;
- GstStateChangeReturn result;
-
- self = GST_SIGNAL_PROCESSOR (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- self->flow_state = GST_FLOW_OK;
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- break;
- default:
- break;
- }
-
- if ((result =
- GST_ELEMENT_CLASS (parent_class)->change_state (element,
- transition)) == GST_STATE_CHANGE_FAILURE)
- goto failure;
-
- switch (transition) {
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- if (GST_SIGNAL_PROCESSOR_IS_RUNNING (self))
- gst_signal_processor_stop (self);
- gst_signal_processor_flush (self);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- if (GST_SIGNAL_PROCESSOR_IS_INITIALIZED (self))
- gst_signal_processor_cleanup (self);
- break;
- default:
- break;
- }
-
- return result;
-
- /* ERRORS */
-failure:
- {
- GST_DEBUG_OBJECT (element, "parent failed state change");
- return result;
- }
-}
diff --git a/ext/ladspa/gstsignalprocessor.h b/ext/ladspa/gstsignalprocessor.h
deleted file mode 100644
index d6f0d0b0..00000000
--- a/ext/ladspa/gstsignalprocessor.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstsignalprocessor.h:
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
- */
-
-
-#ifndef __GST_SIGNAL_PROCESSOR_H__
-#define __GST_SIGNAL_PROCESSOR_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-
-typedef enum
-{
- GST_SIGNAL_PROCESSOR_CLASS_FLAG_CAN_PROCESS_IN_PLACE = 1<<0
-} GstSignalProcessorClassFlags;
-
-#define GST_SIGNAL_PROCESSOR_CLASS_CAN_PROCESS_IN_PLACE(klass) \
- (GST_SIGNAL_PROCESSOR_CLASS (klass)->flags & \
- GST_SIGNAL_PROCESSOR_CLASS_FLAG_CAN_PROCESS_IN_PLACE)
-#define GST_SIGNAL_PROCESSOR_CLASS_SET_CAN_PROCESS_IN_PLACE(klass) \
- GST_SIGNAL_PROCESSOR_CLASS (klass)->flags |= \
- GST_SIGNAL_PROCESSOR_CLASS_FLAG_CAN_PROCESS_IN_PLACE
-
-typedef enum
-{
- GST_SIGNAL_PROCESSOR_STATE_NULL,
- GST_SIGNAL_PROCESSOR_STATE_INITIALIZED,
- GST_SIGNAL_PROCESSOR_STATE_RUNNING
-} GstSignalProcessorState;
-
-
-#define GST_TYPE_SIGNAL_PROCESSOR (gst_signal_processor_get_type())
-#define GST_SIGNAL_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SIGNAL_PROCESSOR,GstSignalProcessor))
-#define GST_SIGNAL_PROCESSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SIGNAL_PROCESSOR,GstSignalProcessorClass))
-#define GST_SIGNAL_PROCESSOR_GET_CLASS(obj) \
- (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_SIGNAL_PROCESSOR,GstSignalProcessorClass))
-#define GST_IS_SIGNAL_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SIGNAL_PROCESSOR))
-#define GST_IS_SIGNAL_PROCESSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SIGNAL_PROCESSOR))
-
-#define GST_SIGNAL_PROCESSOR_IS_INITIALIZED(obj) \
- (GST_SIGNAL_PROCESSOR (obj)->state >= GST_SIGNAL_PROCESSOR_STATE_INITIALIZED)
-#define GST_SIGNAL_PROCESSOR_IS_RUNNING(obj) \
- (GST_SIGNAL_PROCESSOR (obj)->state == GST_SIGNAL_PROCESSOR_STATE_RUNNING)
-
-typedef struct _GstSignalProcessor GstSignalProcessor;
-typedef struct _GstSignalProcessorClass GstSignalProcessorClass;
-
-
-struct _GstSignalProcessor {
- GstElement element;
-
- GstCaps *caps;
-
- guint sample_rate;
-
- GstSignalProcessorState state;
-
- GstFlowReturn flow_state;
-
- GstActivateMode mode;
-
- /* pending inputs before processing can take place */
- guint pending_in;
- /* panding outputs to be filled */
- guint pending_out;
-
- gfloat *control_in;
- gfloat **audio_in;
- gfloat *control_out;
- gfloat **audio_out;
-};
-
-struct _GstSignalProcessorClass {
- GstElementClass parent_class;
-
- /*< public >*/
- guint num_control_in;
- guint num_audio_in;
- guint num_control_out;
- guint num_audio_out;
-
- guint flags;
-
- /* virtual methods for subclasses */
-
- gboolean (*setup) (GstSignalProcessor *self, guint sample_rate);
- gboolean (*start) (GstSignalProcessor *self);
- void (*stop) (GstSignalProcessor *self);
- void (*cleanup) (GstSignalProcessor *self);
- void (*process) (GstSignalProcessor *self, guint num_frames);
- gboolean (*event) (GstSignalProcessor *self, GstEvent *event);
-};
-
-
-GType gst_signal_processor_get_type (void);
-void gst_signal_processor_class_add_pad_template (GstSignalProcessorClass *klass,
- const gchar *name, GstPadDirection direction, guint index);
-
-
-
-G_END_DECLS
-
-
-#endif /* __GST_SIGNAL_PROCESSOR_H__ */
diff --git a/ext/lv2/Makefile.am b/ext/lv2/Makefile.am
new file mode 100644
index 00000000..f10c7acf
--- /dev/null
+++ b/ext/lv2/Makefile.am
@@ -0,0 +1,9 @@
+plugin_LTLIBRARIES = libgstlv2.la
+
+libgstlv2_la_SOURCES = gstlv2.c
+libgstlv2_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CONTROLLER_CFLAGS) $(GST_CFLAGS) $(SLV2_CFLAGS)
+libgstlv2_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR) $(LIBM) $(SLV2_LIBS) ../../gst-libs/gst/signalprocessor/libgstsignalprocessor.la
+libgstlv2_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstlv2_la_LIBTOOLFLAGS = --tag=disable-static
+
+noinst_HEADERS = gstlv2.h
diff --git a/ext/lv2/gstlv2.c b/ext/lv2/gstlv2.c
new file mode 100644
index 00000000..5d05f603
--- /dev/null
+++ b/ext/lv2/gstlv2.c
@@ -0,0 +1,588 @@
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
+ * 2003 Andy Wingo <wingo at pobox.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string.h>
+#include <math.h>
+#include <gst/audio/audio.h>
+#include <gst/controller/gstcontroller.h>
+
+#include "gstlv2.h"
+#include <slv2/slv2.h>
+
+#define GST_SLV2_PLUGIN_QDATA g_quark_from_static_string("slv2-plugin")
+
+static void gst_lv2_set_property (GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+
+static void gst_lv2_get_property (GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+static gboolean gst_lv2_setup (GstSignalProcessor * sigproc, guint sample_rate);
+static gboolean gst_lv2_start (GstSignalProcessor * sigproc);
+static void gst_lv2_stop (GstSignalProcessor * sigproc);
+static void gst_lv2_cleanup (GstSignalProcessor * sigproc);
+static void gst_lv2_process (GstSignalProcessor * sigproc, guint nframes);
+
+static SLV2World world;
+SLV2Value audio_class;
+SLV2Value control_class;
+SLV2Value input_class;
+SLV2Value output_class;
+SLV2Value integer_prop;
+SLV2Value toggled_prop;
+
+static GstSignalProcessorClass *parent_class;
+
+static GstPlugin *gst_lv2_plugin;
+
+GST_DEBUG_CATEGORY_STATIC (lv2_debug);
+#define GST_CAT_DEFAULT lv2_debug
+
+
+static void
+gst_lv2_base_init (gpointer g_class)
+{
+ GstLV2Class *klass = (GstLV2Class *) g_class;
+ GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
+ GstSignalProcessorClass *gsp_class = GST_SIGNAL_PROCESSOR_CLASS (g_class);
+ GstElementDetails *details;
+ SLV2Plugin lv2plugin;
+ SLV2Value val;
+ guint j, audio_in_count, audio_out_count, control_in_count, control_out_count;
+ gchar *klass_tags;
+
+ GST_DEBUG ("base_init %p", g_class);
+
+ lv2plugin = (SLV2Plugin) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
+ GST_SLV2_PLUGIN_QDATA);
+
+ g_assert (lv2plugin);
+
+ /* pad templates */
+ 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;
+
+ 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 */
+ }
+ /* TODO: else ignore plugin */
+ }
+
+ /* construct the element details struct */
+ details = g_new0 (GstElementDetails, 1);
+ val = slv2_plugin_get_name (lv2plugin);
+ if (val) {
+ details->longname = g_strdup (slv2_value_as_string (val));
+ slv2_value_free (val);
+ } else {
+ details->longname = g_strdup ("no description available");
+ }
+ details->description = details->longname;
+ val = slv2_plugin_get_author_name (lv2plugin);
+ if (val) {
+ details->author = g_strdup (slv2_value_as_string (val));
+ slv2_value_free (val);
+ } else {
+ details->author = g_strdup ("no author available");
+ }
+
+ if (gsp_class->num_audio_in == 0)
+ klass_tags = "Source/Audio/LV2";
+ else if (gsp_class->num_audio_out == 0) {
+ if (gsp_class->num_control_out == 0)
+ klass_tags = "Sink/Audio/LV2";
+ else
+ klass_tags = "Sink/Analyzer/Audio/LV2";
+ } else
+ klass_tags = "Filter/Effect/Audio/LV2";
+
+ details->klass = klass_tags;
+ GST_INFO ("tags : %s", details->klass);
+ gst_element_class_set_details (element_class, details);
+ g_free (details->longname);
+ 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); */
+
+ klass->plugin = lv2plugin;
+}
+
+static gchar *
+gst_lv2_class_get_param_name (GstLV2Class * klass, gint portnum)
+{
+ SLV2Plugin lv2plugin = klass->plugin;
+ SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, portnum);
+ return g_strdup (slv2_value_as_string (slv2_port_get_symbol (lv2plugin,
+ port)));
+}
+
+static GParamSpec *
+gst_lv2_class_get_param_spec (GstLV2Class * klass, gint portnum)
+{
+ SLV2Plugin lv2plugin = klass->plugin;
+ SLV2Port port = slv2_plugin_get_port_by_index (lv2plugin, portnum);
+ SLV2Value lv2def, lv2min, lv2max;
+ GParamSpec *ret;
+ gchar *name;
+ gint perms;
+ gfloat lower = 0.0f, upper = 1.0f, def = 0.0f;
+
+ name = gst_lv2_class_get_param_name (klass, portnum);
+ perms = G_PARAM_READABLE;
+ if (slv2_port_is_a (lv2plugin, port, input_class))
+ perms |= G_PARAM_WRITABLE | G_PARAM_CONSTRUCT;
+ if (slv2_port_is_a (lv2plugin, port, control_class))
+ perms |= GST_PARAM_CONTROLLABLE;
+
+ if (slv2_port_has_property (lv2plugin, port, toggled_prop)) {
+ ret = g_param_spec_boolean (name, name, name, FALSE, perms);
+ g_free (name);
+ return ret;
+ }
+
+ slv2_port_get_range (lv2plugin, port, &lv2def, &lv2min, &lv2max);
+
+ if (lv2def)
+ def = slv2_value_as_float (lv2def);
+ if (lv2min)
+ lower = slv2_value_as_float (lv2min);
+ if (lv2max)
+ upper = slv2_value_as_float (lv2max);
+
+ if (def < lower) {
+ fprintf (stderr, "ERROR: %s BAD LOWER %f > %f\n",
+ slv2_value_as_string (slv2_plugin_get_uri (lv2plugin)), lower, def);
+ lower = def;
+ }
+
+ if (def > upper) {
+ fprintf (stderr, "ERROR: %s BAD UPPER %f < %f\n",
+ slv2_value_as_string (slv2_plugin_get_uri (lv2plugin)), upper, def);
+ upper = def;
+ }
+
+ if (slv2_port_has_property (lv2plugin, port, integer_prop))
+ ret = g_param_spec_int (name, name, name, lower, upper, def, perms);
+ else
+ ret = g_param_spec_float (name, name, name, lower, upper, def, perms);
+
+ g_free (name);
+
+ return ret;
+}
+
+static void
+gst_lv2_class_init (GstLV2Class * klass, SLV2Plugin lv2plugin)
+{
+ GObjectClass *gobject_class;
+ GstSignalProcessorClass *gsp_class;
+ gint i;
+
+ GST_DEBUG ("class_init %p", klass);
+
+ gobject_class = (GObjectClass *) klass;
+ gobject_class->set_property = gst_lv2_set_property;
+ gobject_class->get_property = gst_lv2_get_property;
+
+ gsp_class = GST_SIGNAL_PROCESSOR_CLASS (klass);
+ gsp_class->setup = gst_lv2_setup;
+ gsp_class->start = gst_lv2_start;
+ gsp_class->stop = gst_lv2_stop;
+ gsp_class->cleanup = gst_lv2_cleanup;
+ gsp_class->process = gst_lv2_process;
+
+ klass->plugin = lv2plugin;
+
+ /* register properties */
+
+ 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]);
+
+ /* properties have an offset of 1 */
+ g_object_class_install_property (G_OBJECT_CLASS (klass), i + 1, p);
+ }
+
+ 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]);
+
+ /* properties have an offset of 1, and we already added num_control_in */
+ g_object_class_install_property (G_OBJECT_CLASS (klass),
+ gsp_class->num_control_in + i + 1, p);
+ }
+}
+
+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;
+
+ gsp = GST_SIGNAL_PROCESSOR (object);
+ gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (object);
+
+ /* remember, properties have an offset of 1 */
+ prop_id--;
+
+ /* only input ports */
+ g_return_if_fail (prop_id < gsp_class->num_control_in);
+
+ /* 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;
+ break;
+ case G_TYPE_INT:
+ gsp->control_in[prop_id] = g_value_get_int (value);
+ break;
+ case G_TYPE_FLOAT:
+ gsp->control_in[prop_id] = g_value_get_float (value);
+ break;
+ 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;
+
+ gsp = GST_SIGNAL_PROCESSOR (object);
+ gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (object);
+
+ /* remember, properties have an offset of 1 */
+ prop_id--;
+
+ if (prop_id < gsp_class->num_control_in) {
+ controls = gsp->control_in;
+ } else if (prop_id < gsp_class->num_control_in + gsp_class->num_control_out) {
+ controls = gsp->control_out;
+ prop_id -= gsp_class->num_control_in;
+ } else {
+ g_return_if_reached ();
+ }
+
+ /* now see what type it is */
+ switch (pspec->value_type) {
+ case G_TYPE_BOOLEAN:
+ g_value_set_boolean (value, controls[prop_id] > 0.5);
+ break;
+ case G_TYPE_INT:
+ g_value_set_int (value, CLAMP (controls[prop_id], G_MININT, G_MAXINT));
+ break;
+ case G_TYPE_FLOAT:
+ g_value_set_float (value, controls[prop_id]);
+ break;
+ default:
+ g_return_if_reached ();
+ }
+#endif
+}
+
+static gboolean
+gst_lv2_setup (GstSignalProcessor * gsp, guint sample_rate)
+{
+#if 0
+ GstLV2 *ladspa;
+ GstLV2Class *oclass;
+ GstSignalProcessorClass *gsp_class;
+ LV2_Descriptor *desc;
+ int i;
+
+ gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (gsp);
+ ladspa = (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);
+
+ GST_DEBUG_OBJECT (ladspa, "instantiating the plugin at %d Hz", sample_rate);
+
+ ladspa->handle = desc->instantiate (desc, sample_rate);
+
+ g_return_val_if_fail (ladspa->handle != 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]));
+ 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
+ return TRUE;
+}
+
+static gboolean
+gst_lv2_start (GstSignalProcessor * gsp)
+{
+#if 0
+ GstLV2 *ladspa;
+ LV2_Descriptor *desc;
+
+ ladspa = (GstLV2 *) gsp;
+ desc = ladspa->descriptor;
+
+ g_return_val_if_fail (ladspa->activated == FALSE, FALSE);
+ g_return_val_if_fail (ladspa->handle != NULL, FALSE);
+
+ GST_DEBUG_OBJECT (ladspa, "activating");
+
+ if (desc->activate)
+ desc->activate (ladspa->handle);
+
+ ladspa->activated = TRUE;
+#endif
+
+ return TRUE;
+}
+
+static void
+gst_lv2_stop (GstSignalProcessor * gsp)
+{
+#if 0
+ GstLV2 *ladspa;
+ LV2_Descriptor *desc;
+
+ ladspa = (GstLV2 *) gsp;
+ desc = ladspa->descriptor;
+
+ g_return_if_fail (ladspa->activated == TRUE);
+ g_return_if_fail (ladspa->handle != NULL);
+
+ GST_DEBUG_OBJECT (ladspa, "deactivating");
+
+ if (desc->activate)
+ desc->activate (ladspa->handle);
+
+ ladspa->activated = FALSE;
+#endif
+}
+
+static void
+gst_lv2_cleanup (GstSignalProcessor * gsp)
+{
+#if 0
+ GstLV2 *ladspa;
+ LV2_Descriptor *desc;
+
+ ladspa = (GstLV2 *) gsp;
+ desc = ladspa->descriptor;
+
+ g_return_if_fail (ladspa->activated == FALSE);
+ g_return_if_fail (ladspa->handle != NULL);
+
+ GST_DEBUG_OBJECT (ladspa, "cleaning up");
+
+ if (desc->cleanup)
+ desc->cleanup (ladspa->handle);
+
+ ladspa->handle = NULL;
+#endif
+}
+
+static void
+gst_lv2_process (GstSignalProcessor * gsp, guint nframes)
+{
+#if 0
+ GstSignalProcessorClass *gsp_class;
+ GstLV2 *ladspa;
+ GstLV2Class *oclass;
+ LV2_Descriptor *desc;
+ guint i;
+
+ gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (gsp);
+ ladspa = (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],
+ gsp->audio_in[i]);
+ for (i = 0; i < gsp_class->num_audio_out; i++)
+ desc->connect_port (ladspa->handle, oclass->audio_out_portnums[i],
+ gsp->audio_out[i]);
+
+ desc->run (ladspa->handle, nframes);
+#endif
+}
+
+/* search the plugin path
+ */
+static gboolean
+lv2_plugin_discover (void)
+{
+ unsigned 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);
+ GTypeInfo typeinfo = {
+ sizeof (GstLV2Class),
+ (GBaseInitFunc) gst_lv2_base_init,
+ NULL,
+ (GClassInitFunc) gst_lv2_class_init,
+ NULL,
+ lv2plugin,
+ sizeof (GstLV2),
+ 0,
+ (GInstanceInitFunc) gst_lv2_init,
+ };
+
+ GType type;
+
+ /* construct the type name from plugin URI */
+ gchar *type_name = g_strdup_printf ("%s",
+ slv2_value_as_uri (slv2_plugin_get_uri (lv2plugin)));
+ g_strcanon (type_name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-+", '-');
+
+ /* if it's already registered, drop it */
+ if (g_type_from_name (type_name))
+ goto next;
+
+ /* create the type */
+ type =
+ g_type_register_static (GST_TYPE_SIGNAL_PROCESSOR, type_name, &typeinfo,
+ 0);
+
+ /* FIXME: not needed anymore when we can add pad templates, etc in class_init
+ * as class_data contains the LADSPA_Descriptor too */
+ g_type_set_qdata (type, GST_SLV2_PLUGIN_QDATA, (gpointer) lv2plugin);
+
+ if (!gst_element_register (gst_lv2_plugin, type_name, GST_RANK_NONE, type))
+ goto next;
+
+ next:
+ g_free (type_name);
+ }
+ return TRUE;
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+ GST_DEBUG_CATEGORY_INIT (lv2_debug, "lv2",
+ GST_DEBUG_FG_GREEN | GST_DEBUG_BG_BLACK | GST_DEBUG_BOLD, "LV2");
+
+ world = slv2_world_new ();
+ slv2_world_load_all (world);
+
+ audio_class = slv2_value_new_uri (world, SLV2_PORT_CLASS_AUDIO);
+ 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");
+
+ parent_class = g_type_class_ref (GST_TYPE_SIGNAL_PROCESSOR);
+
+ gst_lv2_plugin = plugin;
+
+ return lv2_plugin_discover ();
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "lv2",
+ "All LV2 plugins",
+ plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
diff --git a/ext/lv2/gstlv2.h b/ext/lv2/gstlv2.h
new file mode 100644
index 00000000..f76235b4
--- /dev/null
+++ b/ext/lv2/gstlv2.h
@@ -0,0 +1,76 @@
+/* GStreamer
+ * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * gstladspa.h: Header for LV2 plugin
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+#ifndef __GST_LV2_H__
+#define __GST_LV2_H__
+
+
+#include <slv2/slv2.h>
+
+#include <gst/gst.h>
+
+#include "../../gst-libs/gst/signalprocessor/gstsignalprocessor.h"
+
+
+G_BEGIN_DECLS
+
+
+typedef struct _lv2_control_info {
+ gchar *name;
+ gchar *param_name;
+ gfloat lowerbound, upperbound;
+ gfloat def;
+ gboolean lower, upper, samplerate;
+ gboolean toggled, logarithmic, integer, writable;
+} lv2_control_info;
+
+
+typedef struct _GstLV2 GstLV2;
+typedef struct _GstLV2Class GstLV2Class;
+
+
+struct _GstLV2 {
+ GstSignalProcessor parent;
+
+ SLV2Plugin *plugin;
+ SLV2Instance *instance;
+
+ gboolean activated;
+ gboolean inplace_broken;
+};
+
+struct _GstLV2Class {
+ GstSignalProcessorClass parent_class;
+
+ SLV2Plugin plugin;
+
+ gint *audio_in_portnums;
+ gint *audio_out_portnums;
+ gint *control_in_portnums;
+ gint *control_out_portnums;
+};
+
+
+G_END_DECLS
+
+
+#endif /* __GST_LV2_H__ */