mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-19 16:21:17 +00:00
parent
f1a6d84a6c
commit
70e208d08e
12 changed files with 2864 additions and 740 deletions
|
@ -346,7 +346,7 @@ GST_PLUGINS_NONPORTED=" cdxaparse \
|
|||
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"
|
||||
|
|
|
@ -1,15 +1,32 @@
|
|||
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
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* 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
|
||||
|
@ -18,31 +19,131 @@
|
|||
* 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 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.
|
||||
*
|
||||
* 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
|
||||
|
@ -52,666 +153,29 @@
|
|||
"/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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_ladspa_init (GstLADSPA * ladspa, GstLADSPAClass * klass)
|
||||
{
|
||||
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;
|
||||
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]);
|
||||
|
||||
desc->run (ladspa->handle, nframes);
|
||||
}
|
||||
|
||||
static void
|
||||
ladspa_describe_plugin (LADSPA_Descriptor_Function descriptor_function)
|
||||
ladspa_describe_plugin (GstPlugin * plugin,
|
||||
const gchar * filename, LADSPA_Descriptor_Function descriptor_function)
|
||||
{
|
||||
const LADSPA_Descriptor *desc;
|
||||
gint i;
|
||||
guint 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;
|
||||
/* 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;
|
||||
|
||||
/* 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);
|
||||
/* count ports of this plugin */
|
||||
ladspa_count_ports (desc, &audio_in, &audio_out, &control_in, &control_out);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -742,13 +206,11 @@ ladspa_rdf_directory_search (const char *dir_name)
|
|||
|
||||
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;
|
||||
|
@ -773,7 +235,7 @@ ladspa_plugin_directory_search (const char *dir_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. */
|
||||
|
@ -787,10 +249,9 @@ ladspa_plugin_directory_search (const char *dir_name)
|
|||
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;
|
||||
|
@ -825,7 +286,8 @@ ladspa_plugin_path_search (void)
|
|||
}
|
||||
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"))) {
|
||||
|
@ -848,7 +310,7 @@ ladspa_plugin_path_search (void)
|
|||
}
|
||||
if (skip)
|
||||
break;
|
||||
res |= ladspa_plugin_directory_search (paths[i]);
|
||||
res |= ladspa_plugin_directory_search (plugin, paths[i]);
|
||||
}
|
||||
g_strfreev (paths);
|
||||
|
||||
|
@ -860,8 +322,16 @@ ladspa_plugin_path_search (void)
|
|||
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",
|
||||
|
@ -871,14 +341,8 @@ plugin_init (GstPlugin * plugin)
|
|||
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;
|
||||
|
@ -887,5 +351,5 @@ plugin_init (GstPlugin * plugin)
|
|||
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)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* 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
|
||||
*
|
||||
|
@ -19,58 +20,15 @@
|
|||
* 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__ */
|
||||
|
|
374
ext/ladspa/gstladspafilter.c
Normal file
374
ext/ladspa/gstladspafilter.c
Normal file
|
@ -0,0 +1,374 @@
|
|||
/* 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);
|
||||
}
|
72
ext/ladspa/gstladspafilter.h
Normal file
72
ext/ladspa/gstladspafilter.h
Normal file
|
@ -0,0 +1,72 @@
|
|||
/* 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__ */
|
386
ext/ladspa/gstladspasink.c
Normal file
386
ext/ladspa/gstladspasink.c
Normal file
|
@ -0,0 +1,386 @@
|
|||
/* 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);
|
||||
}
|
78
ext/ladspa/gstladspasink.h
Normal file
78
ext/ladspa/gstladspasink.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* 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__ */
|
633
ext/ladspa/gstladspasource.c
Normal file
633
ext/ladspa/gstladspasource.c
Normal file
|
@ -0,0 +1,633 @@
|
|||
/* 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);
|
||||
}
|
90
ext/ladspa/gstladspasource.h
Normal file
90
ext/ladspa/gstladspasource.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* 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__ */
|
892
ext/ladspa/gstladspautils.c
Normal file
892
ext/ladspa/gstladspautils.c
Normal file
|
@ -0,0 +1,892 @@
|
|||
/* 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);
|
||||
}
|
160
ext/ladspa/gstladspautils.h
Normal file
160
ext/ladspa/gstladspautils.h
Normal file
|
@ -0,0 +1,160 @@
|
|||
/* 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__ */
|
Loading…
Reference in a new issue