videomeasure videosignal vmnc \
linsys vcd \
apexsink cdaudio dc1394 dirac directfb \
- gsettings ladspa \
+ gsettings \
musepack musicbrainz nas neon ofa openal sdl sndfile timidity \
directdraw direct3d9 acm wininet \
xvid lv2 teletextdec sndio osx_video quicktime"
plugin_LTLIBRARIES = libgstladspa.la
-libgstladspa_la_SOURCES = gstladspa.c
+libgstladspa_la_SOURCES = \
+ gstladspautils.c \
+ gstladspafilter.c \
+ gstladspasource.c \
+ gstladspasink.c \
+ gstladspa.c
libgstladspa_la_CFLAGS = \
-I$(top_srcdir)/gst-libs \
$(GST_PLUGINS_BASE_CFLAGS) \
- $(GST_CFLAGS) $(LRDF_CFLAGS)
+ $(GST_BASE_CFLAGS) \
+ $(GST_CFLAGS) \
+ $(LRDF_CFLAGS) \
+ $(GST_PLUGINS_BAD_CFLAGS)
libgstladspa_la_LIBADD = \
- $(top_builddir)/gst-libs/gst/signalprocessor/libgstsignalprocessor-@GST_API_VERSION@.la \
- $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_API_VERSION) \
- $(LIBM) $(LRDF_LIBS)
+ $(GST_PLUGINS_BASE_LIBS) \
+ -lgstaudio-$(GST_API_VERSION) \
+ $(GST_BASE_LIBS) \
+ $(GST_LIBS) \
+ $(LIBM) \
+ $(LRDF_LIBS) \
+ $(GST_LIBS)
libgstladspa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
libgstladspa_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
-noinst_HEADERS = gstladspa.h
+noinst_HEADERS = \
+ gstladspautils.h \
+ gstladspafilter.h \
+ gstladspasource.h \
+ gstladspasink.h \
+ gstladspa.h
-/* GStreamer
+/* GStreamer LADSPA plugin
* Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
* 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
* 2003 Andy Wingo <wingo at pobox.com>
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
+
/**
* SECTION:element-ladspa
- * @short_description: bridge for ladspa (Linux Audio Developer's Simple Plugin API)
+ * @short_description: bridge for LADSPA (Linux Audio Developer's Simple Plugin API)
+ * @see_also: #GstAudioConvert #GstAudioResample, #GstAudioTestSrc, #GstAutoAudioSink
+ *
+ * The LADSPA (Linux Audio Developer's Simple Plugin API) element is a bridge
+ * for plugins using the <ulink url="http://www.ladspa.org/">LADSPA</ulink> API.
+ * It scans all installed LADSPA plugins and registers them as gstreamer
+ * elements. If available it can also parse LRDF files and use the metadata for
+ * element classification. The functionality you get depends on the LADSPA plugins
+ * you have installed.
*
- * The ladspa (Linux Audio Developer's Simple Plugin API) element is a bridge
- * for plugins using the <ulink url="http://www.ladspa.org/">ladspa</ulink> API.
- * It scans all installed ladspa plugins and registers them as gstreamer
- * elements. If available it can also parse lrdf files and use the metadata for
- * element classification.
+ * First off all you can apply not live LADSPA filters without this plugin:
+ *
+ * <refsect2>
+ * <title>Example LADSPA line without this plugins</title>
+ * |[
+ * (padsp) listplugins
+ * (padsp) analyseplugin cmt.so amp_mono
+ * gst-launch -e filesrc location="$myfile" ! decodebin ! audioconvert ! audioresample ! "audio/x-raw,format=S16LE,rate=48000,channels=1" ! wavenc ! filesink location="testin.wav"
+ * (padsp) applyplugin testin.wav testout.wav cmt.so amp_mono 2
+ * gst-launch playbin uri=file://"$PWD"/testout.wav
+ * ]| Decode any audio file into wav with the format expected for the specific ladspa plugin to be applied, apply the ladspa filter and play it.
+ * </refsect2>
+ *
+ * Now with this plugin:
+ *
+ * <refsect2>
+ * <title>Example LADSPA line with this plugins</title>
+ * |[
+ * gst-launch autoaudiosrc ! ladspa-cmt-so-amp-mono gain=2 ! ladspa-caps-so-plate ! ladspa-tap-echo-so-tap-stereo-echo l-delay=500 r-haas-delay=500 ! tee name=myT myT. ! queue ! autoaudiosink myT. ! queue ! audioconvert ! goom ! videoconvert ! xvimagesink pixel-aspect-ratio=3/4
+ * ]| Get audio input, filter it through CAPS Plate and TAP Stereo Echo, play it and show a visualization (recommended hearphones).
+ * </refsect2>
+ *
+ * In case you wonder the plugin naming scheme, quoting ladspa.h:
+ * "Plugin types should be identified by file and label rather than by
+ * index or plugin name, which may be changed in new plugin versions."
+ * This is really the best way then, and so it is less prone to conflicts.
+ *
+ * Also it is worth noting that LADSPA provides a control in and out interface,
+ * on top of the audio in and out one, so some parameters are readable too.
+ *
+ * You can see the listing of plugins available with:
+ * <refsect2>
+ * <title>Inspecting the plugins list</title>
+ * |[
+ * gst-inspect ladspa
+ * ]| List available LADSPA plugins on gstreamer.
+ * </refsect2>
+ *
+ * You can see the parameters of any plugin with:
+ * <refsect2>
+ * <title>Inspecting the plugins</title>
+ * |[
+ * gst-inspect ladspa-retro-flange-1208-so-retroFlange
+ * ]| List details of the plugin, parameters, range and defaults included.
+ * </refsect2>
+ *
+ * The elements categorize in:
+ * <itemizedlist>
+ * <listitem><para>Filter/Effect/Audio/LADSPA:</para>
+ * <refsect2>
+ * <title>Example Filter/Effect/Audio/LADSPA line with this plugins</title>
+ * |[
+ * gst-launch filesrc location="$myfile" ! decodebin ! audioconvert ! audioresample ! ladspa-calf-so-reverb decay-time=15 high-frq-damp=20000 room-size=5 diffusion=1 wet-amount=2 dry-amount=2 pre-delay=50 bass-cut=20000 treble-cut=20000 ! ladspa-tap-echo-so-tap-stereo-echo l-delay=500 r-haas-delay=500 ! autoaudiosink
+ * ]| Decode any audio file, filter it through Calf Reverb LADSPA then TAP Stereo Echo, and play it.
+ * </refsect2>
+ * <refsect2>
+ * </listitem>
+ * <listitem><para>Source/Audio/LADSPA:</para>
+ * <refsect2>
+ * <title>Example Source/Audio/LADSPA line with this plugins</title>
+ * |[
+ * gst-launch -e ladspasrc-sine-so-sine-fcac frequency=220 amplitude=100 ! audioconvert ! "audio/x-raw,rate=22050" ! autoaudiosink
+ * ]| Generate a sine wave with Sine Oscillator (Freq:control, Amp:control), convert it to 22050 Hz and play it.
+ * </refsect2>
+ * <refsect2>
+ * <title>Example Source/Audio/LADSPA line with this plugins</title>
+ * |[
+ * gst-launch -e ladspasrc-caps-so-click bpm=240 volume=1 ! autoaudiosink
+ * ]| Generate clicks with CAPS Click - Metronome at 240 beats per minute and play it.
+ * </refsect2>
+ * <refsect2>
+ * <title>Example Source/Audio/LADSPA line with this plugins</title>
+ * |[
+ * gst-launch -e ladspasrc-random-1661-so-random-fcsc-oa ! ladspa-cmt-so-amp-mono gain=1.5 ! ladspa-caps-so-plate ! tee name=myT myT. ! queue ! autoaudiosink myT. ! queue ! audioconvert ! wavescope ! videoconvert ! autovideosink
+ * ]| Generate random wave, filter it trhough Mono Amplifier and Versatile Plate Reverb, and play, while showing, it.
+ * </refsect2>
+ * </listitem>
+ * <listitem><para>Sink/Audio/LADSPA:</para>
+ * <refsect2>
+ * <title>Example Sink/Audio/LADSPA line with this plugins</title>
+ * |[
+ * gst-launch -e autoaudiosrc ! ladspa-cmt-so-amp-mono gain=2 ! ladspa-caps-so-plate ! ladspa-tap-echo-so-tap-stereo-echo l-delay=500 r-haas-delay=500 ! tee name=myT myT. ! audioconvert ! audioresample ! queue ! ladspasink-cmt-so-null-ai myT. ! audioconvert ! audioresample ! queue ! goom ! videoconvert ! xvimagesink pixel-aspect-ratio=3/4
+ * ]| Get audio input, filter it trhough Mono Amplifier, CAPS Plate LADSPA and TAP Stereo Echo, explicitily anulate audio with Null (Audio Input), and play a visualization (recommended hearphones).
+ * </refsect2>
+ * </listitem>
+ * </itemizedlist>
*/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
-#include <string.h>
-#include <math.h>
-#include <gst/audio/audio.h>
-#include "gstladspa.h"
-#include <ladspa.h> /* main ladspa sdk include file */
+#include "gstladspautils.h"
+#include "gstladspafilter.h"
+#include "gstladspasource.h"
+#include "gstladspasink.h"
+#include <gst/gst-i18n-plugin.h>
+
+#include <gmodule.h>
+#include <string.h>
+#include <ladspa.h>
#ifdef HAVE_LRDF
#include <lrdf.h>
#endif
-/* 1.0 and the 1.1 preliminary headers don't define a version, but 1.1 final
- does */
+GST_DEBUG_CATEGORY (ladspa_debug);
+#define GST_CAT_DEFAULT ladspa_debug
+
+/*
+ * 1.0 and the 1.1 preliminary headers don't define a version, but
+ * 1.1 finally does
+ */
#ifndef LADSPA_VERSION
#define LADSPA_VERSION "1.0"
#endif
"/usr/local/lib/ladspa" G_SEARCHPATH_SEPARATOR_S \
LIBDIR "/ladspa"
-static void gst_ladspa_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_ladspa_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static gboolean gst_ladspa_setup (GstSignalProcessor * sigproc, GstCaps * caps);
-static gboolean gst_ladspa_start (GstSignalProcessor * sigproc);
-static void gst_ladspa_stop (GstSignalProcessor * sigproc);
-static void gst_ladspa_cleanup (GstSignalProcessor * sigproc);
-static void gst_ladspa_process (GstSignalProcessor * sigproc, guint nframes);
-
-static GstSignalProcessorClass *parent_class;
-
-static GstPlugin *ladspa_plugin;
-
-GST_DEBUG_CATEGORY_STATIC (ladspa_debug);
-#define GST_CAT_DEFAULT ladspa_debug
-
-static GQuark descriptor_quark = 0;
-
-
-static void
-gst_ladspa_base_init (gpointer g_class)
-{
- GstLADSPAClass *klass = (GstLADSPAClass *) g_class;
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
- GstSignalProcessorClass *gsp_class = GST_SIGNAL_PROCESSOR_CLASS (g_class);
- LADSPA_Descriptor *desc;
- guint j, audio_in_count, audio_out_count, control_in_count, control_out_count;
- const gchar *klass_tags;
- gchar *longname, *author;
-#ifdef HAVE_LRDF
- gchar *uri;
-#endif
- gchar *extra_klass_tags = NULL;
-
- GST_DEBUG ("base_init %p", g_class);
-
- desc = (LADSPA_Descriptor *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
- descriptor_quark);
- g_assert (desc);
- klass->descriptor = desc;
-
- /* 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 < desc->PortCount; j++) {
- LADSPA_PortDescriptor p = desc->PortDescriptors[j];
-
- if (LADSPA_IS_PORT_AUDIO (p)) {
- gchar *name = g_strdup ((gchar *) desc->PortNames[j]);
-
- /* FIXME: group stereo pairs into a stereo pad
- * ladspa-fx have "XXX (Left)" and "XXX (Right)"
- * where XXX={In,Input,Out,Output}
- */
-
- GST_DEBUG ("LADSPA port name: \"%s\"", name);
- /* replaces all spaces with underscores, and then remaining special chars
- * with '-'
- * FIXME: why, pads can have any name
- */
- g_strdelimit (name, " ", '_');
- g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "_-><=", '-');
- GST_DEBUG ("GStreamer pad name: \"%s\"", name);
-
- if (LADSPA_IS_PORT_INPUT (p))
- gst_signal_processor_class_add_pad_template (gsp_class, name,
- GST_PAD_SINK, gsp_class->num_audio_in++, 1);
- else
- gst_signal_processor_class_add_pad_template (gsp_class, name,
- GST_PAD_SRC, gsp_class->num_audio_out++, 1);
-
- g_free (name);
- } else if (LADSPA_IS_PORT_CONTROL (p)) {
- if (LADSPA_IS_PORT_INPUT (p))
- gsp_class->num_control_in++;
- else
- gsp_class->num_control_out++;
- }
- }
-
- longname = g_locale_to_utf8 (desc->Name, -1, NULL, NULL, NULL);
- if (!longname)
- longname = g_strdup ("no description available");
- author = g_locale_to_utf8 (desc->Maker, -1, NULL, NULL, NULL);
- if (!author)
- author = g_strdup ("no author available");
-
-#ifdef HAVE_LRDF
- /* libldrf support, we want to get extra class information here */
- uri = g_strdup_printf (LADSPA_BASE "%ld", desc->UniqueID);
- if (uri) {
- lrdf_statement query = { 0, };
- lrdf_uris *uris;
- gchar *str, *base_type = NULL;
-
- GST_DEBUG ("uri (id=%d) : %s", desc->UniqueID, uri);
- /* we can take this directly from 'desc', keep this example for future
- attributes.
- if ((str = lrdf_get_setting_metadata (uri, "title"))) {
- GST_DEBUG ("title : %s", str);
- }
- if ((str = lrdf_get_setting_metadata (uri, "creator"))) {
- GST_DEBUG ("creator : %s", str);
- }
- */
-
- /* get the rdf:type for this plugin */
- query.subject = uri;
- query.predicate = (char *) RDF_BASE "type";
- query.object = (char *) "?";
- query.next = NULL;
- uris = lrdf_match_multi (&query);
- if (uris) {
- if (uris->count == 1) {
- base_type = g_strdup (uris->items[0]);
- GST_DEBUG ("base_type : %s", base_type);
- }
- lrdf_free_uris (uris);
- }
-
- /* query taxonomy */
- if (base_type) {
- uris = lrdf_get_all_superclasses (base_type);
- if (uris) {
- guint32 j;
-
- for (j = 0; j < uris->count; j++) {
- GST_LOG ("parent_type_uri : %s", uris->items[j]);
- if ((str = lrdf_get_label (uris->items[j]))) {
- GST_DEBUG ("parent_type_label : %s", str);
- if (extra_klass_tags) {
- gchar *old_tags = extra_klass_tags;
- extra_klass_tags = g_strconcat (extra_klass_tags, "/", str, NULL);
- g_free (old_tags);
- } else {
- extra_klass_tags = g_strconcat ("/", str, NULL);
- }
- }
- }
- lrdf_free_uris (uris);
- }
- g_free (base_type);
- }
-
- /* we can use this for the presets
- uris = lrdf_get_setting_uris (desc->UniqueID);
- if (uris) {
- guint32 j;
-
- for (j = 0; j < uris->count; j++) {
- GST_INFO ("setting_uri : %s", uris->items[j]);
- if ((str = lrdf_get_label (uris->items[j]))) {
- GST_INFO ("setting_label : %s", str);
- }
- }
- lrdf_free_uris (uris);
- }
- */
-
- }
- g_free (uri);
-#endif
-
- if (gsp_class->num_audio_in == 0)
- klass_tags = "Source/Audio/LADSPA";
- else if (gsp_class->num_audio_out == 0) {
- if (gsp_class->num_control_out == 0)
- klass_tags = "Sink/Audio/LADSPA";
- else
- klass_tags = "Sink/Analyzer/Audio/LADSPA";
- } else
- klass_tags = "Filter/Effect/Audio/LADSPA";
-
-#ifdef HAVE_LRDF
- if (extra_klass_tags) {
- char *s = g_strconcat (klass_tags, extra_klass_tags, NULL);
- g_free (extra_klass_tags);
- extra_klass_tags = s;
- }
-#endif
- GST_INFO ("tags : %s", klass_tags);
- gst_element_class_set_metadata (element_class, longname,
- extra_klass_tags ? extra_klass_tags : klass_tags, longname, author);
- g_free (longname);
- g_free (author);
- g_free (extra_klass_tags);
-
- 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 < desc->PortCount; j++) {
- LADSPA_PortDescriptor p = desc->PortDescriptors[j];
-
- if (LADSPA_IS_PORT_AUDIO (p)) {
- if (LADSPA_IS_PORT_INPUT (p))
- klass->audio_in_portnums[audio_in_count++] = j;
- else
- klass->audio_out_portnums[audio_out_count++] = j;
- } else if (LADSPA_IS_PORT_CONTROL (p)) {
- if (LADSPA_IS_PORT_INPUT (p))
- 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 (!LADSPA_IS_INPLACE_BROKEN (desc->Properties))
- GST_SIGNAL_PROCESSOR_CLASS_SET_CAN_PROCESS_IN_PLACE (klass);
-
- klass->descriptor = desc;
-}
-
-static gchar *
-gst_ladspa_class_get_param_name (GstLADSPAClass * klass, gint portnum)
-{
- LADSPA_Descriptor *desc;
- gchar *ret, *paren;
-
- desc = klass->descriptor;
-
- ret = g_strdup (desc->PortNames[portnum]);
-
- paren = g_strrstr (ret, " (");
- if (paren != NULL)
- *paren = '\0';
-
- /* this is the same thing that param_spec_* will do */
- g_strcanon (ret, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
- /* satisfy glib2 (argname[0] must be [A-Za-z]) */
- if (!((ret[0] >= 'a' && ret[0] <= 'z') || (ret[0] >= 'A' && ret[0] <= 'Z'))) {
- gchar *tempstr = ret;
-
- ret = g_strconcat ("param-", ret, NULL);
- g_free (tempstr);
- }
-
- /* check for duplicate property names */
- if (g_object_class_find_property (G_OBJECT_CLASS (klass), ret)) {
- gint n = 1;
- gchar *nret = g_strdup_printf ("%s-%d", ret, n++);
-
- while (g_object_class_find_property (G_OBJECT_CLASS (klass), nret)) {
- g_free (nret);
- nret = g_strdup_printf ("%s-%d", ret, n++);
- }
- g_free (ret);
- ret = nret;
- }
-
- GST_DEBUG ("built property name '%s' from port name '%s'", ret,
- desc->PortNames[portnum]);
-
- return ret;
-}
-
-static GParamSpec *
-gst_ladspa_class_get_param_spec (GstLADSPAClass * klass, gint portnum)
-{
- LADSPA_Descriptor *desc;
- GParamSpec *ret;
- gchar *name;
- gint hintdesc, perms;
- gfloat lower, upper, def;
-
- desc = klass->descriptor;
-
- name = gst_ladspa_class_get_param_name (klass, portnum);
- perms = G_PARAM_READABLE;
- if (LADSPA_IS_PORT_INPUT (desc->PortDescriptors[portnum]))
- perms |= G_PARAM_WRITABLE | G_PARAM_CONSTRUCT;
- if (LADSPA_IS_PORT_CONTROL (desc->PortDescriptors[portnum]))
- perms |= GST_PARAM_CONTROLLABLE;
-
- /* short name for hint descriptor */
- hintdesc = desc->PortRangeHints[portnum].HintDescriptor;
-
- if (LADSPA_IS_HINT_TOGGLED (hintdesc)) {
- ret = g_param_spec_boolean (name, name, name, FALSE, perms);
- g_free (name);
- return ret;
- }
-
- if (LADSPA_IS_HINT_BOUNDED_BELOW (hintdesc))
- lower = desc->PortRangeHints[portnum].LowerBound;
- else
- lower = -G_MAXFLOAT;
-
- if (LADSPA_IS_HINT_BOUNDED_ABOVE (hintdesc))
- upper = desc->PortRangeHints[portnum].UpperBound;
- else
- upper = G_MAXFLOAT;
-
- if (LADSPA_IS_HINT_SAMPLE_RATE (hintdesc)) {
- /* FIXME! */
- lower *= 44100;
- upper *= 44100;
- }
-
- if (LADSPA_IS_HINT_INTEGER (hintdesc)) {
- lower = CLAMP (lower, G_MININT, G_MAXINT);
- upper = CLAMP (upper, G_MININT, G_MAXINT);
- }
-
- /* default to lower bound */
- def = lower;
-
-#ifdef LADSPA_IS_HINT_HAS_DEFAULT
- if (LADSPA_IS_HINT_HAS_DEFAULT (hintdesc)) {
- if (LADSPA_IS_HINT_DEFAULT_0 (hintdesc))
- def = 0.0;
- else if (LADSPA_IS_HINT_DEFAULT_1 (hintdesc))
- def = 1.0;
- else if (LADSPA_IS_HINT_DEFAULT_100 (hintdesc))
- def = 100.0;
- else if (LADSPA_IS_HINT_DEFAULT_440 (hintdesc))
- def = 440.0;
- if (LADSPA_IS_HINT_DEFAULT_MINIMUM (hintdesc))
- def = lower;
- else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM (hintdesc))
- def = upper;
- else if (LADSPA_IS_HINT_LOGARITHMIC (hintdesc)) {
- if (LADSPA_IS_HINT_DEFAULT_LOW (hintdesc))
- def = exp (0.75 * log (lower) + 0.25 * log (upper));
- else if (LADSPA_IS_HINT_DEFAULT_MIDDLE (hintdesc))
- def = exp (0.5 * log (lower) + 0.5 * log (upper));
- else if (LADSPA_IS_HINT_DEFAULT_HIGH (hintdesc))
- def = exp (0.25 * log (lower) + 0.75 * log (upper));
- } else {
- if (LADSPA_IS_HINT_DEFAULT_LOW (hintdesc))
- def = 0.75 * lower + 0.25 * upper;
- else if (LADSPA_IS_HINT_DEFAULT_MIDDLE (hintdesc))
- def = 0.5 * lower + 0.5 * upper;
- else if (LADSPA_IS_HINT_DEFAULT_HIGH (hintdesc))
- def = 0.25 * lower + 0.75 * upper;
- }
- }
-#endif /* LADSPA_IS_HINT_HAS_DEFAULT */
-
- if (lower > upper) {
- gfloat tmp;
-
- /* silently swap */
- tmp = lower;
- lower = upper;
- upper = tmp;
- }
-
- def = CLAMP (def, lower, upper);
-
- if (LADSPA_IS_HINT_INTEGER (hintdesc)) {
- 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_ladspa_class_init (GstLADSPAClass * klass, LADSPA_Descriptor * desc)
-{
- GObjectClass *gobject_class;
- GstSignalProcessorClass *gsp_class;
- GParamSpec *p;
- gint i, ix;
-
- GST_DEBUG ("class_init %p", klass);
-
- gobject_class = (GObjectClass *) klass;
- gobject_class->set_property = gst_ladspa_set_property;
- gobject_class->get_property = gst_ladspa_get_property;
-
- gsp_class = GST_SIGNAL_PROCESSOR_CLASS (klass);
- gsp_class->setup = gst_ladspa_setup;
- gsp_class->start = gst_ladspa_start;
- gsp_class->stop = gst_ladspa_stop;
- gsp_class->cleanup = gst_ladspa_cleanup;
- gsp_class->process = gst_ladspa_process;
-
- /* properties have an offset of 1 */
- ix = 1;
-
- /* register properties */
-
- for (i = 0; i < gsp_class->num_control_in; i++, ix++) {
- p = gst_ladspa_class_get_param_spec (klass, klass->control_in_portnums[i]);
- g_object_class_install_property (gobject_class, ix, p);
- }
-
- for (i = 0; i < gsp_class->num_control_out; i++, ix++) {
- p = gst_ladspa_class_get_param_spec (klass, klass->control_out_portnums[i]);
- g_object_class_install_property (gobject_class, ix, p);
- }
-}
+GQuark descriptor_quark = 0;
static void
-gst_ladspa_init (GstLADSPA * ladspa, GstLADSPAClass * klass)
+ladspa_describe_plugin (GstPlugin * plugin,
+ const gchar * filename, LADSPA_Descriptor_Function descriptor_function)
{
- ladspa->descriptor = klass->descriptor;
- ladspa->activated = FALSE;
- ladspa->inplace_broken =
- LADSPA_IS_INPLACE_BROKEN (ladspa->descriptor->Properties);
-}
-
-static void
-gst_ladspa_set_property (GObject * object, guint prop_id, const GValue * value,
- GParamSpec * pspec)
-{
- 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 ();
- }
-}
-
-static void
-gst_ladspa_get_property (GObject * object, guint prop_id, GValue * value,
- GParamSpec * pspec)
-{
- 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 ();
- }
-}
-
-static gboolean
-gst_ladspa_setup (GstSignalProcessor * gsp, GstCaps * caps)
-{
- GstLADSPA *ladspa;
- GstLADSPAClass *oclass;
- GstSignalProcessorClass *gsp_class;
- LADSPA_Descriptor *desc;
- gint i;
-
- gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (gsp);
- ladspa = (GstLADSPA *) gsp;
- oclass = (GstLADSPAClass *) 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",
- gsp->sample_rate);
-
- if (!(ladspa->handle = desc->instantiate (desc, gsp->sample_rate)))
- goto no_instance;
-
- /* 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]));
-
- return TRUE;
-
-no_instance:
- {
- GST_WARNING_OBJECT (gsp, "could not create instance");
- return FALSE;
- }
-}
-
-static gboolean
-gst_ladspa_start (GstSignalProcessor * gsp)
-{
- GstLADSPA *ladspa;
- LADSPA_Descriptor *desc;
-
- ladspa = (GstLADSPA *) 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;
-
- return TRUE;
-}
-
-static void
-gst_ladspa_stop (GstSignalProcessor * gsp)
-{
- GstLADSPA *ladspa;
- LADSPA_Descriptor *desc;
-
- ladspa = (GstLADSPA *) 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;
-}
-
-static void
-gst_ladspa_cleanup (GstSignalProcessor * gsp)
-{
- GstLADSPA *ladspa;
- LADSPA_Descriptor *desc;
-
- ladspa = (GstLADSPA *) 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;
-}
-
-static void
-gst_ladspa_process (GstSignalProcessor * gsp, guint nframes)
-{
- GstSignalProcessorClass *gsp_class;
- GstLADSPA *ladspa;
- GstLADSPAClass *oclass;
- LADSPA_Descriptor *desc;
+ const LADSPA_Descriptor *desc;
guint i;
- gsp_class = GST_SIGNAL_PROCESSOR_GET_CLASS (gsp);
- ladspa = (GstLADSPA *) gsp;
- oclass = (GstLADSPAClass *) 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]);
+ /* walk through all the plugins in this plugin library */
+ for (i = 0; (desc = descriptor_function (i)); i++) {
+ guint audio_in, audio_out, control_in, control_out;
- desc->run (ladspa->handle, nframes);
-}
+ /* count ports of this plugin */
+ ladspa_count_ports (desc, &audio_in, &audio_out, &control_in, &control_out);
-static void
-ladspa_describe_plugin (LADSPA_Descriptor_Function descriptor_function)
-{
- const LADSPA_Descriptor *desc;
- gint i;
-
- /* walk through all the plugins in this pluginlibrary */
- i = 0;
- while ((desc = descriptor_function (i++))) {
- gchar *type_name;
- GTypeInfo typeinfo = {
- sizeof (GstLADSPAClass),
- (GBaseInitFunc) gst_ladspa_base_init,
- NULL,
- (GClassInitFunc) gst_ladspa_class_init,
- NULL,
- desc,
- sizeof (GstLADSPA),
- 0,
- (GInstanceInitFunc) gst_ladspa_init,
- };
- GType type;
- /* construct the type */
- type_name = g_strdup_printf ("ladspa-%s", desc->Label);
- 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 now */
- 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, descriptor_quark, (gpointer) desc);
-
- if (!gst_element_register (ladspa_plugin, type_name, GST_RANK_NONE, type))
- goto next;
-
- next:
- g_free (type_name);
+ /* categorize and register it */
+ if (audio_in == 0)
+ ladspa_describe_source_plugin (plugin, filename, desc);
+ else if (audio_out == 0)
+ ladspa_describe_sink_plugin (plugin, filename, desc);
+ else
+ ladspa_describe_filter_plugin (plugin, filename, desc);
}
}
return TRUE;
}
-
#endif
-/* search just the one directory.
- */
+/* search just the one directory */
static gboolean
-ladspa_plugin_directory_search (const char *dir_name)
+ladspa_plugin_directory_search (GstPlugin * ladspa_plugin, const char *dir_name)
{
GDir *dir;
gchar *file_name;
(gpointer *) & descriptor_function)) {
/* we've found a ladspa_descriptor function, now introspect it. */
GST_INFO ("describe %s", file_name);
- ladspa_describe_plugin (descriptor_function);
+ ladspa_describe_plugin (ladspa_plugin, entry_name, descriptor_function);
ok = TRUE;
} else {
/* it was a library, but not a LADSPA one. Unload it. */
return ok;
}
-/* search the plugin path
- */
+/* search the plugin path */
static gboolean
-ladspa_plugin_path_search (void)
+ladspa_plugin_path_search (GstPlugin * plugin)
{
const gchar *search_path;
gchar *ladspa_path;
}
if (skip)
break;
- /* transform path: /usr/lib/ladspa -> /usr/share/ladspa/rdf/
+ /*
+ * transform path: /usr/lib/ladspa -> /usr/share/ladspa/rdf/
* yes, this is ugly, but lrdf has not searchpath
*/
if ((pos = strstr (paths[i], "/lib/ladspa"))) {
}
if (skip)
break;
- res |= ladspa_plugin_directory_search (paths[i]);
+ res |= ladspa_plugin_directory_search (plugin, paths[i]);
}
g_strfreev (paths);
static gboolean
plugin_init (GstPlugin * plugin)
{
- GST_DEBUG_CATEGORY_INIT (ladspa_debug, "ladspa",
- GST_DEBUG_FG_GREEN | GST_DEBUG_BG_BLACK | GST_DEBUG_BOLD, "LADSPA");
+#ifdef ENABLE_NLS
+ GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
+ LOCALEDIR);
+ bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+#endif
+
+ GST_DEBUG_CATEGORY_INIT (ladspa_debug, "ladspa", 0, "LADSPA plugins");
+
+ descriptor_quark = g_quark_from_static_string ("ladspa-descriptor");
gst_plugin_add_dependency_simple (plugin,
"LADSPA_PATH",
lrdf_init ();
#endif
- parent_class = g_type_class_ref (GST_TYPE_SIGNAL_PROCESSOR);
-
- ladspa_plugin = plugin;
- descriptor_quark = g_quark_from_static_string ("ladspa-descriptor");
-
- if (!ladspa_plugin_path_search ()) {
- GST_WARNING ("no ladspa plugins found, check LADSPA_PATH");
- }
+ if (!ladspa_plugin_path_search (plugin))
+ GST_WARNING ("no LADSPA plugins found, check LADSPA_PATH");
/* we don't want to fail, even if there are no elements registered */
return TRUE;
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
GST_VERSION_MINOR,
ladspa,
- "All LADSPA plugins",
+ "LADSPA plugin",
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
/* GStreamer
- * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
*
* gstladspa.h: Header for LADSPA plugin
*
* Boston, MA 02110-1301, USA.
*/
-
#ifndef __GST_LADSPA_H__
#define __GST_LADSPA_H__
-
-#include <ladspa.h>
-
#include <gst/gst.h>
-#include <gst/signalprocessor/gstsignalprocessor.h>
-
-
G_BEGIN_DECLS
-
-typedef struct _ladspa_control_info {
- gchar *name;
- gchar *param_name;
- gfloat lowerbound, upperbound;
- gfloat def;
- gboolean lower, upper, samplerate;
- gboolean toggled, logarithmic, integer, writable;
-} ladspa_control_info;
-
-
-typedef struct _GstLADSPA GstLADSPA;
-typedef struct _GstLADSPAClass GstLADSPAClass;
-
-
-struct _GstLADSPA {
- GstSignalProcessor parent;
-
- LADSPA_Descriptor *descriptor;
- LADSPA_Handle *handle;
-
- gboolean activated;
- gboolean inplace_broken;
-};
-
-struct _GstLADSPAClass {
- GstSignalProcessorClass parent_class;
-
- LADSPA_Descriptor *descriptor;
-
- gint *audio_in_portnums;
- gint *audio_out_portnums;
- gint *control_in_portnums;
- gint *control_out_portnums;
-};
-
+extern GQuark descriptor_quark;
G_END_DECLS
-
#endif /* __GST_LADSPA_H__ */
--- /dev/null
+/* GStreamer LADSPA filter category
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
+ * 2003 Andy Wingo <wingo at pobox.com>
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstladspafilter.h"
+#include "gstladspa.h"
+#include "gstladspautils.h"
+
+GST_DEBUG_CATEGORY_EXTERN (ladspa_debug);
+#define GST_CAT_DEFAULT ladspa_debug
+
+#define GST_LADSPA_FILTER_CLASS_TAGS "Filter/Effect/Audio/LADSPA"
+
+static GstLADSPAFilterClass *gst_ladspa_filter_type_parent_class = NULL;
+
+/*
+ * Assumes only same format (base of AudioFilter), not same channels.
+ */
+void
+gst_my_audio_filter_class_add_pad_templates (GstAudioFilterClass * audio_class,
+ GstCaps * srccaps, GstCaps * sinkcaps)
+{
+ GstElementClass *elem_class = GST_ELEMENT_CLASS (audio_class);
+ GstPadTemplate *pad_template;
+
+ g_return_if_fail (GST_IS_CAPS (srccaps) && GST_IS_CAPS (sinkcaps));
+
+ pad_template =
+ gst_pad_template_new (GST_BASE_TRANSFORM_SRC_NAME, GST_PAD_SRC,
+ GST_PAD_ALWAYS, srccaps);
+ gst_element_class_add_pad_template (elem_class, pad_template);
+
+ pad_template =
+ gst_pad_template_new (GST_BASE_TRANSFORM_SINK_NAME, GST_PAD_SINK,
+ GST_PAD_ALWAYS, sinkcaps);
+ gst_element_class_add_pad_template (elem_class, pad_template);
+}
+
+static GstCaps *
+gst_ladspa_filter_type_fixate_caps (GstBaseTransform * base,
+ GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
+{
+ GstStructure *structure;
+ gint rate;
+
+ structure = gst_caps_get_structure (caps, 0);
+ if (G_UNLIKELY (!gst_structure_get_int (structure, "rate", &rate)))
+ return othercaps;
+
+ othercaps = gst_caps_truncate (othercaps);
+ othercaps = gst_caps_make_writable (othercaps);
+ structure = gst_caps_get_structure (othercaps, 0);
+
+ gst_structure_fixate_field_nearest_int (structure, "rate", rate);
+
+ return othercaps;
+}
+
+static GstCaps *
+gst_ladspa_filter_type_transform_caps (GstBaseTransform * base,
+ GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+ GstCaps *srccaps, *sinkcaps;
+ GstCaps *ret = NULL;
+
+ srccaps = gst_pad_get_pad_template_caps (GST_BASE_TRANSFORM_SRC_PAD (base));
+ sinkcaps = gst_pad_get_pad_template_caps (GST_BASE_TRANSFORM_SINK_PAD (base));
+
+ switch (direction) {
+ case GST_PAD_SINK:
+ if (gst_caps_can_intersect (caps, sinkcaps))
+ ret = gst_caps_copy (srccaps);
+ else
+ ret = gst_caps_new_empty ();
+ break;
+ case GST_PAD_SRC:
+ if (gst_caps_can_intersect (caps, srccaps))
+ ret = gst_caps_copy (sinkcaps);
+ else
+ ret = gst_caps_new_empty ();
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ GST_DEBUG_OBJECT (ladspa_debug, "transformed %" GST_PTR_FORMAT, ret);
+
+ if (filter) {
+ GstCaps *intersection;
+
+ GST_DEBUG_OBJECT (ladspa_debug, "Using filter caps %" GST_PTR_FORMAT,
+ filter);
+
+ intersection =
+ gst_caps_intersect_full (filter, ret, GST_CAPS_INTERSECT_FIRST);
+ gst_caps_unref (ret);
+ ret = intersection;
+
+ GST_DEBUG_OBJECT (ladspa_debug, "Intersection %" GST_PTR_FORMAT, ret);
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_ladspa_filter_type_prepare_output_buffer (GstBaseTransform * base,
+ GstBuffer * inbuf, GstBuffer ** outbuf)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
+ GstLADSPAFilterClass *ladspa_class = GST_LADSPA_FILTER_GET_CLASS (ladspa);
+ guint samples;
+
+ samples =
+ gst_buffer_get_size (inbuf) / sizeof (LADSPA_Data) /
+ ladspa_class->ladspa.count.audio.in;
+
+ if (!gst_base_transform_is_in_place (base)) {
+ *outbuf =
+ gst_buffer_new_allocate (NULL,
+ samples * sizeof (LADSPA_Data) * ladspa_class->ladspa.count.audio.out,
+ NULL);
+ *outbuf = gst_buffer_make_writable (*outbuf);
+ return GST_FLOW_OK;
+ } else {
+ return
+ GST_BASE_TRANSFORM_CLASS
+ (gst_ladspa_filter_type_parent_class)->prepare_output_buffer (base,
+ inbuf, outbuf);
+ }
+}
+
+static gboolean
+gst_ladspa_filter_type_setup (GstAudioFilter * audio,
+ const GstAudioInfo * info)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (audio);
+
+ return gst_ladspa_setup (&ladspa->ladspa, GST_AUDIO_INFO_RATE (info));
+}
+
+static gboolean
+gst_ladspa_filter_type_cleanup (GstBaseTransform * base)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
+
+ return gst_ladspa_cleanup (&ladspa->ladspa);
+}
+
+static GstFlowReturn
+gst_ladspa_filter_type_transform_ip (GstBaseTransform * base,
+ GstBuffer * buf)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
+ GstMapInfo map;
+ guint samples;
+
+ gst_buffer_map (buf, &map, GST_MAP_READWRITE);
+ samples =
+ map.size / sizeof (LADSPA_Data) / ladspa->ladspa.klass->count.audio.in;
+ gst_ladspa_transform (&ladspa->ladspa, map.data, samples, map.data);
+ gst_buffer_unmap (buf, &map);
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_ladspa_filter_type_transform (GstBaseTransform * base,
+ GstBuffer * inbuf, GstBuffer * outbuf)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (base);
+ GstMapInfo inmap, outmap;
+ guint samples;
+
+ gst_buffer_map (inbuf, &inmap, GST_MAP_READ);
+ gst_buffer_map (outbuf, &outmap, GST_MAP_WRITE);
+ samples =
+ inmap.size / sizeof (LADSPA_Data) / ladspa->ladspa.klass->count.audio.in;
+ gst_ladspa_transform (&ladspa->ladspa, outmap.data, samples, inmap.data);
+ gst_buffer_unmap (outbuf, &outmap);
+ gst_buffer_unmap (inbuf, &inmap);
+
+ return GST_FLOW_OK;
+}
+
+static void
+gst_ladspa_filter_type_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (object);
+
+ gst_ladspa_object_set_property (&ladspa->ladspa, object, prop_id, value,
+ pspec);
+}
+
+static void
+gst_ladspa_filter_type_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (object);
+
+ gst_ladspa_object_get_property (&ladspa->ladspa, object, prop_id, value,
+ pspec);
+}
+
+static void
+gst_ladspa_filter_type_init (GstLADSPAFilter * ladspa,
+ LADSPA_Descriptor * desc)
+{
+ GstBaseTransform *base = GST_BASE_TRANSFORM (ladspa);
+ GstLADSPAFilterClass *ladspa_class = GST_LADSPA_FILTER_GET_CLASS (ladspa);
+
+ gst_ladspa_init (&ladspa->ladspa, &ladspa_class->ladspa);
+
+ /* even if channels are different LADSPA still maintains same samples */
+ gst_base_transform_set_in_place (base,
+ ladspa_class->ladspa.count.audio.in ==
+ ladspa_class->ladspa.count.audio.out
+ && !LADSPA_IS_INPLACE_BROKEN (ladspa_class->ladspa.descriptor->
+ Properties));
+
+}
+
+static void
+gst_ladspa_filter_type_dispose (GObject * object)
+{
+ GstBaseTransform *base = GST_BASE_TRANSFORM (object);
+
+ gst_ladspa_filter_type_cleanup (base);
+
+ G_OBJECT_CLASS (gst_ladspa_filter_type_parent_class)->dispose (object);
+}
+
+static void
+gst_ladspa_filter_type_finalize (GObject * object)
+{
+ GstLADSPAFilter *ladspa = GST_LADSPA_FILTER (object);
+
+ gst_ladspa_finalize (&ladspa->ladspa);
+
+ G_OBJECT_CLASS (gst_ladspa_filter_type_parent_class)->finalize (object);
+}
+
+/*
+ * It is okay for plugins to 'leak' a one-time allocation. This will be freed when
+ * the application exits. When the plugins are scanned for the first time, this is
+ * done from a separate process to not impose the memory overhead on the calling
+ * application (among other reasons). Hence no need for class_finalize.
+ */
+static void
+gst_ladspa_filter_type_base_init (GstLADSPAFilterClass * ladspa_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
+ GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class);
+ GstAudioFilterClass *audio_class = GST_AUDIO_FILTER_CLASS (ladspa_class);
+ LADSPA_Descriptor *desc;
+
+ desc =
+ g_type_get_qdata (G_OBJECT_CLASS_TYPE (object_class), descriptor_quark);
+ g_assert (desc);
+
+ gst_ladspa_class_init (&ladspa_class->ladspa, desc);
+
+ gst_ladspa_element_class_set_metadata (&ladspa_class->ladspa, elem_class,
+ GST_LADSPA_FILTER_CLASS_TAGS);
+ gst_ladspa_filter_type_class_add_pad_templates (&ladspa_class->ladspa,
+ audio_class);
+}
+
+static void
+gst_ladspa_filter_type_base_finalize (GstLADSPAFilterClass * ladspa_class)
+{
+ gst_ladspa_class_finalize (&ladspa_class->ladspa);
+}
+
+static void
+gst_ladspa_filter_type_class_init (GstLADSPAFilterClass * ladspa_class,
+ LADSPA_Descriptor * desc)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
+ GstBaseTransformClass *base_class = GST_BASE_TRANSFORM_CLASS (ladspa_class);
+ GstAudioFilterClass *audio_class = GST_AUDIO_FILTER_CLASS (ladspa_class);
+
+ GST_DEBUG ("LADSPA filter class %p", ladspa_class);
+
+ gst_ladspa_filter_type_parent_class =
+ g_type_class_peek_parent (ladspa_class);
+
+ object_class->dispose =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_dispose);
+ object_class->finalize =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_finalize);
+ object_class->set_property =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_set_property);
+ object_class->get_property =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_get_property);
+
+ base_class->fixate_caps =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_fixate_caps);
+ base_class->transform_caps =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_transform_caps);
+ base_class->prepare_output_buffer =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_prepare_output_buffer);
+ base_class->transform =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_transform);
+ base_class->transform_ip =
+ GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_transform_ip);
+
+ audio_class->setup = GST_DEBUG_FUNCPTR (gst_ladspa_filter_type_setup);
+
+ gst_ladspa_object_class_install_properties (&ladspa_class->ladspa,
+ object_class, 1);
+}
+
+G_DEFINE_ABSTRACT_TYPE (GstLADSPAFilter, gst_ladspa_filter,
+ GST_TYPE_AUDIO_FILTER);
+
+static void
+gst_ladspa_filter_init (GstLADSPAFilter * ladspa)
+{
+}
+
+static void
+gst_ladspa_filter_class_init (GstLADSPAFilterClass * ladspa_class)
+{
+}
+
+/*
+ * Construct the type.
+ */
+void
+ladspa_describe_filter_plugin (GstPlugin * plugin,
+ const gchar * filename, const LADSPA_Descriptor * desc)
+{
+ GTypeInfo info = {
+ sizeof (GstLADSPAFilterClass),
+ (GBaseInitFunc) gst_ladspa_filter_type_base_init,
+ (GBaseFinalizeFunc) gst_ladspa_filter_type_base_finalize,
+ (GClassInitFunc) gst_ladspa_filter_type_class_init,
+ NULL,
+ desc,
+ sizeof (GstLADSPAFilter),
+ 0,
+ (GInstanceInitFunc) gst_ladspa_filter_type_init,
+ NULL
+ };
+ gchar *tmp;
+
+ tmp = g_strdup_printf ("ladspa-%s-%s", filename, desc->Label);
+ ladspa_register_plugin (plugin, GST_TYPE_LADSPA_FILTER, tmp, &info,
+ descriptor_quark, filename, desc);
+ g_free (tmp);
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
+ *
+ * gstladspafilter.h: Header for LADSPA filter
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_LADSPA_FILTER_H__
+#define __GST_LADSPA_FILTER_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+#include "gstladspautils.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_LADSPA_FILTER (gst_ladspa_filter_get_type())
+#define GST_LADSPA_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LADSPA_FILTER,GstLADSPAFilter))
+#define GST_LADSPA_FILTER_CAST(obj) ((GstLADSPAFilter *) (obj))
+#define GST_LADSPA_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LADSPA_FILTER,GstLADSPAFilterClass))
+#define GST_LADSPA_FILTER_CLASS_CAST(klass) ((GstLADSPAFilterClass *) (klass))
+#define GST_LADSPA_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_LADSPA_FILTER,GstLADSPAFilterClass))
+#define GST_IS_LADSPA_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LADSPA_FILTER))
+#define GST_IS_LADSPA_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LADSPA_FILTER))
+
+typedef struct _GstLADSPAFilter GstLADSPAFilter;
+
+typedef struct _GstLADSPAFilterClass GstLADSPAFilterClass;
+
+struct _GstLADSPAFilter
+{
+ GstAudioFilter parent;
+
+ GstLADSPA ladspa;
+};
+
+struct _GstLADSPAFilterClass
+{
+ GstAudioFilterClass parent_class;
+
+ GstLADSPAClass ladspa;
+};
+
+GType
+gst_ladspa_filter_get_type (void);
+
+void
+ladspa_describe_filter_plugin (GstPlugin * plugin,
+ const gchar * filename, const LADSPA_Descriptor * desc);
+
+void
+gst_my_audio_filter_class_add_pad_templates (GstAudioFilterClass * audio_class,
+ GstCaps * srccaps, GstCaps * sinkcaps);
+
+G_END_DECLS
+
+#endif /* __GST_LADSPA_FILTER_H__ */
--- /dev/null
+/* GStreamer LADSPA sink category
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
+ * 2003 Andy Wingo <wingo at pobox.com>
+ * Copyright (C) 2005 Wim Taymans <wim@fluendo.com> (fakesink)
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstladspasink.h"
+#include "gstladspa.h"
+#include "gstladspautils.h"
+#include <gst/base/gstbasetransform.h>
+
+#include <string.h>
+
+GST_DEBUG_CATEGORY_EXTERN (ladspa_debug);
+#define GST_CAT_DEFAULT ladspa_debug
+
+#define GST_LADSPA_SINK_CLASS_TAGS "Sink/Audio/LADSPA"
+#define GST_LADSPA_SINK_DEFAULT_SYNC TRUE
+#define GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PUSH TRUE
+#define GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PULL FALSE
+#define GST_LADSPA_SINK_DEFAULT_NUM_BUFFERS -1
+
+enum
+{
+ GST_LADSPA_SINK_PROP_0,
+ GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH,
+ GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL,
+ GST_LADSPA_SINK_PROP_NUM_BUFFERS,
+ GST_LADSPA_SINK_PROP_LAST
+};
+
+static GstLADSPASinkClass *gst_ladspa_sink_type_parent_class = NULL;
+
+/*
+ * Boilerplates BaseSink add pad.
+ */
+void
+gst_my_base_sink_class_add_pad_template (GstBaseSinkClass * base_class,
+ GstCaps * sinkcaps)
+{
+ GstElementClass *elem_class = GST_ELEMENT_CLASS (base_class);
+ GstPadTemplate *pad_template;
+
+ g_return_if_fail (GST_IS_CAPS (sinkcaps));
+
+ pad_template =
+ gst_pad_template_new (GST_BASE_TRANSFORM_SINK_NAME, GST_PAD_SINK,
+ GST_PAD_ALWAYS, sinkcaps);
+ gst_element_class_add_pad_template (elem_class, pad_template);
+}
+
+static gboolean
+gst_ladspa_sink_type_set_caps (GstBaseSink * base, GstCaps * caps)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (base);
+ GstAudioInfo info;
+
+ if (!gst_audio_info_from_caps (&info, caps)) {
+ GST_ERROR_OBJECT (base, "received invalid caps");
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT (ladspa, "negotiated to caps %" GST_PTR_FORMAT, caps);
+
+ ladspa->info = info;
+
+ return gst_ladspa_setup (&ladspa->ladspa, GST_AUDIO_INFO_RATE (&info));
+}
+
+static gboolean
+gst_ladspa_sink_type_query (GstBaseSink * base, GstQuery * query)
+{
+ gboolean ret;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_SEEKING:{
+ GstFormat fmt;
+
+ /* we don't supporting seeking */
+ gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
+ gst_query_set_seeking (query, fmt, FALSE, 0, -1);
+ ret = TRUE;
+ break;
+ }
+ default:
+ ret =
+ GST_BASE_SINK_CLASS (gst_ladspa_sink_type_parent_class)->query
+ (base, query);
+ break;
+ }
+
+ return ret;
+}
+
+static GstFlowReturn
+gst_ladspa_sink_type_preroll (GstBaseSink * base, GstBuffer * buffer)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (base);
+
+ if (ladspa->num_buffers_left == 0) {
+ GST_DEBUG_OBJECT (ladspa, "we are EOS");
+ return GST_FLOW_EOS;
+ }
+
+ return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_ladspa_sink_type_render (GstBaseSink * base, GstBuffer * buf)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (base);
+ GstMapInfo info;
+
+ if (ladspa->num_buffers_left == 0)
+ goto eos;
+
+ if (ladspa->num_buffers_left != -1)
+ ladspa->num_buffers_left--;
+
+ gst_buffer_map (buf, &info, GST_MAP_READ);
+ gst_ladspa_transform (&ladspa->ladspa, NULL,
+ info.size / sizeof (LADSPA_Data) / ladspa->ladspa.klass->count.audio.in,
+ info.data);
+ gst_buffer_unmap (buf, &info);
+
+ if (ladspa->num_buffers_left == 0)
+ goto eos;
+
+ return GST_FLOW_OK;
+
+ /* ERRORS */
+eos:
+ {
+ GST_DEBUG_OBJECT (ladspa, "we are EOS");
+ return GST_FLOW_EOS;
+ }
+}
+
+static GstStateChangeReturn
+gst_ladspa_sink_type_change_state (GstElement * element,
+ GstStateChange transition)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (element);
+ GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+ switch (transition) {
+ case GST_STATE_CHANGE_READY_TO_PAUSED:
+ ladspa->num_buffers_left = ladspa->num_buffers;
+ break;
+ default:
+ break;
+ }
+
+ ret =
+ GST_ELEMENT_CLASS (gst_ladspa_sink_type_parent_class)->change_state
+ (element, transition);
+
+ return ret;
+}
+
+
+static void
+gst_ladspa_sink_type_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
+
+ switch (prop_id) {
+ case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH:
+ GST_BASE_SINK (ladspa)->can_activate_push = g_value_get_boolean (value);
+ break;
+ case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL:
+ GST_BASE_SINK (ladspa)->can_activate_pull = g_value_get_boolean (value);
+ break;
+ case GST_LADSPA_SINK_PROP_NUM_BUFFERS:
+ ladspa->num_buffers = g_value_get_int (value);
+ break;
+ default:
+ gst_ladspa_object_set_property (&ladspa->ladspa, object, prop_id, value,
+ pspec);
+ break;
+ }
+}
+
+static void
+gst_ladspa_sink_type_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
+
+ switch (prop_id) {
+ case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH:
+ g_value_set_boolean (value, GST_BASE_SINK (ladspa)->can_activate_push);
+ break;
+ case GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL:
+ g_value_set_boolean (value, GST_BASE_SINK (ladspa)->can_activate_pull);
+ break;
+ case GST_LADSPA_SINK_PROP_NUM_BUFFERS:
+ g_value_set_int (value, ladspa->num_buffers);
+ break;
+ default:
+ gst_ladspa_object_get_property (&ladspa->ladspa, object, prop_id, value,
+ pspec);
+ break;
+ }
+}
+
+static void
+gst_ladspa_sink_type_init (GstLADSPASink * ladspa, LADSPA_Descriptor * desc)
+{
+ GstLADSPASinkClass *ladspa_class = GST_LADSPA_SINK_GET_CLASS (ladspa);
+ GstBaseSink *base = GST_BASE_SINK (ladspa);
+
+ gst_ladspa_init (&ladspa->ladspa, &ladspa_class->ladspa);
+
+ ladspa->num_buffers = GST_LADSPA_SINK_DEFAULT_NUM_BUFFERS;
+
+ gst_base_sink_set_sync (base, GST_LADSPA_SINK_DEFAULT_SYNC);
+}
+
+static void
+gst_ladspa_sink_type_dispose (GObject * object)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
+
+ gst_ladspa_cleanup (&ladspa->ladspa);
+
+ G_OBJECT_CLASS (gst_ladspa_sink_type_parent_class)->dispose (object);
+}
+
+static void
+gst_ladspa_sink_type_finalize (GObject * object)
+{
+ GstLADSPASink *ladspa = GST_LADSPA_SINK (object);
+
+ gst_ladspa_finalize (&ladspa->ladspa);
+
+ G_OBJECT_CLASS (gst_ladspa_sink_type_parent_class)->finalize (object);
+}
+
+/*
+ * It is okay for plugins to 'leak' a one-time allocation. This will be freed when
+ * the application exits. When the plugins are scanned for the first time, this is
+ * done from a separate process to not impose the memory overhead on the calling
+ * application (among other reasons). Hence no need for class_finalize.
+ */
+static void
+gst_ladspa_sink_type_base_init (GstLADSPASinkClass * ladspa_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
+ GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class);
+ GstBaseSinkClass *base_class = GST_BASE_SINK_CLASS (ladspa_class);
+ LADSPA_Descriptor *desc;
+
+ desc =
+ g_type_get_qdata (G_OBJECT_CLASS_TYPE (object_class), descriptor_quark);
+ g_assert (desc);
+
+ gst_ladspa_class_init (&ladspa_class->ladspa, desc);
+
+ gst_ladspa_element_class_set_metadata (&ladspa_class->ladspa, elem_class,
+ GST_LADSPA_SINK_CLASS_TAGS);
+
+ gst_ladspa_sink_type_class_add_pad_template (&ladspa_class->ladspa,
+ base_class);
+}
+
+
+static void
+gst_ladspa_sink_type_base_finalize (GstLADSPASinkClass * ladspa_class)
+{
+ gst_ladspa_class_finalize (&ladspa_class->ladspa);
+}
+
+static void
+gst_ladspa_sink_type_class_init (GstLADSPASinkClass * ladspa_class,
+ LADSPA_Descriptor * desc)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
+ GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class);
+ GstBaseSinkClass *base_class = base_class =
+ GST_BASE_SINK_CLASS (ladspa_class);
+
+ gst_ladspa_sink_type_parent_class =
+ g_type_class_peek_parent (ladspa_class);
+
+ object_class->dispose = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_dispose);
+ object_class->finalize =
+ GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_finalize);
+ object_class->set_property =
+ GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_set_property);
+ object_class->get_property =
+ GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_get_property);
+
+ elem_class->change_state =
+ GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_change_state);
+
+ base_class->set_caps = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_set_caps);
+ base_class->preroll = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_preroll);
+ base_class->render = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_render);
+ base_class->query = GST_DEBUG_FUNCPTR (gst_ladspa_sink_type_query);
+
+ g_object_class_install_property (object_class,
+ GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PUSH,
+ g_param_spec_boolean ("can-activate-push", "Can activate push",
+ "Can activate in push mode",
+ GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PUSH,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ GST_LADSPA_SINK_PROP_CAN_ACTIVATE_PULL,
+ g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+ "Can activate in pull mode",
+ GST_LADSPA_SINK_DEFAULT_CAN_ACTIVATE_PULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ GST_LADSPA_SINK_PROP_NUM_BUFFERS, g_param_spec_int ("num-buffers",
+ "num-buffers", "Number of buffers to accept going EOS", -1, G_MAXINT,
+ GST_LADSPA_SINK_DEFAULT_NUM_BUFFERS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_ladspa_object_class_install_properties (&ladspa_class->ladspa,
+ object_class, GST_LADSPA_SINK_PROP_LAST);
+
+}
+
+G_DEFINE_ABSTRACT_TYPE (GstLADSPASink, gst_ladspa_sink, GST_TYPE_BASE_SINK);
+
+static void
+gst_ladspa_sink_init (GstLADSPASink * ladspa)
+{
+}
+
+static void
+gst_ladspa_sink_class_init (GstLADSPASinkClass * ladspa_class)
+{
+}
+
+/*
+ * Construct the type.
+ */
+void
+ladspa_describe_sink_plugin (GstPlugin * plugin,
+ const gchar * filename, const LADSPA_Descriptor * desc)
+{
+ GTypeInfo info = {
+ sizeof (GstLADSPASinkClass),
+ (GBaseInitFunc) gst_ladspa_sink_type_base_init,
+ (GBaseFinalizeFunc) gst_ladspa_sink_type_base_finalize,
+ (GClassInitFunc) gst_ladspa_sink_type_class_init,
+ NULL,
+ desc,
+ sizeof (GstLADSPASink),
+ 0,
+ (GInstanceInitFunc) gst_ladspa_sink_type_init,
+ NULL
+ };
+ gchar *tmp;
+
+ tmp = g_strdup_printf ("ladspasink-%s-%s", filename, desc->Label);
+ ladspa_register_plugin (plugin, GST_TYPE_LADSPA_SINK, tmp, &info,
+ descriptor_quark, filename, desc);
+ g_free (tmp);
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
+ *
+ * gstladspasink.h: Header for LADSPA sink
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_LADSPA_SINK_H__
+#define __GST_LADSPA_SINK_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesink.h>
+#include "gstladspautils.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_LADSPA_SINK (gst_ladspa_sink_get_type())
+#define GST_LADSPA_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LADSPA_SINK,GstLADSPASink))
+#define GST_LADSPA_SINK_CAST(obj) ((GstLADSPASink *) (obj))
+#define GST_LADSPA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LADSPA_SINK,GstLADSPASinkClass))
+#define GST_LADSPA_SINK_CLASS_CAST(klass) ((GstLADSPASinkClass *) (klass))
+#define GST_LADSPA_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_LADSPA_SINK,GstLADSPASinkClass))
+#define GST_IS_LADSPA_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LADSPA_SINK))
+#define GST_IS_LADSPA_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LADSPA_SINK))
+
+typedef struct _GstLADSPASink GstLADSPASink;
+
+typedef struct _GstLADSPASinkClass GstLADSPASinkClass;
+
+struct _GstLADSPASink
+{
+ GstBaseSink parent;
+
+ GstLADSPA ladspa;
+
+ GstAudioInfo info;
+
+ gint num_buffers;
+ gint num_buffers_left;
+};
+
+struct _GstLADSPASinkClass
+{
+ GstBaseSinkClass parent_class;
+
+ GstLADSPAClass ladspa;
+};
+
+GType
+gst_ladspa_sink_get_type (void);
+
+void
+ladspa_describe_sink_plugin (GstPlugin * plugin,
+ const gchar * filename, const LADSPA_Descriptor * desc);
+
+void
+gst_my_base_sink_class_add_pad_template (GstBaseSinkClass * base_class,
+ GstCaps * sinkcaps);
+
+G_END_DECLS
+
+#endif /* __GST_LADSPA_SINK_H__ */
--- /dev/null
+/* GStreamer LADSPA source category
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
+ * 2003 Andy Wingo <wingo at pobox.com>
+ * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net> (audiotestsrc)
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstladspasource.h"
+#include "gstladspa.h"
+#include "gstladspautils.h"
+#include <gst/base/gstbasetransform.h>
+
+GST_DEBUG_CATEGORY_EXTERN (ladspa_debug);
+#define GST_CAT_DEFAULT ladspa_debug
+
+#define GST_LADSPA_SOURCE_CLASS_TAGS "Source/Audio/LADSPA"
+#define GST_LADSPA_SOURCE_DEFAULT_SAMPLES_PER_BUFFER 1024
+#define GST_LADSPA_SOURCE_DEFAULT_IS_LIVE FALSE
+#define GST_LADSPA_SOURCE_DEFAULT_TIMESTAMP_OFFSET G_GINT64_CONSTANT (0)
+#define GST_LADSPA_SOURCE_DEFAULT_CAN_ACTIVATE_PUSH TRUE
+#define GST_LADSPA_SOURCE_DEFAULT_CAN_ACTIVATE_PULL FALSE
+
+enum
+{
+ GST_LADSPA_SOURCE_PROP_0,
+ GST_LADSPA_SOURCE_PROP_SAMPLES_PER_BUFFER,
+ GST_LADSPA_SOURCE_PROP_IS_LIVE,
+ GST_LADSPA_SOURCE_PROP_TIMESTAMP_OFFSET,
+ GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PUSH,
+ GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PULL,
+ GST_LADSPA_SOURCE_PROP_LAST
+};
+
+static GstLADSPASourceClass *gst_ladspa_source_type_parent_class = NULL;
+
+/*
+ * Boilerplates BaseSrc add pad.
+ */
+void
+gst_my_base_source_class_add_pad_template (GstBaseSrcClass * base_class,
+ GstCaps * srccaps)
+{
+ GstElementClass *elem_class = GST_ELEMENT_CLASS (base_class);
+ GstPadTemplate *pad_template;
+
+ g_return_if_fail (GST_IS_CAPS (srccaps));
+
+ pad_template =
+ gst_pad_template_new (GST_BASE_TRANSFORM_SRC_NAME, GST_PAD_SRC,
+ GST_PAD_ALWAYS, srccaps);
+ gst_element_class_add_pad_template (elem_class, pad_template);
+}
+
+static GstCaps *
+gst_ladspa_source_type_fixate (GstBaseSrc * base, GstCaps * caps)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (base);
+ GstStructure *structure;
+
+ caps = gst_caps_make_writable (caps);
+
+ structure = gst_caps_get_structure (caps, 0);
+
+ GST_DEBUG_OBJECT (ladspa, "fixating samplerate to %d", GST_AUDIO_DEF_RATE);
+
+ gst_structure_fixate_field_nearest_int (structure, "rate",
+ GST_AUDIO_DEF_RATE);
+
+ gst_structure_fixate_field_string (structure, "format", GST_AUDIO_NE (F32));
+
+ gst_structure_fixate_field_nearest_int (structure, "channels",
+ ladspa->ladspa.klass->count.audio.out);
+
+ caps =
+ GST_BASE_SRC_CLASS (gst_ladspa_source_type_parent_class)->fixate
+ (base, caps);
+
+ return caps;
+}
+
+static gboolean
+gst_ladspa_source_type_set_caps (GstBaseSrc * base, GstCaps * caps)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (base);
+ GstAudioInfo info;
+
+ if (!gst_audio_info_from_caps (&info, caps)) {
+ GST_ERROR_OBJECT (base, "received invalid caps");
+ return FALSE;
+ }
+
+ GST_DEBUG_OBJECT (ladspa, "negotiated to caps %" GST_PTR_FORMAT, caps);
+
+ ladspa->info = info;
+
+ gst_base_src_set_blocksize (base,
+ GST_AUDIO_INFO_BPF (&info) * ladspa->samples_per_buffer);
+
+ return gst_ladspa_setup (&ladspa->ladspa, GST_AUDIO_INFO_RATE (&info));
+}
+
+static gboolean
+gst_ladspa_source_type_query (GstBaseSrc * base, GstQuery * query)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (base);
+ gboolean res = FALSE;
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_CONVERT:
+ {
+ GstFormat src_fmt, dest_fmt;
+ gint64 src_val, dest_val;
+
+ gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, &dest_val);
+
+ if (!gst_audio_info_convert (&ladspa->info, src_fmt, src_val, dest_fmt,
+ &dest_val)) {
+ GST_DEBUG_OBJECT (ladspa, "query failed");
+ return FALSE;
+ }
+
+ gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
+ res = TRUE;
+ break;
+ }
+ case GST_QUERY_SCHEDULING:
+ {
+ /* if we can operate in pull mode */
+ gst_query_set_scheduling (query, GST_SCHEDULING_FLAG_SEEKABLE, 1, -1, 0);
+ gst_query_add_scheduling_mode (query, GST_PAD_MODE_PUSH);
+ if (ladspa->can_activate_pull)
+ gst_query_add_scheduling_mode (query, GST_PAD_MODE_PULL);
+
+ res = TRUE;
+ break;
+ }
+ default:
+ res =
+ GST_BASE_SRC_CLASS (gst_ladspa_source_type_parent_class)->query
+ (base, query);
+ break;
+ }
+
+ return res;
+}
+
+static void
+gst_ladspa_source_type_get_times (GstBaseSrc * base, GstBuffer * buffer,
+ GstClockTime * start, GstClockTime * end)
+{
+ /* for live sources, sync on the timestamp of the buffer */
+ if (gst_base_src_is_live (base)) {
+ GstClockTime timestamp = GST_BUFFER_TIMESTAMP (buffer);
+
+ if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
+ /* get duration to calculate end time */
+ GstClockTime duration = GST_BUFFER_DURATION (buffer);
+
+ if (GST_CLOCK_TIME_IS_VALID (duration)) {
+ *end = timestamp + duration;
+ }
+ *start = timestamp;
+ }
+ } else {
+ *start = -1;
+ *end = -1;
+ }
+}
+
+/* seek to time, will be called when we operate in push mode. In pull mode we
+ * get the requested byte offset. */
+static gboolean
+gst_ladspa_source_type_do_seek (GstBaseSrc * base, GstSegment * segment)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (base);
+ GstClockTime time;
+ gint samplerate, bpf;
+ gint64 next_sample;
+
+ GST_DEBUG_OBJECT (ladspa, "seeking %" GST_SEGMENT_FORMAT, segment);
+
+ time = segment->position;
+ ladspa->reverse = (segment->rate < 0.0);
+
+ samplerate = GST_AUDIO_INFO_RATE (&ladspa->info);
+ bpf = GST_AUDIO_INFO_BPF (&ladspa->info);
+
+ /* now move to the time indicated, don't seek to the sample *after* the time */
+ next_sample = gst_util_uint64_scale_int (time, samplerate, GST_SECOND);
+ ladspa->next_byte = next_sample * bpf;
+ if (samplerate == 0)
+ ladspa->next_time = 0;
+ else
+ ladspa->next_time =
+ gst_util_uint64_scale_round (next_sample, GST_SECOND, samplerate);
+
+ GST_DEBUG_OBJECT (ladspa, "seeking next_sample=%" G_GINT64_FORMAT
+ " next_time=%" GST_TIME_FORMAT, next_sample,
+ GST_TIME_ARGS (ladspa->next_time));
+
+ g_assert (ladspa->next_time <= time);
+
+ ladspa->next_sample = next_sample;
+
+ if (!ladspa->reverse) {
+ if (GST_CLOCK_TIME_IS_VALID (segment->start)) {
+ segment->time = segment->start;
+ }
+ } else {
+ if (GST_CLOCK_TIME_IS_VALID (segment->stop)) {
+ segment->time = segment->stop;
+ }
+ }
+
+ if (GST_CLOCK_TIME_IS_VALID (segment->stop)) {
+ time = segment->stop;
+ ladspa->sample_stop =
+ gst_util_uint64_scale_round (time, samplerate, GST_SECOND);
+ ladspa->check_seek_stop = TRUE;
+ } else {
+ ladspa->check_seek_stop = FALSE;
+ }
+ ladspa->eos_reached = FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_ladspa_source_type_is_seekable (GstBaseSrc * base)
+{
+ /* we're seekable... */
+ return TRUE;
+}
+
+static GstFlowReturn
+gst_ladspa_source_type_fill (GstBaseSrc * base, guint64 offset,
+ guint length, GstBuffer * buffer)
+{
+ GstLADSPASource *ladspa;
+ GstClockTime next_time;
+ gint64 next_sample, next_byte;
+ gint bytes, samples;
+ GstElementClass *eclass;
+ GstMapInfo map;
+ gint samplerate, bpf;
+
+ ladspa = GST_LADSPA_SOURCE (base);
+
+ /* example for tagging generated data */
+ if (!ladspa->tags_pushed) {
+ GstTagList *taglist;
+
+ taglist = gst_tag_list_new (GST_TAG_DESCRIPTION, "ladspa wave", NULL);
+
+ eclass = GST_ELEMENT_CLASS (gst_ladspa_source_type_parent_class);
+ if (eclass->send_event)
+ eclass->send_event (GST_ELEMENT (base), gst_event_new_tag (taglist));
+ else
+ gst_tag_list_unref (taglist);
+ ladspa->tags_pushed = TRUE;
+ }
+
+ if (ladspa->eos_reached) {
+ GST_INFO_OBJECT (ladspa, "eos");
+ return GST_FLOW_EOS;
+ }
+
+ samplerate = GST_AUDIO_INFO_RATE (&ladspa->info);
+ bpf = GST_AUDIO_INFO_BPF (&ladspa->info);
+
+ /* if no length was given, use our default length in samples otherwise convert
+ * the length in bytes to samples. */
+ if (length == -1)
+ samples = ladspa->samples_per_buffer;
+ else
+ samples = length / bpf;
+
+ /* if no offset was given, use our next logical byte */
+ if (offset == -1)
+ offset = ladspa->next_byte;
+
+ /* now see if we are at the byteoffset we think we are */
+ if (offset != ladspa->next_byte) {
+ GST_DEBUG_OBJECT (ladspa, "seek to new offset %" G_GUINT64_FORMAT, offset);
+ /* we have a discont in the expected sample offset, do a 'seek' */
+ ladspa->next_sample = offset / bpf;
+ ladspa->next_time =
+ gst_util_uint64_scale_int (ladspa->next_sample, GST_SECOND, samplerate);
+ ladspa->next_byte = offset;
+ }
+
+ /* check for eos */
+ if (ladspa->check_seek_stop &&
+ (ladspa->sample_stop > ladspa->next_sample) &&
+ (ladspa->sample_stop < ladspa->next_sample + samples)
+ ) {
+ /* calculate only partial buffer */
+ ladspa->generate_samples_per_buffer =
+ ladspa->sample_stop - ladspa->next_sample;
+ next_sample = ladspa->sample_stop;
+ ladspa->eos_reached = TRUE;
+ } else {
+ /* calculate full buffer */
+ ladspa->generate_samples_per_buffer = samples;
+ next_sample =
+ ladspa->next_sample + (ladspa->reverse ? (-samples) : samples);
+ }
+
+ bytes = ladspa->generate_samples_per_buffer * bpf;
+
+ next_byte = ladspa->next_byte + (ladspa->reverse ? (-bytes) : bytes);
+ next_time = gst_util_uint64_scale_int (next_sample, GST_SECOND, samplerate);
+
+ GST_LOG_OBJECT (ladspa, "samplerate %d", samplerate);
+ GST_LOG_OBJECT (ladspa,
+ "next_sample %" G_GINT64_FORMAT ", ts %" GST_TIME_FORMAT, next_sample,
+ GST_TIME_ARGS (next_time));
+
+ gst_buffer_set_size (buffer, bytes);
+
+ GST_BUFFER_OFFSET (buffer) = ladspa->next_sample;
+ GST_BUFFER_OFFSET_END (buffer) = next_sample;
+ if (!ladspa->reverse) {
+ GST_BUFFER_TIMESTAMP (buffer) =
+ ladspa->timestamp_offset + ladspa->next_time;
+ GST_BUFFER_DURATION (buffer) = next_time - ladspa->next_time;
+ } else {
+ GST_BUFFER_TIMESTAMP (buffer) = ladspa->timestamp_offset + next_time;
+ GST_BUFFER_DURATION (buffer) = ladspa->next_time - next_time;
+ }
+
+ gst_object_sync_values (GST_OBJECT (ladspa), GST_BUFFER_TIMESTAMP (buffer));
+
+ ladspa->next_time = next_time;
+ ladspa->next_sample = next_sample;
+ ladspa->next_byte = next_byte;
+
+ GST_LOG_OBJECT (ladspa, "generating %u samples at ts %" GST_TIME_FORMAT,
+ ladspa->generate_samples_per_buffer,
+ GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (buffer)));
+
+ gst_buffer_map (buffer, &map, GST_MAP_WRITE);
+ gst_ladspa_transform (&ladspa->ladspa, map.data,
+ ladspa->generate_samples_per_buffer, NULL);
+ gst_buffer_unmap (buffer, &map);
+
+ return GST_FLOW_OK;
+}
+
+static gboolean
+gst_ladspa_source_type_start (GstBaseSrc * base)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (base);
+
+ ladspa->next_sample = 0;
+ ladspa->next_byte = 0;
+ ladspa->next_time = 0;
+ ladspa->check_seek_stop = FALSE;
+ ladspa->eos_reached = FALSE;
+ ladspa->tags_pushed = FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_ladspa_source_type_stop (GstBaseSrc * base)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (base);
+ return gst_ladspa_cleanup (&ladspa->ladspa);
+}
+
+static void
+gst_ladspa_source_type_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (object);
+
+ switch (prop_id) {
+ case GST_LADSPA_SOURCE_PROP_SAMPLES_PER_BUFFER:
+ ladspa->samples_per_buffer = g_value_get_int (value);
+ gst_base_src_set_blocksize (GST_BASE_SRC (ladspa),
+ GST_AUDIO_INFO_BPF (&ladspa->info) * ladspa->samples_per_buffer);
+ break;
+ case GST_LADSPA_SOURCE_PROP_IS_LIVE:
+ gst_base_src_set_live (GST_BASE_SRC (ladspa),
+ g_value_get_boolean (value));
+ break;
+ case GST_LADSPA_SOURCE_PROP_TIMESTAMP_OFFSET:
+ ladspa->timestamp_offset = g_value_get_int64 (value);
+ break;
+ case GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PUSH:
+ GST_BASE_SRC (ladspa)->can_activate_push = g_value_get_boolean (value);
+ break;
+ case GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PULL:
+ ladspa->can_activate_pull = g_value_get_boolean (value);
+ break;
+ default:
+ gst_ladspa_object_set_property (&ladspa->ladspa, object, prop_id, value,
+ pspec);
+ break;
+ }
+}
+
+static void
+gst_ladspa_source_type_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (object);
+
+ switch (prop_id) {
+ case GST_LADSPA_SOURCE_PROP_SAMPLES_PER_BUFFER:
+ g_value_set_int (value, ladspa->samples_per_buffer);
+ break;
+ case GST_LADSPA_SOURCE_PROP_IS_LIVE:
+ g_value_set_boolean (value, gst_base_src_is_live (GST_BASE_SRC (ladspa)));
+ break;
+ case GST_LADSPA_SOURCE_PROP_TIMESTAMP_OFFSET:
+ g_value_set_int64 (value, ladspa->timestamp_offset);
+ break;
+ case GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PUSH:
+ g_value_set_boolean (value, GST_BASE_SRC (ladspa)->can_activate_push);
+ break;
+ case GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PULL:
+ g_value_set_boolean (value, ladspa->can_activate_pull);
+ break;
+ default:
+ gst_ladspa_object_get_property (&ladspa->ladspa, object, prop_id, value,
+ pspec);
+ break;
+ }
+}
+
+static void
+gst_ladspa_source_type_init (GstLADSPASource * ladspa,
+ LADSPA_Descriptor * desc)
+{
+ GstLADSPASourceClass *ladspa_class = GST_LADSPA_SOURCE_GET_CLASS (ladspa);
+
+ gst_ladspa_init (&ladspa->ladspa, &ladspa_class->ladspa);
+
+ /* we operate in time */
+ gst_base_src_set_format (GST_BASE_SRC (ladspa), GST_FORMAT_TIME);
+ gst_base_src_set_live (GST_BASE_SRC (ladspa),
+ GST_LADSPA_SOURCE_DEFAULT_IS_LIVE);
+
+ ladspa->samples_per_buffer = GST_LADSPA_SOURCE_DEFAULT_SAMPLES_PER_BUFFER;
+ ladspa->generate_samples_per_buffer = ladspa->samples_per_buffer;
+ ladspa->timestamp_offset = GST_LADSPA_SOURCE_DEFAULT_TIMESTAMP_OFFSET;
+ ladspa->can_activate_pull = GST_LADSPA_SOURCE_DEFAULT_CAN_ACTIVATE_PULL;
+
+ gst_base_src_set_blocksize (GST_BASE_SRC (ladspa), -1);
+}
+
+static void
+gst_ladspa_source_type_dispose (GObject * object)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (object);
+
+ gst_ladspa_cleanup (&ladspa->ladspa);
+
+ G_OBJECT_CLASS (gst_ladspa_source_type_parent_class)->dispose (object);
+}
+
+static void
+gst_ladspa_source_type_finalize (GObject * object)
+{
+ GstLADSPASource *ladspa = GST_LADSPA_SOURCE (object);
+
+ gst_ladspa_finalize (&ladspa->ladspa);
+
+ G_OBJECT_CLASS (gst_ladspa_source_type_parent_class)->finalize (object);
+}
+
+/*
+ * It is okay for plugins to 'leak' a one-time allocation. This will be freed when
+ * the application exits. When the plugins are scanned for the first time, this is
+ * done from a separate process to not impose the memory overhead on the calling
+ * application (among other reasons). Hence no need for class_finalize.
+ */
+static void
+gst_ladspa_source_type_base_init (GstLADSPASourceClass * ladspa_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (ladspa_class);
+ GstElementClass *elem_class = GST_ELEMENT_CLASS (ladspa_class);
+ GstBaseSrcClass *base_class = GST_BASE_SRC_CLASS (ladspa_class);
+ LADSPA_Descriptor *desc;
+
+ desc =
+ g_type_get_qdata (G_OBJECT_CLASS_TYPE (object_class), descriptor_quark);
+ g_assert (desc);
+
+ gst_ladspa_class_init (&ladspa_class->ladspa, desc);
+
+ gst_ladspa_element_class_set_metadata (&ladspa_class->ladspa, elem_class,
+ GST_LADSPA_SOURCE_CLASS_TAGS);
+
+ gst_ladspa_source_type_class_add_pad_template (&ladspa_class->ladspa,
+ base_class);
+}
+
+static void
+gst_ladspa_source_type_base_finalize (GstLADSPASourceClass * ladspa_class)
+{
+ gst_ladspa_class_finalize (&ladspa_class->ladspa);
+}
+
+static void
+gst_ladspa_source_type_class_init (GstLADSPASourceClass * ladspa_class,
+ LADSPA_Descriptor * desc)
+{
+ GObjectClass *object_class = (GObjectClass *) ladspa_class;
+ GstBaseSrcClass *base_class = (GstBaseSrcClass *) ladspa_class;
+
+ gst_ladspa_source_type_parent_class =
+ g_type_class_peek_parent (ladspa_class);
+
+ object_class->dispose =
+ GST_DEBUG_FUNCPTR (gst_ladspa_source_type_dispose);
+ object_class->finalize =
+ GST_DEBUG_FUNCPTR (gst_ladspa_source_type_finalize);
+ object_class->set_property =
+ GST_DEBUG_FUNCPTR (gst_ladspa_source_type_set_property);
+ object_class->get_property =
+ GST_DEBUG_FUNCPTR (gst_ladspa_source_type_get_property);
+
+ base_class->set_caps =
+ GST_DEBUG_FUNCPTR (gst_ladspa_source_type_set_caps);
+ base_class->fixate = GST_DEBUG_FUNCPTR (gst_ladspa_source_type_fixate);
+ base_class->is_seekable =
+ GST_DEBUG_FUNCPTR (gst_ladspa_source_type_is_seekable);
+ base_class->do_seek = GST_DEBUG_FUNCPTR (gst_ladspa_source_type_do_seek);
+ base_class->query = GST_DEBUG_FUNCPTR (gst_ladspa_source_type_query);
+ base_class->get_times =
+ GST_DEBUG_FUNCPTR (gst_ladspa_source_type_get_times);
+ base_class->start = GST_DEBUG_FUNCPTR (gst_ladspa_source_type_start);
+ base_class->stop = GST_DEBUG_FUNCPTR (gst_ladspa_source_type_stop);
+ base_class->fill = GST_DEBUG_FUNCPTR (gst_ladspa_source_type_fill);
+
+ g_object_class_install_property (object_class,
+ GST_LADSPA_SOURCE_PROP_SAMPLES_PER_BUFFER,
+ g_param_spec_int ("samplesperbuffer", "Samples per buffer",
+ "Number of samples in each outgoing buffer", 1, G_MAXINT,
+ GST_LADSPA_SOURCE_DEFAULT_SAMPLES_PER_BUFFER,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class, GST_LADSPA_SOURCE_PROP_IS_LIVE,
+ g_param_spec_boolean ("is-live", "Is Live",
+ "Whether to act as a live source", GST_LADSPA_SOURCE_DEFAULT_IS_LIVE,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ GST_LADSPA_SOURCE_PROP_TIMESTAMP_OFFSET,
+ g_param_spec_int64 ("timestamp-offset", "Timestamp offset",
+ "An offset added to timestamps set on buffers (in ns)", G_MININT64,
+ G_MAXINT64, GST_LADSPA_SOURCE_DEFAULT_TIMESTAMP_OFFSET,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PUSH,
+ g_param_spec_boolean ("can-activate-push", "Can activate push",
+ "Can activate in push mode",
+ GST_LADSPA_SOURCE_DEFAULT_CAN_ACTIVATE_PUSH,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (object_class,
+ GST_LADSPA_SOURCE_PROP_CAN_ACTIVATE_PULL,
+ g_param_spec_boolean ("can-activate-pull", "Can activate pull",
+ "Can activate in pull mode",
+ GST_LADSPA_SOURCE_DEFAULT_CAN_ACTIVATE_PULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+ gst_ladspa_object_class_install_properties (&ladspa_class->ladspa,
+ object_class, GST_LADSPA_SOURCE_PROP_LAST);
+}
+
+G_DEFINE_ABSTRACT_TYPE (GstLADSPASource, gst_ladspa_source, GST_TYPE_BASE_SRC);
+
+static void
+gst_ladspa_source_init (GstLADSPASource * ladspa)
+{
+}
+
+static void
+gst_ladspa_source_class_init (GstLADSPASourceClass * ladspa_class)
+{
+}
+
+/*
+ * Construct the type.
+ */
+void
+ladspa_describe_source_plugin (GstPlugin * plugin,
+ const gchar * filename, const LADSPA_Descriptor * desc)
+{
+ GTypeInfo info = {
+ sizeof (GstLADSPASourceClass),
+ (GBaseInitFunc) gst_ladspa_source_type_base_init,
+ (GBaseFinalizeFunc) gst_ladspa_source_type_base_finalize,
+ (GClassInitFunc) gst_ladspa_source_type_class_init,
+ NULL,
+ desc,
+ sizeof (GstLADSPASource),
+ 0,
+ (GInstanceInitFunc) gst_ladspa_source_type_init,
+ NULL
+ };
+ gchar *tmp;
+
+ tmp = g_strdup_printf ("ladspasrc-%s-%s", filename, desc->Label);
+ ladspa_register_plugin (plugin, GST_TYPE_LADSPA_SOURCE, tmp, &info,
+ descriptor_quark, filename, desc);
+ g_free (tmp);
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * Copyright (C) 2005 Stefan Kost <ensonic@users.sf.net> (audiotestsrc)
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
+ *
+ * gstladspasource.h: Header for LADSPA source
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_LADSPA_SOURCE_H__
+#define __GST_LADSPA_SOURCE_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasesrc.h>
+#include "gstladspautils.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_LADSPA_SOURCE (gst_ladspa_source_get_type())
+#define GST_LADSPA_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_LADSPA_SOURCE,GstLADSPASource))
+#define GST_LADSPA_SOURCE_CAST(obj) ((GstLADSPASource *) (obj))
+#define GST_LADSPA_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_LADSPA_SOURCE,GstLADSPASourceClass))
+#define GST_LADSPA_SOURCE_CLASS_CAST(klass) ((GstLADSPASourceClass *) (klass))
+#define GST_LADSPA_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_LADSPA_SOURCE,GstLADSPASourceClass))
+#define GST_IS_LADSPA_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_LADSPA_SOURCE))
+#define GST_IS_LADSPA_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_LADSPA_SOURCE))
+
+typedef struct _GstLADSPASource GstLADSPASource;
+
+typedef struct _GstLADSPASourceClass GstLADSPASourceClass;
+
+struct _GstLADSPASource
+{
+ GstBaseSrc parent;
+
+ GstLADSPA ladspa;
+
+ /* audio parameters */
+ GstAudioInfo info;
+ gint samples_per_buffer;
+
+ /*< private > */
+ gboolean tags_pushed; /* send tags just once ? */
+ GstClockTimeDiff timestamp_offset; /* base offset */
+ GstClockTime next_time; /* next timestamp */
+ gint64 next_sample; /* next sample to send */
+ gint64 next_byte; /* next byte to send */
+ gint64 sample_stop;
+ gboolean check_seek_stop;
+ gboolean eos_reached;
+ gint generate_samples_per_buffer; /* used to generate a partial buffer */
+ gboolean can_activate_pull;
+ gboolean reverse; /* play backwards */
+};
+
+struct _GstLADSPASourceClass
+{
+ GstBaseSrcClass parent_class;
+
+ GstLADSPAClass ladspa;
+};
+
+GType
+gst_ladspa_source_get_type (void);
+
+void
+ladspa_describe_source_plugin (GstPlugin * plugin,
+ const gchar * filename, const LADSPA_Descriptor * desc);
+
+void
+gst_my_base_source_class_add_pad_template (GstBaseSrcClass * base_class,
+ GstCaps * srccaps);
+
+G_END_DECLS
+
+#endif /* __GST_LADSPA_SOURCE_H__ */
--- /dev/null
+/* GStreamer LADSPA utils
+ * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2001 Steve Baker <stevebaker_org@yahoo.co.uk>
+ * 2003 Andy Wingo <wingo at pobox.com>
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * This module is smartly shared between the source, transform and
+ * sink elements. Handling any specific LADSPA <-> gstreamer interaction.
+ *
+ * FIXME:
+ * Assigning channel orders could be tricky since LADSPA seems to not
+ * specify order of channels in a really nice computer parseable way,
+ * stereo is probably wrong, more than stereo is crazy. LADSPA has
+ * no channel order. All that could be done is to parse the port names
+ * for "(Left)/(Right)", "-L/-R" or ":l/:r" - these are the 3 patterns
+ * seen most of the time. By now, it just let's them pass in / pass out.
+ * Some nice effort might be done to set channel-masks and/or channel
+ * positions correctly, if this is needed and expected, users will tell.
+ *
+ * This affects mainly interleaving, right now, it just interleaves all
+ * input and output ports. This is the right thing in 90% of the cases,
+ * but will e.g. create a 4 channel out for a plugin that has 2 stereo
+ * 'pairs'.
+ *
+ * Also, gstreamer supports not-interleaved audio, where you just memcpy
+ * each channel after each other: c1...c1c2....c2 and so on. This is not
+ * taken into account, but could be added to the _transform and caps easily
+ * if users demands it.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstladspautils.h"
+#include "gstladspafilter.h"
+#include "gstladspasource.h"
+#include "gstladspasink.h"
+
+#include <math.h>
+
+GST_DEBUG_CATEGORY_EXTERN (ladspa_debug);
+#define GST_CAT_DEFAULT ladspa_debug
+
+/*
+ * Interleaved buffer: (c1c2c1c2...)
+ * De-interleaved buffer: (c1c1...c2c2...)
+ */
+static inline void
+gst_ladspa_ladspa_deinterleave_data (GstLADSPA * ladspa, LADSPA_Data * outdata,
+ guint samples, guint8 * indata)
+{
+ guint i, j;
+ const guint audio_in = ladspa->klass->count.audio.in;
+
+ for (i = 0; i < audio_in; i++)
+ for (j = 0; j < samples; j++)
+ outdata[i * samples + j] =
+ ((LADSPA_Data *) indata)[j * audio_in + i];
+}
+
+/*
+ * Interleaved buffer: (c1c2c1c2...)
+ * De-interleaved buffer: (c1c1...c2c2...)
+ */
+static inline void
+gst_ladspa_interleave_ladspa_data (GstLADSPA * ladspa, guint8 * outdata,
+ guint samples, LADSPA_Data * indata)
+{
+ guint i, j;
+ const guint audio_out = ladspa->klass->count.audio.out;
+
+ for (i = 0; i < audio_out; i++)
+ for (j = 0; j < samples; j++)
+ ((LADSPA_Data *) outdata)[j * audio_out + i] =
+ indata[i * samples + j];
+}
+
+/*
+ * Connect the audio in ports.
+ */
+static inline void
+gst_ladspa_connect_audio_in (GstLADSPA * ladspa, guint samples,
+ LADSPA_Data * data)
+{
+ guint i;
+
+ for (i = 0; i < ladspa->klass->count.audio.in; i++) {
+ ladspa->ports.audio.in[i] = data + (i * samples);
+ ladspa->klass->descriptor->connect_port (ladspa->handle,
+ ladspa->klass->map.audio.in[i], ladspa->ports.audio.in[i]);
+ }
+}
+
+/*
+ * Connect the audio out ports.
+ */
+static inline void
+gst_ladspa_connect_audio_out (GstLADSPA * ladspa, guint samples,
+ LADSPA_Data * data)
+{
+ guint i;
+
+ for (i = 0; i < ladspa->klass->count.audio.out; i++) {
+ ladspa->ports.audio.out[i] = data + (i * samples);
+ ladspa->klass->descriptor->connect_port (ladspa->handle,
+ ladspa->klass->map.audio.out[i], ladspa->ports.audio.out[i]);
+ }
+}
+
+/*
+ * Process a block of audio with the ladspa plugin.
+ */
+static inline void
+gst_ladspa_run (GstLADSPA * ladspa, guint nframes)
+{
+ ladspa->klass->descriptor->run (ladspa->handle, nframes);
+}
+
+/*
+ * The data entry/exit point.
+ */
+gboolean
+gst_ladspa_transform (GstLADSPA * ladspa, guint8 * outdata, guint samples,
+ guint8 * indata)
+{
+ LADSPA_Data *in, *out;
+
+ in = g_new0 (LADSPA_Data, samples * ladspa->klass->count.audio.in);
+ out = g_new0 (LADSPA_Data, samples * ladspa->klass->count.audio.out);
+
+ gst_ladspa_ladspa_deinterleave_data (ladspa, in, samples, indata);
+
+ gst_ladspa_connect_audio_in (ladspa, samples, in);
+ gst_ladspa_connect_audio_out (ladspa, samples, out);
+
+ gst_ladspa_run (ladspa, samples);
+
+ gst_ladspa_interleave_ladspa_data (ladspa, outdata, samples, out);
+
+ g_free (out);
+ g_free (in);
+
+ return TRUE;
+}
+
+static gboolean
+gst_ladspa_activate (GstLADSPA * ladspa)
+{
+ g_return_val_if_fail (ladspa->handle != NULL, FALSE);
+ g_return_val_if_fail (ladspa->activated == FALSE, FALSE);
+
+ GST_DEBUG ("activating LADSPA plugin");
+
+ if (ladspa->klass->descriptor->activate)
+ ladspa->klass->descriptor->activate (ladspa->handle);
+
+ ladspa->activated = TRUE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_ladspa_deactivate (GstLADSPA * ladspa)
+{
+ g_return_val_if_fail (ladspa->handle != NULL, FALSE);
+ g_return_val_if_fail (ladspa->activated == TRUE, FALSE);
+
+ GST_DEBUG ("LADSPA deactivating plugin");
+
+ if (ladspa->klass->descriptor->deactivate)
+ ladspa->klass->descriptor->deactivate (ladspa->handle);
+
+ ladspa->activated = FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+gst_ladspa_open (GstLADSPA * ladspa, unsigned long rate)
+{
+ guint i;
+
+ GST_DEBUG ("LADSPA instantiating plugin at %lu Hz", rate);
+
+ if (!(ladspa->handle =
+ ladspa->klass->descriptor->instantiate (ladspa->klass->descriptor,
+ rate))) {
+ GST_WARNING ("could not instantiate LADSPA plugin");
+ return FALSE;
+ }
+
+ ladspa->rate = rate;
+
+ /* connect the control ports */
+ for (i = 0; i < ladspa->klass->count.control.in; i++)
+ ladspa->klass->descriptor->connect_port (ladspa->handle,
+ ladspa->klass->map.control.in[i], &(ladspa->ports.control.in[i]));
+ for (i = 0; i < ladspa->klass->count.control.out; i++)
+ ladspa->klass->descriptor->connect_port (ladspa->handle,
+ ladspa->klass->map.control.out[i], &(ladspa->ports.control.out[i]));
+
+ return TRUE;
+}
+
+static void
+gst_ladspa_close (GstLADSPA * ladspa)
+{
+ g_return_if_fail (ladspa->handle != NULL);
+ g_return_if_fail (ladspa->activated == FALSE);
+
+ GST_DEBUG ("LADSPA deinstantiating plugin");
+
+ if (ladspa->klass->descriptor->cleanup)
+ ladspa->klass->descriptor->cleanup (ladspa->handle);
+
+ ladspa->rate = 0;
+ ladspa->handle = NULL;
+}
+
+/*
+ * Safe open.
+ */
+gboolean
+gst_ladspa_setup (GstLADSPA * ladspa, unsigned long rate)
+{
+ gboolean ret = TRUE;
+
+ GST_DEBUG ("LADSPA setting up plugin");
+
+ if (ladspa->handle && ladspa->rate != rate) {
+ if (ladspa->activated)
+ gst_ladspa_deactivate (ladspa);
+
+ gst_ladspa_close (ladspa);
+ }
+
+ if (!ladspa->handle) {
+ gst_ladspa_open (ladspa, rate);
+ if (!(ret = gst_ladspa_activate (ladspa)))
+ gst_ladspa_close (ladspa);
+ }
+
+ return ret;
+}
+
+/*
+ * Safe close.
+ */
+gboolean
+gst_ladspa_cleanup (GstLADSPA * ladspa)
+{
+ gboolean ret = TRUE;
+
+ GST_DEBUG ("LADSPA cleaning up plugin");
+
+ if (ladspa->handle) {
+ if (ladspa->activated)
+ ret = gst_ladspa_deactivate (ladspa);
+ gst_ladspa_close (ladspa);
+ }
+
+ return ret;
+}
+
+static gchar *
+gst_ladspa_object_class_get_param_name (GstLADSPAClass * ladspa_class,
+ GObjectClass * object_class, unsigned long portnum)
+{
+ LADSPA_Descriptor *desc;
+ gchar *name, **namev, **v, *tmp;
+ guint i;
+
+ desc = ladspa_class->descriptor;
+
+ /* beauty in the mess */
+ name = g_strdup ("");
+ namev = g_strsplit_set (desc->PortNames[portnum], "[]()", 0);
+ for (i = 0, v = namev; *v; i++, v++) {
+ if (!(i % 2)) {
+ tmp = name;
+ name = g_strconcat (name, *v, NULL);
+ g_free (tmp);
+ }
+ }
+ g_strfreev (namev);
+ g_strstrip (name);
+ tmp = name;
+ name = g_ascii_strdown (name, -1);
+ g_free (tmp);
+
+ /* this is the same thing that param_spec_* will do */
+ g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-", '-');
+
+ /* satisfy glib2 (argname[0] must be [A-Za-z]) */
+ if (!((name[0] >= 'a' && name[0] <= 'z') || (name[0] >= 'A'
+ && name[0] <= 'Z'))) {
+ tmp = name;
+ name = g_strconcat ("param-", name, NULL);
+ g_free (tmp);
+ }
+
+ /* check for duplicate property names */
+ if (g_object_class_find_property (G_OBJECT_CLASS (object_class), name)) {
+ gint n = 1;
+ gchar *nprop = g_strdup_printf ("%s-%d", name, n++);
+
+ while (g_object_class_find_property (G_OBJECT_CLASS (object_class), nprop)) {
+ g_free (nprop);
+ nprop = g_strdup_printf ("%s-%d", name, n++);
+ }
+ g_free (name);
+ name = nprop;
+ }
+
+ GST_DEBUG ("LADSPA built property name '%s' from port name '%s'", name,
+ desc->PortNames[portnum]);
+
+ return name;
+}
+
+static GParamSpec *
+gst_ladspa_object_class_get_param_spec (GstLADSPAClass * ladspa_class,
+ GObjectClass * object_class, unsigned long portnum)
+{
+ LADSPA_Descriptor *desc;
+ GParamSpec *ret;
+ gchar *name;
+ gint hintdesc, perms;
+ gfloat lower, upper, def;
+
+ desc = ladspa_class->descriptor;
+
+ name =
+ gst_ladspa_object_class_get_param_name (ladspa_class, object_class,
+ portnum);
+ perms = G_PARAM_READABLE;
+ if (LADSPA_IS_PORT_INPUT (desc->PortDescriptors[portnum]))
+ perms |= G_PARAM_WRITABLE | G_PARAM_CONSTRUCT;
+ if (LADSPA_IS_PORT_CONTROL (desc->PortDescriptors[portnum]))
+ perms |= GST_PARAM_CONTROLLABLE;
+
+ /* short name for hint descriptor */
+ hintdesc = desc->PortRangeHints[portnum].HintDescriptor;
+
+ if (LADSPA_IS_HINT_TOGGLED (hintdesc)) {
+ ret =
+ g_param_spec_boolean (name, name, desc->PortNames[portnum], FALSE,
+ perms);
+ g_free (name);
+ return ret;
+ }
+
+ if (LADSPA_IS_HINT_BOUNDED_BELOW (hintdesc))
+ lower = desc->PortRangeHints[portnum].LowerBound;
+ else
+ lower = -G_MAXFLOAT;
+
+ if (LADSPA_IS_HINT_BOUNDED_ABOVE (hintdesc))
+ upper = desc->PortRangeHints[portnum].UpperBound;
+ else
+ upper = G_MAXFLOAT;
+
+ if (LADSPA_IS_HINT_SAMPLE_RATE (hintdesc)) {
+ /* FIXME:! (*= ladspa->rate?, *= GST_AUDIO_DEF_RATE?) */
+ lower *= 44100;
+ upper *= 44100;
+ }
+
+ if (LADSPA_IS_HINT_INTEGER (hintdesc)) {
+ lower = CLAMP (lower, G_MININT, G_MAXINT);
+ upper = CLAMP (upper, G_MININT, G_MAXINT);
+ }
+
+ /* default to lower bound */
+ def = lower;
+
+#ifdef LADSPA_IS_HINT_HAS_DEFAULT
+ if (LADSPA_IS_HINT_HAS_DEFAULT (hintdesc)) {
+ if (LADSPA_IS_HINT_DEFAULT_0 (hintdesc))
+ def = 0.0;
+ else if (LADSPA_IS_HINT_DEFAULT_1 (hintdesc))
+ def = 1.0;
+ else if (LADSPA_IS_HINT_DEFAULT_100 (hintdesc))
+ def = 100.0;
+ else if (LADSPA_IS_HINT_DEFAULT_440 (hintdesc))
+ def = 440.0;
+ if (LADSPA_IS_HINT_DEFAULT_MINIMUM (hintdesc))
+ def = lower;
+ else if (LADSPA_IS_HINT_DEFAULT_MAXIMUM (hintdesc))
+ def = upper;
+ else if (LADSPA_IS_HINT_LOGARITHMIC (hintdesc)) {
+ if (LADSPA_IS_HINT_DEFAULT_LOW (hintdesc))
+ def = exp (0.75 * log (lower) + 0.25 * log (upper));
+ else if (LADSPA_IS_HINT_DEFAULT_MIDDLE (hintdesc))
+ def = exp (0.5 * log (lower) + 0.5 * log (upper));
+ else if (LADSPA_IS_HINT_DEFAULT_HIGH (hintdesc))
+ def = exp (0.25 * log (lower) + 0.75 * log (upper));
+ } else {
+ if (LADSPA_IS_HINT_DEFAULT_LOW (hintdesc))
+ def = 0.75 * lower + 0.25 * upper;
+ else if (LADSPA_IS_HINT_DEFAULT_MIDDLE (hintdesc))
+ def = 0.5 * lower + 0.5 * upper;
+ else if (LADSPA_IS_HINT_DEFAULT_HIGH (hintdesc))
+ def = 0.25 * lower + 0.75 * upper;
+ }
+ }
+#endif /* LADSPA_IS_HINT_HAS_DEFAULT */
+
+ if (lower > upper) {
+ gfloat tmp;
+
+ /* silently swap */
+ tmp = lower;
+ lower = upper;
+ upper = tmp;
+ }
+
+ def = CLAMP (def, lower, upper);
+
+ if (LADSPA_IS_HINT_INTEGER (hintdesc)) {
+ ret =
+ g_param_spec_int (name, name, desc->PortNames[portnum], lower, upper,
+ def, perms);
+ } else {
+ ret =
+ g_param_spec_float (name, name, desc->PortNames[portnum], lower, upper,
+ def, perms);
+ }
+
+ g_free (name);
+
+ return ret;
+}
+
+void
+gst_ladspa_object_set_property (GstLADSPA * ladspa, GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ /* remember, properties have an offset */
+ prop_id -= ladspa->klass->properties;
+
+ /* only input ports */
+ g_return_if_fail (prop_id < ladspa->klass->count.control.in);
+
+ /* now see what type it is */
+ switch (pspec->value_type) {
+ case G_TYPE_BOOLEAN:
+ ladspa->ports.control.in[prop_id] =
+ g_value_get_boolean (value) ? 1.f : 0.f;
+ break;
+ case G_TYPE_INT:
+ ladspa->ports.control.in[prop_id] = g_value_get_int (value);
+ break;
+ case G_TYPE_FLOAT:
+ ladspa->ports.control.in[prop_id] = g_value_get_float (value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+void
+gst_ladspa_object_get_property (GstLADSPA * ladspa, GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ LADSPA_Data *controls;
+
+ /* remember, properties have an offset */
+ prop_id -= ladspa->klass->properties;
+
+ if (prop_id < ladspa->klass->count.control.in) {
+ controls = ladspa->ports.control.in;
+ } else if (prop_id <
+ ladspa->klass->count.control.in + ladspa->klass->count.control.out) {
+ controls = ladspa->ports.control.out;
+ prop_id -= ladspa->klass->count.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_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+void
+gst_ladspa_object_class_install_properties (GstLADSPAClass * ladspa_class,
+ GObjectClass * object_class, guint offset)
+{
+ GParamSpec *p;
+ gint i, ix;
+
+ ladspa_class->properties = offset;
+
+ /* properties have an offset */
+ ix = ladspa_class->properties;
+
+ /* register properties */
+
+ for (i = 0; i < ladspa_class->count.control.in; i++, ix++) {
+ p = gst_ladspa_object_class_get_param_spec (ladspa_class, object_class,
+ ladspa_class->map.control.in[i]);
+ g_object_class_install_property (object_class, ix, p);
+ }
+ for (i = 0; i < ladspa_class->count.control.out; i++, ix++) {
+ p = gst_ladspa_object_class_get_param_spec (ladspa_class, object_class,
+ ladspa_class->map.control.out[i]);
+ g_object_class_install_property (object_class, ix, p);
+ }
+}
+
+void
+gst_ladspa_element_class_set_metadata (GstLADSPAClass * ladspa_class,
+ GstElementClass * elem_class, const gchar * ladspa_class_tags)
+{
+ LADSPA_Descriptor *desc = ladspa_class->descriptor;
+ gchar *longname, *author, *extra_ladspa_class_tags = NULL, *tmp;
+#ifdef HAVE_LRDF
+ gchar *uri;
+#endif
+
+ longname = g_locale_to_utf8 (desc->Name, -1, NULL, NULL, NULL);
+ if (!longname)
+ longname = g_strdup ("no LADSPA description available");
+
+ /* FIXME: no plugin author field different from element author field */
+ tmp = g_locale_to_utf8 (desc->Maker, -1, NULL, NULL, NULL);
+ if (!tmp)
+ tmp = g_strdup ("no LADSPA author available");
+ author =
+ g_strjoin (", ", tmp,
+ "Juan Manuel Borges Caño <juanmabcmail@gmail.com>",
+ "Andy Wingo <wingo at pobox.com>",
+ "Steve Baker <stevebaker_org@yahoo.co.uk>",
+ "Erik Walthinsen <omega@cse.ogi.edu>",
+ "Stefan Kost <ensonic@users.sf.net>",
+ "Wim Taymans <wim@fluendo.com>", NULL);
+ g_free (tmp);
+
+#ifdef HAVE_LRDF
+ /* libldrf support, we want to get extra klass information here */
+ uri = g_strdup_printf (LADSPA_BASE "%ld", desc->UniqueID);
+ if (uri) {
+ lrdf_statement query = { 0, };
+ lrdf_uris *uris;
+ gchar *str, *base_type = NULL;
+
+ GST_DEBUG ("LADSPA uri (id=%d) : %s", desc->UniqueID, uri);
+
+ /* we can take this directly from 'desc', keep this example for future
+ attributes.
+
+ if ((str = lrdf_get_setting_metadata (uri, "title"))) {
+ GST_DEBUG ("LADSPA title : %s", str);
+ }
+ if ((str = lrdf_get_setting_metadata (uri, "creator"))) {
+ GST_DEBUG ("LADSPA creator : %s", str);
+ }
+ */
+
+ /* get the rdf:type for this plugin */
+ query.subject = uri;
+ query.predicate = (char *) RDF_BASE "type";
+ query.object = (char *) "?";
+ query.next = NULL;
+ uris = lrdf_match_multi (&query);
+ if (uris) {
+ if (uris->ladspa.count == 1) {
+ base_type = g_strdup (uris->items[0]);
+ GST_DEBUG ("LADSPA base_type : %s", base_type);
+ }
+ lrdf_free_uris (uris);
+ }
+
+ /* query taxonomy */
+ if (base_type) {
+ uris = lrdf_get_all_superclasses (base_type);
+ if (uris) {
+ guint32 j;
+
+ for (j = 0; j < uris->ladspa.count; j++) {
+ if ((str = lrdf_get_label (uris->items[j]))) {
+ GST_DEBUG ("LADSPA parent_type_label : %s", str);
+ if (extra_ladspa_class_tags) {
+ gchar *old_tags = extra_ladspa_class_tags;
+ extra_ladspa_class_tags =
+ g_strconcat (extra_ladspa_class_tags, "/", str, NULL);
+ g_free (old_tags);
+ } else {
+ extra_ladspa_class_tags = g_strconcat ("/", str, NULL);
+ }
+ }
+ }
+ lrdf_free_uris (uris);
+ }
+ g_free (base_type);
+ }
+
+ /* we can use this for the presets
+
+ uris = lrdf_get_setting_uris (desc->UniqueID);
+ if (uris) {
+ guint32 j;
+
+ for (j = 0; j < uris->ladspa.count; j++) {
+ GST_INFO ("setting_uri : %s", uris->items[j]);
+ if ((str = lrdf_get_label (uris->items[j]))) {
+ GST_INFO ("setting_label : %s", str);
+ }
+ }
+ lrdf_free_uris (uris);
+ }
+
+ */
+ }
+ g_free (uri);
+
+ if (extra_ladspa_class_tags) {
+ char *s = g_strconcat (ladspa_class_tags, extra_ladspa_class_tags, NULL);
+ g_free (extra_ladspa_class_tags);
+ extra_ladspa_class_tags = s;
+ }
+#endif
+
+ GST_INFO ("tags : %s", ladspa_class_tags);
+ gst_element_class_set_metadata (elem_class, longname,
+ extra_ladspa_class_tags ? extra_ladspa_class_tags : ladspa_class_tags,
+ longname, author);
+
+ g_free (extra_ladspa_class_tags);
+ g_free (author);
+ g_free (longname);
+}
+
+void
+gst_ladspa_filter_type_class_add_pad_templates (GstLADSPAClass *
+ ladspa_class, GstAudioFilterClass * audio_class)
+{
+ GstCaps *srccaps, *sinkcaps;
+
+ srccaps = gst_caps_new_simple ("audio/x-raw",
+ "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+ "channels", G_TYPE_INT, ladspa_class->count.audio.out,
+ "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "layout", G_TYPE_STRING, "interleaved", NULL);
+
+ sinkcaps = gst_caps_new_simple ("audio/x-raw",
+ "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+ "channels", G_TYPE_INT, ladspa_class->count.audio.in,
+ "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "layout", G_TYPE_STRING, "interleaved", NULL);
+
+ gst_my_audio_filter_class_add_pad_templates (audio_class, srccaps, sinkcaps);
+
+ gst_caps_unref (sinkcaps);
+ gst_caps_unref (srccaps);
+}
+
+void
+gst_ladspa_source_type_class_add_pad_template (GstLADSPAClass *
+ ladspa_class, GstBaseSrcClass * base_class)
+{
+ GstCaps *srccaps;
+
+ srccaps = gst_caps_new_simple ("audio/x-raw",
+ "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+ "channels", G_TYPE_INT, ladspa_class->count.audio.out,
+ "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "layout", G_TYPE_STRING, "interleaved", NULL);
+
+ gst_my_base_source_class_add_pad_template (base_class, srccaps);
+
+ gst_caps_unref (srccaps);
+}
+
+void
+gst_ladspa_sink_type_class_add_pad_template (GstLADSPAClass * ladspa_class,
+ GstBaseSinkClass * base_class)
+{
+ GstCaps *sinkcaps;
+
+ sinkcaps = gst_caps_new_simple ("audio/x-raw",
+ "format", G_TYPE_STRING, GST_AUDIO_NE (F32),
+ "channels", G_TYPE_INT, ladspa_class->count.audio.in,
+ "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+ "layout", G_TYPE_STRING, "interleaved", NULL);
+
+ gst_my_base_sink_class_add_pad_template (base_class, sinkcaps);
+
+ gst_caps_unref (sinkcaps);
+}
+
+void
+gst_ladspa_init (GstLADSPA * ladspa, GstLADSPAClass * ladspa_class)
+{
+ GST_DEBUG ("LADSPA initializing component");
+
+ ladspa->klass = ladspa_class;
+
+ ladspa->handle = NULL;
+ ladspa->activated = FALSE;
+ ladspa->rate = 0;
+
+ ladspa->ports.audio.in =
+ g_new0 (LADSPA_Data *, ladspa->klass->count.audio.in);
+ ladspa->ports.audio.out =
+ g_new0 (LADSPA_Data *, ladspa->klass->count.audio.out);
+
+ ladspa->ports.control.in =
+ g_new0 (LADSPA_Data, ladspa->klass->count.control.in);
+ ladspa->ports.control.out =
+ g_new0 (LADSPA_Data, ladspa->klass->count.control.out);
+}
+
+void
+gst_ladspa_finalize (GstLADSPA * ladspa)
+{
+ GST_DEBUG ("LADSPA finalizing component");
+
+ g_free (ladspa->ports.control.out);
+ ladspa->ports.control.out = NULL;
+ g_free (ladspa->ports.control.in);
+ ladspa->ports.control.in = NULL;
+
+ g_free (ladspa->ports.audio.out);
+ ladspa->ports.audio.out = NULL;
+ g_free (ladspa->ports.audio.in);
+ ladspa->ports.audio.in = NULL;
+}
+
+void
+gst_ladspa_class_init (GstLADSPAClass * ladspa_class,
+ LADSPA_Descriptor * descriptor)
+{
+ guint mapper;
+ struct
+ {
+ struct
+ {
+ guint in, out;
+ } control;
+ struct
+ {
+ guint in, out;
+ } audio;
+ } count;
+
+ GST_DEBUG ("LADSPA initializing class");
+
+ ladspa_class->descriptor = descriptor;
+ ladspa_class->properties = 1;
+
+ ladspa_count_ports (ladspa_class->descriptor, &ladspa_class->count.audio.in,
+ &ladspa_class->count.audio.out, &ladspa_class->count.control.in,
+ &ladspa_class->count.control.out);
+
+ ladspa_class->map.audio.in =
+ g_new0 (unsigned long, ladspa_class->count.audio.in);
+ ladspa_class->map.audio.out =
+ g_new0 (unsigned long, ladspa_class->count.audio.out);
+
+ ladspa_class->map.control.in =
+ g_new0 (unsigned long, ladspa_class->count.control.in);
+ ladspa_class->map.control.out =
+ g_new0 (unsigned long, ladspa_class->count.control.out);
+
+ count.audio.in = count.audio.out = count.control.in = count.control.out = 0;
+
+ for (mapper = 0; mapper < ladspa_class->descriptor->PortCount; mapper++) {
+ LADSPA_PortDescriptor p = ladspa_class->descriptor->PortDescriptors[mapper];
+
+ if (LADSPA_IS_PORT_AUDIO (p)) {
+ if (LADSPA_IS_PORT_INPUT (p))
+ ladspa_class->map.audio.in[count.audio.in++] = mapper;
+ else
+ ladspa_class->map.audio.out[count.audio.out++] = mapper;
+ } else if (LADSPA_IS_PORT_CONTROL (p)) {
+ if (LADSPA_IS_PORT_INPUT (p))
+ ladspa_class->map.control.in[count.control.in++] = mapper;
+ else
+ ladspa_class->map.control.out[count.control.out++] = mapper;
+ }
+ }
+
+ g_assert (count.control.out == ladspa_class->count.control.out);
+ g_assert (count.control.in == ladspa_class->count.control.in);
+
+ g_assert (count.audio.out == ladspa_class->count.audio.out);
+ g_assert (count.audio.in == ladspa_class->count.audio.in);
+}
+
+void
+gst_ladspa_class_finalize (GstLADSPAClass * ladspa_class)
+{
+ GST_DEBUG ("LADSPA finalizing class");
+
+ g_free (ladspa_class->map.control.out);
+ ladspa_class->map.control.out = NULL;
+ g_free (ladspa_class->map.control.in);
+ ladspa_class->map.control.in = NULL;
+
+ g_free (ladspa_class->map.audio.out);
+ ladspa_class->map.audio.out = NULL;
+ g_free (ladspa_class->map.audio.in);
+ ladspa_class->map.audio.in = NULL;
+}
+
+void
+ladspa_count_ports (const LADSPA_Descriptor * descriptor,
+ guint * audio_in, guint * audio_out, guint * control_in,
+ guint * control_out)
+{
+ guint i;
+
+ *audio_in = *audio_out = *control_in = *control_out = 0;
+
+ for (i = 0; i < descriptor->PortCount; i++) {
+ LADSPA_PortDescriptor p = descriptor->PortDescriptors[i];
+
+ if (LADSPA_IS_PORT_AUDIO (p)) {
+ if (LADSPA_IS_PORT_INPUT (p))
+ (*audio_in)++;
+ else
+ (*audio_out)++;
+ } else if (LADSPA_IS_PORT_CONTROL (p)) {
+ if (LADSPA_IS_PORT_INPUT (p))
+ (*control_in)++;
+ else
+ (*control_out)++;
+ }
+ }
+}
+
+/*
+ * Register the type.
+ */
+void
+ladspa_register_plugin (GstPlugin * plugin, GType parent_type,
+ const gchar * tmp, const GTypeInfo * info, GQuark descriptor_quark,
+ const gchar * filename, const LADSPA_Descriptor * desc)
+{
+ gchar *name;
+ GType type;
+
+ name = g_ascii_strdown (tmp, -1);
+ g_strcanon (name, G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-+", '-');
+
+ /* if it's not already registered, do it */
+ if (!g_type_from_name (name)) {
+ /* create the type now */
+ type = g_type_register_static (parent_type, name, info, 0);
+
+ /* base init is expected to initialize dynamic data */
+ g_type_set_qdata (type, descriptor_quark, (gpointer) desc);
+
+ /* register the element */
+ gst_element_register (plugin, name, GST_RANK_NONE, type);
+ } else
+ GST_WARNING ("Plugin identifier collision for %s (%s:%lu/%s)", name,
+ filename, desc->UniqueID, desc->Label);
+
+ g_free (name);
+}
--- /dev/null
+/* GStreamer
+ * Copyright (C) 2013 Juan Manuel Borges Caño <juanmabcmail@gmail.com>
+ *
+ * gstladspautils.h: Header for LADSPA plugin utils
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_LADSPA_UTILS_H__
+#define __GST_LADSPA_UTILS_H__
+
+#include <gst/gst.h>
+#include <gst/audio/gstaudiofilter.h>
+#include <gst/base/gstbasesrc.h>
+#include <gst/base/gstbasesink.h>
+
+#include <ladspa.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstLADSPA GstLADSPA;
+
+typedef struct _GstLADSPAClass GstLADSPAClass;
+
+struct _GstLADSPA
+{
+ GstLADSPAClass *klass;
+
+ LADSPA_Handle *handle;
+ gboolean activated;
+ unsigned long rate;
+
+ struct
+ {
+ struct
+ {
+ LADSPA_Data *in;
+ LADSPA_Data *out;
+ } control;
+
+ struct
+ {
+ LADSPA_Data **in;
+ LADSPA_Data **out;
+ } audio;
+ } ports;
+};
+
+struct _GstLADSPAClass
+{
+ guint properties;
+
+ LADSPA_Descriptor *descriptor;
+
+ struct
+ {
+ struct
+ {
+ guint in;
+ guint out;
+ } control;
+
+ struct
+ {
+ guint in;
+ guint out;
+ } audio;
+ } count;
+
+ struct
+ {
+ struct
+ {
+ unsigned long *in;
+ unsigned long *out;
+ } control;
+
+ struct
+ {
+ unsigned long *in;
+ unsigned long *out;
+ } audio;
+ } map;
+};
+
+gboolean
+gst_ladspa_transform (GstLADSPA * ladspa, guint8 * outdata, guint samples,
+ guint8 * indata);
+
+gboolean
+gst_ladspa_setup (GstLADSPA * ladspa, unsigned long rate);
+
+gboolean
+gst_ladspa_cleanup (GstLADSPA * ladspa);
+
+void
+gst_ladspa_object_set_property (GstLADSPA * ladspa, GObject * object,
+ guint prop_id, const GValue * value, GParamSpec * pspec);
+
+void
+gst_ladspa_object_get_property (GstLADSPA * ladspa, GObject * object,
+ guint prop_id, GValue * value, GParamSpec * pspec);
+
+void
+gst_ladspa_object_class_install_properties (GstLADSPAClass * ladspa_class,
+ GObjectClass * object_class, guint offset);
+
+void
+gst_ladspa_element_class_set_metadata (GstLADSPAClass * ladspa_class,
+ GstElementClass * elem_class, const gchar * ladspa_class_tags);
+
+void
+gst_ladspa_filter_type_class_add_pad_templates (GstLADSPAClass * ladspa_class,
+ GstAudioFilterClass * audio_class);
+
+void
+gst_ladspa_source_type_class_add_pad_template (GstLADSPAClass * ladspa_class,
+ GstBaseSrcClass * audio_class);
+
+void
+gst_ladspa_sink_type_class_add_pad_template (GstLADSPAClass * ladspa_class,
+ GstBaseSinkClass * base_class);
+
+void
+gst_ladspa_init (GstLADSPA * ladspa, GstLADSPAClass * ladspa_class);
+
+void
+gst_ladspa_finalize (GstLADSPA * ladspa);
+
+void
+gst_ladspa_class_init (GstLADSPAClass * ladspa_class, LADSPA_Descriptor * desc);
+
+void
+gst_ladspa_class_finalize (GstLADSPAClass * ladspa_class);
+
+void
+ladspa_count_ports (const LADSPA_Descriptor * desc, guint * audio_in,
+ guint * audio_out, guint * control_in, guint * control_out);
+
+void
+ladspa_register_plugin (GstPlugin * plugin, GType parent_type,
+ const gchar * tmp, const GTypeInfo * info, GQuark descriptor_quark,
+ const gchar * filename, const LADSPA_Descriptor * desc);
+
+G_END_DECLS
+
+#endif /* __GST_LADSPA_UTILS_H__ */