mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 20:21:24 +00:00
ladspa: Remove the sources from gst-plugins-good
It's disabled anyway and the latest version of it is in gst-plugins-bad. Fixes bug #603779.
This commit is contained in:
parent
ee6d7fd2db
commit
648f0f0b50
10 changed files with 0 additions and 2216 deletions
|
@ -1102,7 +1102,6 @@ ext/flac/Makefile
|
||||||
ext/gconf/Makefile
|
ext/gconf/Makefile
|
||||||
ext/gdk_pixbuf/Makefile
|
ext/gdk_pixbuf/Makefile
|
||||||
ext/hal/Makefile
|
ext/hal/Makefile
|
||||||
ext/ladspa/Makefile
|
|
||||||
ext/libcaca/Makefile
|
ext/libcaca/Makefile
|
||||||
ext/libpng/Makefile
|
ext/libpng/Makefile
|
||||||
ext/pulse/Makefile
|
ext/pulse/Makefile
|
||||||
|
|
|
@ -159,7 +159,6 @@ DIST_SUBDIRS = \
|
||||||
gdk_pixbuf \
|
gdk_pixbuf \
|
||||||
hal \
|
hal \
|
||||||
jpeg \
|
jpeg \
|
||||||
ladspa \
|
|
||||||
libcaca \
|
libcaca \
|
||||||
libpng \
|
libpng \
|
||||||
pulse \
|
pulse \
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
plugin_LTLIBRARIES = libgstladspa.la
|
|
||||||
|
|
||||||
libgstladspa_la_SOURCES = gstsignalprocessor.c gstladspa.c search.c load.c
|
|
||||||
libgstladspa_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_CFLAGS)
|
|
||||||
libgstladspa_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) -lgstaudio-$(GST_MAJORMINOR)
|
|
||||||
libgstladspa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
|
||||||
libgstladspa_la_LIBTOOLFLAGS = --tag=disable-static
|
|
||||||
|
|
||||||
noinst_HEADERS = gstsignalprocessor.h gstladspa.h utils.h
|
|
|
@ -1,635 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
|
||||||
* <2001> Steve Baker <stevebaker_org@yahoo.co.uk>
|
|
||||||
* 2003 Andy Wingo <wingo at pobox.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
#include <string.h>
|
|
||||||
#include <math.h>
|
|
||||||
#include <gst/audio/audio.h>
|
|
||||||
|
|
||||||
#include "gstladspa.h"
|
|
||||||
#include <ladspa.h> /* main ladspa sdk include file */
|
|
||||||
#include "utils.h" /* ladspa sdk utility functions */
|
|
||||||
|
|
||||||
/* 1.0 and the 1.1 preliminary headers don't define a version, but 1.1 final
|
|
||||||
does */
|
|
||||||
#ifndef LADSPA_VERSION
|
|
||||||
#define LADSPA_VERSION "1.0"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GST_BOILERPLATE (GstLADSPA, gst_ladspa, GstSignalProcessor,
|
|
||||||
GST_TYPE_SIGNAL_PROCESSOR);
|
|
||||||
|
|
||||||
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,
|
|
||||||
guint sample_rate);
|
|
||||||
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 GstPlugin *ladspa_plugin;
|
|
||||||
static GHashTable *ladspa_descriptors;
|
|
||||||
|
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (ladspa_debug);
|
|
||||||
#define GST_CAT_DEFAULT ladspa_debug
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
|
||||||
GstElementDetails *details;
|
|
||||||
LADSPA_Descriptor *desc;
|
|
||||||
gint j, sinkcount, srccount;
|
|
||||||
|
|
||||||
GST_DEBUG ("base_init %p", g_class);
|
|
||||||
|
|
||||||
desc = g_hash_table_lookup (ladspa_descriptors,
|
|
||||||
GINT_TO_POINTER (G_TYPE_FROM_CLASS (klass)));
|
|
||||||
if (!desc)
|
|
||||||
desc = g_hash_table_lookup (ladspa_descriptors, GINT_TO_POINTER (0));
|
|
||||||
g_assert (desc);
|
|
||||||
klass->descriptor = desc;
|
|
||||||
g_assert (desc);
|
|
||||||
|
|
||||||
/* pad templates */
|
|
||||||
gsp_class->num_audio_in = 0;
|
|
||||||
gsp_class->num_audio_out = 0;
|
|
||||||
/* control gets set in the class init */
|
|
||||||
|
|
||||||
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]);
|
|
||||||
|
|
||||||
GST_DEBUG ("LADSPA port name: \"%s\"", 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++);
|
|
||||||
else
|
|
||||||
gst_signal_processor_class_add_pad_template (gsp_class, name,
|
|
||||||
GST_PAD_SRC, gsp_class->num_audio_out++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* construct the element details struct */
|
|
||||||
details = g_new0 (GstElementDetails, 1);
|
|
||||||
details->longname = g_locale_to_utf8 (desc->Name, -1, NULL, NULL, NULL);
|
|
||||||
if (!details->longname)
|
|
||||||
details->longname = g_strdup ("no description available");
|
|
||||||
details->description = details->longname;
|
|
||||||
details->author = g_locale_to_utf8 (desc->Maker, -1, NULL, NULL, NULL);
|
|
||||||
if (!details->author)
|
|
||||||
details->author = g_strdup ("no author available");
|
|
||||||
if (gsp_class->num_audio_in == 0)
|
|
||||||
details->klass = "Source/Audio/LADSPA";
|
|
||||||
else if (gsp_class->num_audio_out == 0)
|
|
||||||
details->klass = "Sink/Audio/LADSPA";
|
|
||||||
else
|
|
||||||
details->klass = "Filter/Effect/Audio/LADSPA";
|
|
||||||
gst_element_class_set_details (element_class, details);
|
|
||||||
|
|
||||||
klass->audio_in_portnums = g_new0 (gint, gsp_class->num_audio_in);
|
|
||||||
klass->audio_out_portnums = g_new0 (gint, gsp_class->num_audio_out);
|
|
||||||
|
|
||||||
sinkcount = srccount = 0;
|
|
||||||
for (j = 0; j < desc->PortCount; j++) {
|
|
||||||
if (LADSPA_IS_PORT_AUDIO (desc->PortDescriptors[j])) {
|
|
||||||
if (LADSPA_IS_PORT_INPUT (desc->PortDescriptors[j]))
|
|
||||||
klass->audio_in_portnums[sinkcount++] = j;
|
|
||||||
else
|
|
||||||
klass->audio_out_portnums[srccount++] = j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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++);
|
|
||||||
}
|
|
||||||
ret = nret;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
/* 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)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class;
|
|
||||||
GstSignalProcessorClass *gsp_class;
|
|
||||||
LADSPA_Descriptor *desc;
|
|
||||||
gint i, control_in_count, control_out_count;
|
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
desc = klass->descriptor;
|
|
||||||
g_assert (desc);
|
|
||||||
|
|
||||||
gsp_class->num_control_in = 0;
|
|
||||||
gsp_class->num_control_out = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < desc->PortCount; i++) {
|
|
||||||
LADSPA_PortDescriptor p = desc->PortDescriptors[i];
|
|
||||||
|
|
||||||
if (!LADSPA_IS_PORT_AUDIO (p)) {
|
|
||||||
if (LADSPA_IS_PORT_INPUT (p))
|
|
||||||
gsp_class->num_control_in++;
|
|
||||||
else
|
|
||||||
gsp_class->num_control_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);
|
|
||||||
|
|
||||||
control_in_count = control_out_count = 0;
|
|
||||||
for (i = 0; i < desc->PortCount; i++) {
|
|
||||||
LADSPA_PortDescriptor p = desc->PortDescriptors[i];
|
|
||||||
|
|
||||||
if (!LADSPA_IS_PORT_AUDIO (p)) {
|
|
||||||
if (LADSPA_IS_PORT_INPUT (p))
|
|
||||||
klass->control_in_portnums[control_in_count++] = i;
|
|
||||||
else
|
|
||||||
klass->control_out_portnums[control_out_count++] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
g_assert (control_in_count == gsp_class->num_control_in);
|
|
||||||
g_assert (control_out_count == gsp_class->num_control_out);
|
|
||||||
|
|
||||||
for (i = 0; i < gsp_class->num_control_in; i++) {
|
|
||||||
GParamSpec *p;
|
|
||||||
|
|
||||||
p = gst_ladspa_class_get_param_spec (klass, klass->control_in_portnums[i]);
|
|
||||||
|
|
||||||
/* properties have an offset of 1 */
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass), i + 1, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < gsp_class->num_control_out; i++) {
|
|
||||||
GParamSpec *p;
|
|
||||||
|
|
||||||
p = gst_ladspa_class_get_param_spec (klass, klass->control_out_portnums[i]);
|
|
||||||
|
|
||||||
/* properties have an offset of 1, and we already added num_control_in */
|
|
||||||
g_object_class_install_property (G_OBJECT_CLASS (klass),
|
|
||||||
gsp_class->num_control_in + i + 1, p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_ladspa_init (GstLADSPA * ladspa, GstLADSPAClass * klass)
|
|
||||||
{
|
|
||||||
/* whoopee, nothing to do */
|
|
||||||
|
|
||||||
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_assert_not_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_assert_not_reached ();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_ladspa_setup (GstSignalProcessor * gsp, guint sample_rate)
|
|
||||||
{
|
|
||||||
GstLADSPA *ladspa;
|
|
||||||
GstLADSPAClass *oclass;
|
|
||||||
GstSignalProcessorClass *gsp_class;
|
|
||||||
LADSPA_Descriptor *desc;
|
|
||||||
int 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", sample_rate);
|
|
||||||
|
|
||||||
ladspa->handle = desc->instantiate (desc, sample_rate);
|
|
||||||
|
|
||||||
g_return_val_if_fail (ladspa->handle != NULL, FALSE);
|
|
||||||
|
|
||||||
/* connect the control ports */
|
|
||||||
for (i = 0; i < gsp_class->num_control_in; i++)
|
|
||||||
desc->connect_port (ladspa->handle,
|
|
||||||
oclass->control_in_portnums[i], &(gsp->control_in[i]));
|
|
||||||
for (i = 0; i < gsp_class->num_control_out; i++)
|
|
||||||
desc->connect_port (ladspa->handle,
|
|
||||||
oclass->control_out_portnums[i], &(gsp->control_out[i]));
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 (const char *pcFullFilename,
|
|
||||||
void *pvPluginHandle, LADSPA_Descriptor_Function pfDescriptorFunction)
|
|
||||||
{
|
|
||||||
const LADSPA_Descriptor *desc;
|
|
||||||
gint i;
|
|
||||||
GTypeInfo typeinfo = {
|
|
||||||
sizeof (GstLADSPAClass),
|
|
||||||
(GBaseInitFunc) gst_ladspa_base_init,
|
|
||||||
NULL,
|
|
||||||
(GClassInitFunc) gst_ladspa_class_init,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
sizeof (GstLADSPA),
|
|
||||||
0,
|
|
||||||
(GInstanceInitFunc) gst_ladspa_init,
|
|
||||||
};
|
|
||||||
GType type;
|
|
||||||
|
|
||||||
/* walk through all the plugins in this pluginlibrary */
|
|
||||||
i = 0;
|
|
||||||
while ((desc = pfDescriptorFunction (i++))) {
|
|
||||||
gchar *type_name;
|
|
||||||
|
|
||||||
/* 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)) {
|
|
||||||
g_free (type_name);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* base-init temp alloc */
|
|
||||||
g_hash_table_insert (ladspa_descriptors,
|
|
||||||
GINT_TO_POINTER (0), (gpointer) desc);
|
|
||||||
|
|
||||||
/* create the type now */
|
|
||||||
type =
|
|
||||||
g_type_register_static (GST_TYPE_SIGNAL_PROCESSOR, type_name, &typeinfo,
|
|
||||||
0);
|
|
||||||
if (!gst_element_register (ladspa_plugin, type_name, GST_RANK_NONE, type))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* add this plugin to the hash */
|
|
||||||
g_hash_table_insert (ladspa_descriptors,
|
|
||||||
GINT_TO_POINTER (type), (gpointer) desc);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_hash_table_remove (ladspa_descriptors, GINT_TO_POINTER (0));
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
|
||||||
|
|
||||||
ladspa_descriptors = g_hash_table_new (NULL, NULL);
|
|
||||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
|
||||||
|
|
||||||
ladspa_plugin = plugin;
|
|
||||||
|
|
||||||
LADSPAPluginSearch (ladspa_describe_plugin);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
|
||||||
GST_VERSION_MINOR,
|
|
||||||
"ladspa",
|
|
||||||
"All LADSPA plugins",
|
|
||||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)
|
|
|
@ -1,76 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
|
||||||
*
|
|
||||||
* gstladspa.h: Header for LADSPA plugin
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __GST_LADSPA_H__
|
|
||||||
#define __GST_LADSPA_H__
|
|
||||||
|
|
||||||
|
|
||||||
#include <ladspa.h>
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
#include "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;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_LADSPA_H__ */
|
|
|
@ -1,976 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
||||||
* 2000 Wim Taymans <wtay@chello.be>
|
|
||||||
* 2005 Wim Taymans <wim@fluendo.com>
|
|
||||||
*
|
|
||||||
* gstsignalprocessor.c:
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <gst/audio/audio.h>
|
|
||||||
#include "gstsignalprocessor.h"
|
|
||||||
|
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_STATIC (gst_signal_processor_debug);
|
|
||||||
#define GST_CAT_DEFAULT gst_signal_processor_debug
|
|
||||||
|
|
||||||
|
|
||||||
static GstStaticCaps template_caps =
|
|
||||||
GST_STATIC_CAPS (GST_AUDIO_FLOAT_STANDARD_PAD_TEMPLATE_CAPS);
|
|
||||||
|
|
||||||
#define GST_TYPE_SIGNAL_PROCESSOR_PAD_TEMPLATE \
|
|
||||||
(gst_signal_processor_pad_template_get_type ())
|
|
||||||
#define GST_SIGNAL_PROCESSOR_PAD_TEMPLATE(obj) \
|
|
||||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SIGNAL_PROCESSOR_PAD_TEMPLATE,\
|
|
||||||
GstSignalProcessorPadTemplate))
|
|
||||||
typedef struct _GstSignalProcessorPadTemplate GstSignalProcessorPadTemplate;
|
|
||||||
typedef GstPadTemplateClass GstSignalProcessorPadTemplateClass;
|
|
||||||
|
|
||||||
struct _GstSignalProcessorPadTemplate
|
|
||||||
{
|
|
||||||
GstPadTemplate parent;
|
|
||||||
|
|
||||||
guint index;
|
|
||||||
};
|
|
||||||
|
|
||||||
static GType
|
|
||||||
gst_signal_processor_pad_template_get_type (void)
|
|
||||||
{
|
|
||||||
static GType type = 0;
|
|
||||||
|
|
||||||
if (!type) {
|
|
||||||
static const GTypeInfo info = {
|
|
||||||
sizeof (GstSignalProcessorPadTemplateClass), NULL, NULL, NULL, NULL,
|
|
||||||
NULL, sizeof (GstSignalProcessorPadTemplate), 0, NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
type = g_type_register_static (GST_TYPE_PAD_TEMPLATE,
|
|
||||||
"GstSignalProcessorPadTemplate", &info, 0);
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
gst_signal_processor_class_add_pad_template (GstSignalProcessorClass * klass,
|
|
||||||
const gchar * name, GstPadDirection direction, guint index)
|
|
||||||
{
|
|
||||||
GstPadTemplate *new;
|
|
||||||
|
|
||||||
g_return_if_fail (GST_IS_SIGNAL_PROCESSOR_CLASS (klass));
|
|
||||||
g_return_if_fail (name != NULL);
|
|
||||||
g_return_if_fail (direction == GST_PAD_SRC || direction == GST_PAD_SINK);
|
|
||||||
|
|
||||||
new = g_object_new (gst_signal_processor_pad_template_get_type (),
|
|
||||||
"name", name, NULL);
|
|
||||||
|
|
||||||
GST_PAD_TEMPLATE_NAME_TEMPLATE (new) = g_strdup (name);
|
|
||||||
GST_PAD_TEMPLATE_DIRECTION (new) = direction;
|
|
||||||
GST_PAD_TEMPLATE_PRESENCE (new) = GST_PAD_ALWAYS;
|
|
||||||
GST_PAD_TEMPLATE_CAPS (new) = gst_caps_copy (gst_static_caps_get
|
|
||||||
(&template_caps));
|
|
||||||
GST_SIGNAL_PROCESSOR_PAD_TEMPLATE (new)->index = index;
|
|
||||||
|
|
||||||
gst_element_class_add_pad_template (GST_ELEMENT_CLASS (klass), new);
|
|
||||||
gst_object_unref (new);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_SIGNAL_PROCESSOR_PAD (gst_signal_processor_pad_get_type ())
|
|
||||||
#define GST_SIGNAL_PROCESSOR_PAD(obj) \
|
|
||||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SIGNAL_PROCESSOR_PAD,\
|
|
||||||
GstSignalProcessorPad))
|
|
||||||
typedef struct _GstSignalProcessorPad GstSignalProcessorPad;
|
|
||||||
typedef GstPadClass GstSignalProcessorPadClass;
|
|
||||||
|
|
||||||
struct _GstSignalProcessorPad
|
|
||||||
{
|
|
||||||
GstPad parent;
|
|
||||||
|
|
||||||
GstBuffer *pen;
|
|
||||||
|
|
||||||
guint index;
|
|
||||||
|
|
||||||
/* these are only used for sink pads */
|
|
||||||
guint samples_avail;
|
|
||||||
gfloat *data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static GType
|
|
||||||
gst_signal_processor_pad_get_type (void)
|
|
||||||
{
|
|
||||||
static GType type = 0;
|
|
||||||
|
|
||||||
if (!type) {
|
|
||||||
static const GTypeInfo info = {
|
|
||||||
sizeof (GstSignalProcessorPadClass), NULL, NULL, NULL, NULL,
|
|
||||||
NULL, sizeof (GstSignalProcessorPad), 0, NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
type = g_type_register_static (GST_TYPE_PAD,
|
|
||||||
"GstSignalProcessorPad", &info, 0);
|
|
||||||
}
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GST_BOILERPLATE (GstSignalProcessor, gst_signal_processor, GstElement,
|
|
||||||
GST_TYPE_ELEMENT);
|
|
||||||
|
|
||||||
|
|
||||||
static void gst_signal_processor_finalize (GObject * object);
|
|
||||||
static void gst_signal_processor_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec);
|
|
||||||
static void gst_signal_processor_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec);
|
|
||||||
static gboolean gst_signal_processor_src_activate_pull (GstPad * pad,
|
|
||||||
gboolean active);
|
|
||||||
static gboolean gst_signal_processor_sink_activate_push (GstPad * pad,
|
|
||||||
gboolean active);
|
|
||||||
static GstStateChangeReturn gst_signal_processor_change_state (GstElement *
|
|
||||||
element, GstStateChange transition);
|
|
||||||
|
|
||||||
static gboolean gst_signal_processor_event (GstPad * pad, GstEvent * event);
|
|
||||||
static GstFlowReturn gst_signal_processor_getrange (GstPad * pad,
|
|
||||||
guint64 offset, guint length, GstBuffer ** buffer);
|
|
||||||
static GstFlowReturn gst_signal_processor_chain (GstPad * pad,
|
|
||||||
GstBuffer * buffer);
|
|
||||||
static gboolean gst_signal_processor_setcaps (GstPad * pad, GstCaps * caps);
|
|
||||||
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_base_init (gpointer g_class)
|
|
||||||
{
|
|
||||||
GST_DEBUG_CATEGORY_INIT (gst_signal_processor_debug, "gst-dsp", 0,
|
|
||||||
"signalprocessor element");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_class_init (GstSignalProcessorClass * klass)
|
|
||||||
{
|
|
||||||
GObjectClass *gobject_class;
|
|
||||||
GstElementClass *gstelement_class;
|
|
||||||
|
|
||||||
gobject_class = G_OBJECT_CLASS (klass);
|
|
||||||
gstelement_class = GST_ELEMENT_CLASS (klass);
|
|
||||||
|
|
||||||
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_signal_processor_finalize);
|
|
||||||
gobject_class->set_property =
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_set_property);
|
|
||||||
gobject_class->get_property =
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_get_property);
|
|
||||||
|
|
||||||
gstelement_class->change_state =
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_change_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_add_pad_from_template (GstSignalProcessor * self,
|
|
||||||
GstPadTemplate * templ)
|
|
||||||
{
|
|
||||||
GstPad *new;
|
|
||||||
|
|
||||||
new = g_object_new (GST_TYPE_SIGNAL_PROCESSOR_PAD,
|
|
||||||
"name", GST_OBJECT_NAME (templ), "direction", templ->direction,
|
|
||||||
"template", templ, NULL);
|
|
||||||
GST_SIGNAL_PROCESSOR_PAD (new)->index =
|
|
||||||
GST_SIGNAL_PROCESSOR_PAD_TEMPLATE (templ)->index;
|
|
||||||
|
|
||||||
gst_pad_set_setcaps_function (new,
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_setcaps));
|
|
||||||
|
|
||||||
if (templ->direction == GST_PAD_SINK) {
|
|
||||||
GST_DEBUG ("added new sink pad");
|
|
||||||
|
|
||||||
gst_pad_set_event_function (new,
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_event));
|
|
||||||
gst_pad_set_chain_function (new,
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_chain));
|
|
||||||
gst_pad_set_activatepush_function (new,
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_sink_activate_push));
|
|
||||||
} else {
|
|
||||||
GST_DEBUG ("added new src pad");
|
|
||||||
|
|
||||||
gst_pad_set_getrange_function (new,
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_getrange));
|
|
||||||
gst_pad_set_activatepull_function (new,
|
|
||||||
GST_DEBUG_FUNCPTR (gst_signal_processor_src_activate_pull));
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_element_add_pad (GST_ELEMENT (self), new);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_init (GstSignalProcessor * self,
|
|
||||||
GstSignalProcessorClass * klass)
|
|
||||||
{
|
|
||||||
GList *templates;
|
|
||||||
|
|
||||||
templates =
|
|
||||||
gst_element_class_get_pad_template_list (GST_ELEMENT_CLASS (klass));
|
|
||||||
|
|
||||||
while (templates) {
|
|
||||||
GstPadTemplate *templ = GST_PAD_TEMPLATE (templates->data);
|
|
||||||
|
|
||||||
gst_signal_processor_add_pad_from_template (self, templ);
|
|
||||||
templates = templates->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
self->state = GST_SIGNAL_PROCESSOR_STATE_NULL;
|
|
||||||
|
|
||||||
self->audio_in = g_new0 (gfloat *, klass->num_audio_in);
|
|
||||||
self->control_in = g_new0 (gfloat, klass->num_control_in);
|
|
||||||
self->audio_out = g_new0 (gfloat *, klass->num_audio_out);
|
|
||||||
self->control_out = g_new0 (gfloat, klass->num_control_out);
|
|
||||||
|
|
||||||
/* init */
|
|
||||||
self->pending_in = klass->num_audio_in;
|
|
||||||
self->pending_out = 0;
|
|
||||||
|
|
||||||
self->sample_rate = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_finalize (GObject * object)
|
|
||||||
{
|
|
||||||
GstSignalProcessor *self = GST_SIGNAL_PROCESSOR (object);
|
|
||||||
|
|
||||||
g_free (self->audio_in);
|
|
||||||
self->audio_in = NULL;
|
|
||||||
g_free (self->control_in);
|
|
||||||
self->control_in = NULL;
|
|
||||||
g_free (self->audio_out);
|
|
||||||
self->audio_out = NULL;
|
|
||||||
g_free (self->control_out);
|
|
||||||
self->control_out = NULL;
|
|
||||||
|
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_signal_processor_setup (GstSignalProcessor * self, guint sample_rate)
|
|
||||||
{
|
|
||||||
GstSignalProcessorClass *klass;
|
|
||||||
gboolean ret = TRUE;
|
|
||||||
|
|
||||||
klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (self, "setup()");
|
|
||||||
|
|
||||||
g_return_val_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_NULL, FALSE);
|
|
||||||
|
|
||||||
if (klass->setup)
|
|
||||||
ret = klass->setup (self, sample_rate);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
goto setup_failed;
|
|
||||||
|
|
||||||
self->state = GST_SIGNAL_PROCESSOR_STATE_INITIALIZED;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
setup_failed:
|
|
||||||
{
|
|
||||||
GST_INFO_OBJECT (self, "setup() failed at %u Hz", sample_rate);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_signal_processor_start (GstSignalProcessor * self)
|
|
||||||
{
|
|
||||||
GstSignalProcessorClass *klass;
|
|
||||||
gboolean ret = TRUE;
|
|
||||||
|
|
||||||
klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
g_return_val_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_INITIALIZED,
|
|
||||||
FALSE);
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (self, "start()");
|
|
||||||
|
|
||||||
if (klass->start)
|
|
||||||
ret = klass->start (self);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
goto start_failed;
|
|
||||||
|
|
||||||
self->state = GST_SIGNAL_PROCESSOR_STATE_RUNNING;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
start_failed:
|
|
||||||
{
|
|
||||||
GST_INFO_OBJECT (self, "start() failed");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_stop (GstSignalProcessor * self)
|
|
||||||
{
|
|
||||||
GstSignalProcessorClass *klass;
|
|
||||||
GstElement *elem;
|
|
||||||
GList *sinks;
|
|
||||||
|
|
||||||
klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
elem = GST_ELEMENT (self);
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (self, "stop()");
|
|
||||||
|
|
||||||
g_return_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_RUNNING);
|
|
||||||
|
|
||||||
if (klass->stop)
|
|
||||||
klass->stop (self);
|
|
||||||
|
|
||||||
for (sinks = elem->sinkpads; sinks; sinks = sinks->next)
|
|
||||||
/* force set_caps when going to RUNNING, see note in set_caps */
|
|
||||||
gst_pad_set_caps (GST_PAD (sinks->data), NULL);
|
|
||||||
|
|
||||||
/* should also flush our buffers perhaps? */
|
|
||||||
|
|
||||||
self->state = GST_SIGNAL_PROCESSOR_STATE_INITIALIZED;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_cleanup (GstSignalProcessor * self)
|
|
||||||
{
|
|
||||||
GstSignalProcessorClass *klass;
|
|
||||||
|
|
||||||
klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (self, "cleanup()");
|
|
||||||
|
|
||||||
g_return_if_fail (self->state == GST_SIGNAL_PROCESSOR_STATE_INITIALIZED);
|
|
||||||
|
|
||||||
if (klass->cleanup)
|
|
||||||
klass->cleanup (self);
|
|
||||||
|
|
||||||
self->state = GST_SIGNAL_PROCESSOR_STATE_NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_signal_processor_setcaps (GstPad * pad, GstCaps * caps)
|
|
||||||
{
|
|
||||||
GstSignalProcessor *self;
|
|
||||||
|
|
||||||
self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
|
|
||||||
|
|
||||||
/* the whole processor has one caps; if the sample rate changes, let subclass
|
|
||||||
implementations know */
|
|
||||||
if (!gst_caps_is_equal (caps, self->caps)) {
|
|
||||||
GstStructure *s;
|
|
||||||
gint sample_rate;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (pad, "got caps %" GST_PTR_FORMAT, caps);
|
|
||||||
|
|
||||||
s = gst_caps_get_structure (caps, 0);
|
|
||||||
if (!gst_structure_get_int (s, "rate", &sample_rate)) {
|
|
||||||
GST_WARNING ("got no sample-rate");
|
|
||||||
goto impossible;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "Got rate=%d", sample_rate);
|
|
||||||
|
|
||||||
if (GST_SIGNAL_PROCESSOR_IS_RUNNING (self))
|
|
||||||
gst_signal_processor_stop (self);
|
|
||||||
if (GST_SIGNAL_PROCESSOR_IS_INITIALIZED (self))
|
|
||||||
gst_signal_processor_cleanup (self);
|
|
||||||
|
|
||||||
if (!gst_signal_processor_setup (self, sample_rate))
|
|
||||||
goto start_failed;
|
|
||||||
|
|
||||||
self->sample_rate = sample_rate;
|
|
||||||
gst_caps_replace (&self->caps, caps);
|
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (self, "skipping, have caps already");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* we use this method to manage the processor's state, hence the caps clearing
|
|
||||||
in stop(). so it can be that we enter here just to manage the processor's
|
|
||||||
state, to take it to RUNNING from already being INITIALIZED with the right
|
|
||||||
sample rate (e.g., when having gone PLAYING->READY->PLAYING). make sure
|
|
||||||
when we leave that the processor is RUNNING. */
|
|
||||||
if (!GST_SIGNAL_PROCESSOR_IS_INITIALIZED (self)
|
|
||||||
&& !gst_signal_processor_setup (self, self->sample_rate))
|
|
||||||
goto start_failed;
|
|
||||||
if (!GST_SIGNAL_PROCESSOR_IS_RUNNING (self)
|
|
||||||
&& !gst_signal_processor_start (self))
|
|
||||||
goto start_failed;
|
|
||||||
|
|
||||||
gst_object_unref (self);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
start_failed:
|
|
||||||
{
|
|
||||||
gst_object_unref (self);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
impossible:
|
|
||||||
{
|
|
||||||
g_critical ("something impossible happened");
|
|
||||||
gst_object_unref (self);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_signal_processor_event (GstPad * pad, GstEvent * event)
|
|
||||||
{
|
|
||||||
GstSignalProcessor *self;
|
|
||||||
GstSignalProcessorClass *bclass;
|
|
||||||
gboolean ret;
|
|
||||||
|
|
||||||
self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
|
|
||||||
bclass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
/* this probably isn't the correct interface: what about return values, what
|
|
||||||
about overriding event_default */
|
|
||||||
if (bclass->event)
|
|
||||||
bclass->event (self, event);
|
|
||||||
|
|
||||||
switch (GST_EVENT_TYPE (event)) {
|
|
||||||
case GST_EVENT_FLUSH_START:
|
|
||||||
break;
|
|
||||||
case GST_EVENT_FLUSH_STOP:
|
|
||||||
/* clear errors now */
|
|
||||||
self->flow_state = GST_FLOW_OK;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ret = gst_pad_event_default (pad, event);
|
|
||||||
|
|
||||||
gst_object_unref (self);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static guint
|
|
||||||
gst_signal_processor_prepare (GstSignalProcessor * self)
|
|
||||||
{
|
|
||||||
GstElement *elem = (GstElement *) self;
|
|
||||||
GstSignalProcessorClass *klass;
|
|
||||||
GList *sinks, *srcs;
|
|
||||||
guint samples_avail = G_MAXUINT;
|
|
||||||
|
|
||||||
klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
/* first, assign audio_in pointers, and determine the number of samples that
|
|
||||||
* we can process */
|
|
||||||
for (sinks = elem->sinkpads; sinks; sinks = sinks->next) {
|
|
||||||
GstSignalProcessorPad *sinkpad;
|
|
||||||
|
|
||||||
sinkpad = (GstSignalProcessorPad *) sinks->data;
|
|
||||||
g_assert (sinkpad->samples_avail > 0);
|
|
||||||
samples_avail = MIN (samples_avail, sinkpad->samples_avail);
|
|
||||||
self->audio_in[sinkpad->index] = sinkpad->data;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (samples_avail == G_MAXUINT) {
|
|
||||||
/* we don't have any sink pads, just choose a size -- should fix this
|
|
||||||
* function to have a suggested number of samples in the case of
|
|
||||||
* gst_pad_pull_range */
|
|
||||||
samples_avail = 256;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now assign output buffers. we can avoid allocation by reusing input
|
|
||||||
buffers, but only if process() can work in place, and if the input buffer
|
|
||||||
is the exact size of the number of samples we are processing. */
|
|
||||||
sinks = elem->sinkpads;
|
|
||||||
srcs = elem->srcpads;
|
|
||||||
if (GST_SIGNAL_PROCESSOR_CLASS_CAN_PROCESS_IN_PLACE (klass)) {
|
|
||||||
while (sinks && srcs) {
|
|
||||||
GstSignalProcessorPad *sinkpad, *srcpad;
|
|
||||||
|
|
||||||
sinkpad = (GstSignalProcessorPad *) sinks->data;
|
|
||||||
srcpad = (GstSignalProcessorPad *) srcs->data;
|
|
||||||
|
|
||||||
if (GST_BUFFER_SIZE (sinkpad->pen) == samples_avail * sizeof (gfloat)) {
|
|
||||||
/* reusable, yay */
|
|
||||||
g_assert (sinkpad->samples_avail == samples_avail);
|
|
||||||
srcpad->pen = sinkpad->pen;
|
|
||||||
sinkpad->pen = NULL;
|
|
||||||
self->audio_out[srcpad->index] = sinkpad->data;
|
|
||||||
self->pending_out++;
|
|
||||||
|
|
||||||
srcs = srcs->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
sinks = sinks->next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now allocate for any remaining outputs */
|
|
||||||
while (srcs) {
|
|
||||||
GstSignalProcessorPad *srcpad;
|
|
||||||
GstFlowReturn ret;
|
|
||||||
|
|
||||||
srcpad = (GstSignalProcessorPad *) srcs->data;
|
|
||||||
|
|
||||||
ret =
|
|
||||||
gst_pad_alloc_buffer_and_set_caps (GST_PAD (srcpad), -1,
|
|
||||||
samples_avail * sizeof (gfloat), GST_PAD_CAPS (srcpad), &srcpad->pen);
|
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK) {
|
|
||||||
self->flow_state = ret;
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
self->audio_out[srcpad->index] = (gfloat *) GST_BUFFER_DATA (srcpad->pen);
|
|
||||||
self->pending_out++;
|
|
||||||
}
|
|
||||||
|
|
||||||
srcs = srcs->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
return samples_avail;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_update_inputs (GstSignalProcessor * self, guint nprocessed)
|
|
||||||
{
|
|
||||||
GstElement *elem = (GstElement *) self;
|
|
||||||
GList *sinks;
|
|
||||||
|
|
||||||
for (sinks = elem->sinkpads; sinks; sinks = sinks->next) {
|
|
||||||
GstSignalProcessorPad *sinkpad;
|
|
||||||
|
|
||||||
sinkpad = (GstSignalProcessorPad *) sinks->data;
|
|
||||||
g_assert (sinkpad->samples_avail >= nprocessed);
|
|
||||||
|
|
||||||
if (sinkpad->pen && sinkpad->samples_avail == nprocessed) {
|
|
||||||
/* used up this buffer, unpen */
|
|
||||||
gst_buffer_unref (sinkpad->pen);
|
|
||||||
sinkpad->pen = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!sinkpad->pen) {
|
|
||||||
/* this buffer was used up */
|
|
||||||
self->pending_in++;
|
|
||||||
sinkpad->data = NULL;
|
|
||||||
sinkpad->samples_avail = 0;
|
|
||||||
} else {
|
|
||||||
/* advance ->data pointers and decrement ->samples_avail, unreffing buffer
|
|
||||||
if no samples are left */
|
|
||||||
sinkpad->samples_avail -= nprocessed;
|
|
||||||
sinkpad->data += nprocessed; /* gfloat* arithmetic */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_process (GstSignalProcessor * self)
|
|
||||||
{
|
|
||||||
GstElement *elem;
|
|
||||||
GstSignalProcessorClass *klass;
|
|
||||||
guint nframes;
|
|
||||||
|
|
||||||
g_return_if_fail (self->pending_in == 0);
|
|
||||||
g_return_if_fail (self->pending_out == 0);
|
|
||||||
|
|
||||||
elem = GST_ELEMENT (self);
|
|
||||||
|
|
||||||
nframes = gst_signal_processor_prepare (self);
|
|
||||||
if (G_UNLIKELY (nframes == 0))
|
|
||||||
goto flow_error;
|
|
||||||
|
|
||||||
klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (self, "process(%u)", nframes);
|
|
||||||
|
|
||||||
klass->process (self, nframes);
|
|
||||||
|
|
||||||
gst_signal_processor_update_inputs (self, nframes);
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
flow_error:
|
|
||||||
{
|
|
||||||
GST_WARNING ("gst_pad_alloc_buffer_and_set_caps() returned %d",
|
|
||||||
self->flow_state);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_pen_buffer (GstSignalProcessor * self, GstPad * pad,
|
|
||||||
GstBuffer * buffer)
|
|
||||||
{
|
|
||||||
GstSignalProcessorPad *spad = (GstSignalProcessorPad *) pad;
|
|
||||||
|
|
||||||
if (spad->pen)
|
|
||||||
goto had_buffer;
|
|
||||||
|
|
||||||
/* keep the reference */
|
|
||||||
spad->pen = buffer;
|
|
||||||
spad->data = (gfloat *) GST_BUFFER_DATA (buffer);
|
|
||||||
spad->samples_avail = GST_BUFFER_SIZE (buffer) / sizeof (float);
|
|
||||||
|
|
||||||
g_assert (self->pending_in != 0);
|
|
||||||
|
|
||||||
self->pending_in--;
|
|
||||||
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
had_buffer:
|
|
||||||
{
|
|
||||||
GST_WARNING ("Pad %s:%s already has penned buffer",
|
|
||||||
GST_DEBUG_PAD_NAME (pad));
|
|
||||||
gst_buffer_unref (buffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_flush (GstSignalProcessor * self)
|
|
||||||
{
|
|
||||||
GList *pads;
|
|
||||||
GstSignalProcessorClass *klass;
|
|
||||||
|
|
||||||
klass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
GST_INFO_OBJECT (self, "flush()");
|
|
||||||
|
|
||||||
for (pads = GST_ELEMENT (self)->pads; pads; pads = pads->next) {
|
|
||||||
GstSignalProcessorPad *spad = (GstSignalProcessorPad *) pads->data;
|
|
||||||
|
|
||||||
if (spad->pen) {
|
|
||||||
gst_buffer_unref (spad->pen);
|
|
||||||
spad->pen = NULL;
|
|
||||||
spad->data = NULL;
|
|
||||||
spad->samples_avail = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self->pending_out = 0;
|
|
||||||
self->pending_in = klass->num_audio_in;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_do_pulls (GstSignalProcessor * self, guint nframes)
|
|
||||||
{
|
|
||||||
GList *sinkpads;
|
|
||||||
|
|
||||||
/* FIXME: not threadsafe atm */
|
|
||||||
|
|
||||||
sinkpads = GST_ELEMENT (self)->sinkpads;
|
|
||||||
|
|
||||||
for (; sinkpads; sinkpads = sinkpads->next) {
|
|
||||||
GstSignalProcessorPad *spad = (GstSignalProcessorPad *) sinkpads->data;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
|
||||||
GstBuffer *buf;
|
|
||||||
|
|
||||||
if (spad->pen) {
|
|
||||||
g_warning ("Unexpectedly full buffer pen for pad %s:%s",
|
|
||||||
GST_DEBUG_PAD_NAME (spad));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = gst_pad_pull_range (GST_PAD (spad), -1, nframes, &buf);
|
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK) {
|
|
||||||
gst_signal_processor_flush (self);
|
|
||||||
self->flow_state = ret;
|
|
||||||
return;
|
|
||||||
} else if (!buf) {
|
|
||||||
g_critical ("Pull failed to make a buffer!");
|
|
||||||
self->flow_state = GST_FLOW_ERROR;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
gst_signal_processor_pen_buffer (self, GST_PAD (spad), buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->pending_in != 0) {
|
|
||||||
g_critical ("Something wierd happened...");
|
|
||||||
self->flow_state = GST_FLOW_ERROR;
|
|
||||||
} else {
|
|
||||||
gst_signal_processor_process (self);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_signal_processor_getrange (GstPad * pad, guint64 offset,
|
|
||||||
guint length, GstBuffer ** buffer)
|
|
||||||
{
|
|
||||||
GstSignalProcessor *self;
|
|
||||||
GstSignalProcessorPad *spad = (GstSignalProcessorPad *) pad;
|
|
||||||
GstFlowReturn ret = GST_FLOW_ERROR;
|
|
||||||
|
|
||||||
self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
|
|
||||||
|
|
||||||
if (spad->pen) {
|
|
||||||
*buffer = spad->pen;
|
|
||||||
spad->pen = NULL;
|
|
||||||
g_assert (self->pending_out != 0);
|
|
||||||
self->pending_out--;
|
|
||||||
ret = GST_FLOW_OK;
|
|
||||||
} else {
|
|
||||||
gst_signal_processor_do_pulls (self, length);
|
|
||||||
if (!spad->pen) {
|
|
||||||
/* this is an error condition */
|
|
||||||
*buffer = NULL;
|
|
||||||
ret = self->flow_state;
|
|
||||||
} else {
|
|
||||||
*buffer = spad->pen;
|
|
||||||
spad->pen = NULL;
|
|
||||||
self->pending_out--;
|
|
||||||
ret = GST_FLOW_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "returns %s", gst_flow_get_name (ret));
|
|
||||||
|
|
||||||
gst_object_unref (self);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_do_pushes (GstSignalProcessor * self)
|
|
||||||
{
|
|
||||||
GList *srcpads;
|
|
||||||
|
|
||||||
/* not threadsafe atm */
|
|
||||||
|
|
||||||
srcpads = GST_ELEMENT (self)->srcpads;
|
|
||||||
|
|
||||||
for (; srcpads; srcpads = srcpads->next) {
|
|
||||||
GstSignalProcessorPad *spad = (GstSignalProcessorPad *) srcpads->data;
|
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
|
||||||
GstBuffer *buffer;
|
|
||||||
|
|
||||||
if (!spad->pen) {
|
|
||||||
g_warning ("Unexpectedly empty buffer pen for pad %s:%s",
|
|
||||||
GST_DEBUG_PAD_NAME (spad));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* take buffer from pen */
|
|
||||||
buffer = spad->pen;
|
|
||||||
spad->pen = NULL;
|
|
||||||
|
|
||||||
ret = gst_pad_push (GST_PAD (spad), buffer);
|
|
||||||
|
|
||||||
if (ret != GST_FLOW_OK) {
|
|
||||||
gst_signal_processor_flush (self);
|
|
||||||
self->flow_state = ret;
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
g_assert (self->pending_out > 0);
|
|
||||||
self->pending_out--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self->pending_out != 0) {
|
|
||||||
g_critical ("Something wierd happened...");
|
|
||||||
self->flow_state = GST_FLOW_ERROR;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstFlowReturn
|
|
||||||
gst_signal_processor_chain (GstPad * pad, GstBuffer * buffer)
|
|
||||||
{
|
|
||||||
GstSignalProcessor *self;
|
|
||||||
|
|
||||||
self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
|
|
||||||
|
|
||||||
gst_signal_processor_pen_buffer (self, pad, buffer);
|
|
||||||
|
|
||||||
if (self->pending_in == 0) {
|
|
||||||
gst_signal_processor_process (self);
|
|
||||||
|
|
||||||
gst_signal_processor_do_pushes (self);
|
|
||||||
}
|
|
||||||
|
|
||||||
gst_object_unref (self);
|
|
||||||
|
|
||||||
return self->flow_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_set_property (GObject * object, guint prop_id,
|
|
||||||
const GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
/* GstSignalProcessor *self = GST_SIGNAL_PROCESSOR (object); */
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gst_signal_processor_get_property (GObject * object, guint prop_id,
|
|
||||||
GValue * value, GParamSpec * pspec)
|
|
||||||
{
|
|
||||||
/* GstSignalProcessor *self = GST_SIGNAL_PROCESSOR (object); */
|
|
||||||
|
|
||||||
switch (prop_id) {
|
|
||||||
default:
|
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_signal_processor_sink_activate_push (GstPad * pad, gboolean active)
|
|
||||||
{
|
|
||||||
gboolean result = TRUE;
|
|
||||||
GstSignalProcessor *self;
|
|
||||||
GstSignalProcessorClass *bclass;
|
|
||||||
|
|
||||||
self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
|
|
||||||
bclass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
if (active) {
|
|
||||||
if (self->mode == GST_ACTIVATE_NONE) {
|
|
||||||
self->mode = GST_ACTIVATE_PUSH;
|
|
||||||
result = TRUE;
|
|
||||||
} else if (self->mode == GST_ACTIVATE_PUSH) {
|
|
||||||
result = TRUE;
|
|
||||||
} else {
|
|
||||||
g_warning ("foo");
|
|
||||||
result = FALSE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (self->mode == GST_ACTIVATE_NONE) {
|
|
||||||
result = TRUE;
|
|
||||||
} else if (self->mode == GST_ACTIVATE_PUSH) {
|
|
||||||
self->mode = GST_ACTIVATE_NONE;
|
|
||||||
result = TRUE;
|
|
||||||
} else {
|
|
||||||
g_warning ("foo");
|
|
||||||
result = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "result : %d", result);
|
|
||||||
|
|
||||||
gst_object_unref (self);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
gst_signal_processor_src_activate_pull (GstPad * pad, gboolean active)
|
|
||||||
{
|
|
||||||
gboolean result = TRUE;
|
|
||||||
GstSignalProcessor *self;
|
|
||||||
GstSignalProcessorClass *bclass;
|
|
||||||
|
|
||||||
self = GST_SIGNAL_PROCESSOR (gst_pad_get_parent (pad));
|
|
||||||
bclass = GST_SIGNAL_PROCESSOR_GET_CLASS (self);
|
|
||||||
|
|
||||||
if (active) {
|
|
||||||
if (self->mode == GST_ACTIVATE_NONE) {
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next)
|
|
||||||
result &= gst_pad_activate_pull (pad, active);
|
|
||||||
if (result)
|
|
||||||
self->mode = GST_ACTIVATE_PULL;
|
|
||||||
} else if (self->mode == GST_ACTIVATE_PULL) {
|
|
||||||
result = TRUE;
|
|
||||||
} else {
|
|
||||||
g_warning ("foo");
|
|
||||||
result = FALSE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (self->mode == GST_ACTIVATE_NONE) {
|
|
||||||
result = TRUE;
|
|
||||||
} else if (self->mode == GST_ACTIVATE_PULL) {
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
for (l = GST_ELEMENT (self)->sinkpads; l; l = l->next)
|
|
||||||
result &= gst_pad_activate_pull (pad, active);
|
|
||||||
if (result)
|
|
||||||
self->mode = GST_ACTIVATE_NONE;
|
|
||||||
result = TRUE;
|
|
||||||
} else {
|
|
||||||
g_warning ("foo");
|
|
||||||
result = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self, "result : %d", result);
|
|
||||||
|
|
||||||
gst_object_unref (self);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GstStateChangeReturn
|
|
||||||
gst_signal_processor_change_state (GstElement * element,
|
|
||||||
GstStateChange transition)
|
|
||||||
{
|
|
||||||
GstSignalProcessor *self;
|
|
||||||
GstStateChangeReturn result;
|
|
||||||
|
|
||||||
self = GST_SIGNAL_PROCESSOR (element);
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
|
||||||
self->flow_state = GST_FLOW_OK;
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((result =
|
|
||||||
GST_ELEMENT_CLASS (parent_class)->change_state (element,
|
|
||||||
transition)) == GST_STATE_CHANGE_FAILURE)
|
|
||||||
goto failure;
|
|
||||||
|
|
||||||
switch (transition) {
|
|
||||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
|
||||||
if (GST_SIGNAL_PROCESSOR_IS_RUNNING (self))
|
|
||||||
gst_signal_processor_stop (self);
|
|
||||||
gst_signal_processor_flush (self);
|
|
||||||
break;
|
|
||||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
|
||||||
if (GST_SIGNAL_PROCESSOR_IS_INITIALIZED (self))
|
|
||||||
gst_signal_processor_cleanup (self);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
|
|
||||||
/* ERRORS */
|
|
||||||
failure:
|
|
||||||
{
|
|
||||||
GST_DEBUG_OBJECT (element, "parent failed state change");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,122 +0,0 @@
|
||||||
/* GStreamer
|
|
||||||
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
|
|
||||||
* 2005 Wim Taymans <wim@fluendo.com>
|
|
||||||
*
|
|
||||||
* gstsignalprocessor.h:
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Library General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Library General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Library General Public
|
|
||||||
* License along with this library; if not, write to the
|
|
||||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
||||||
* Boston, MA 02111-1307, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __GST_SIGNAL_PROCESSOR_H__
|
|
||||||
#define __GST_SIGNAL_PROCESSOR_H__
|
|
||||||
|
|
||||||
#include <gst/gst.h>
|
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
|
||||||
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
GST_SIGNAL_PROCESSOR_CLASS_FLAG_CAN_PROCESS_IN_PLACE = 1<<0
|
|
||||||
} GstSignalProcessorClassFlags;
|
|
||||||
|
|
||||||
#define GST_SIGNAL_PROCESSOR_CLASS_CAN_PROCESS_IN_PLACE(klass) \
|
|
||||||
(GST_SIGNAL_PROCESSOR_CLASS (klass)->flags & \
|
|
||||||
GST_SIGNAL_PROCESSOR_CLASS_FLAG_CAN_PROCESS_IN_PLACE)
|
|
||||||
#define GST_SIGNAL_PROCESSOR_CLASS_SET_CAN_PROCESS_IN_PLACE(klass) \
|
|
||||||
GST_SIGNAL_PROCESSOR_CLASS (klass)->flags |= \
|
|
||||||
GST_SIGNAL_PROCESSOR_CLASS_FLAG_CAN_PROCESS_IN_PLACE
|
|
||||||
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
GST_SIGNAL_PROCESSOR_STATE_NULL,
|
|
||||||
GST_SIGNAL_PROCESSOR_STATE_INITIALIZED,
|
|
||||||
GST_SIGNAL_PROCESSOR_STATE_RUNNING
|
|
||||||
} GstSignalProcessorState;
|
|
||||||
|
|
||||||
|
|
||||||
#define GST_TYPE_SIGNAL_PROCESSOR (gst_signal_processor_get_type())
|
|
||||||
#define GST_SIGNAL_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SIGNAL_PROCESSOR,GstSignalProcessor))
|
|
||||||
#define GST_SIGNAL_PROCESSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SIGNAL_PROCESSOR,GstSignalProcessorClass))
|
|
||||||
#define GST_SIGNAL_PROCESSOR_GET_CLASS(obj) \
|
|
||||||
(G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_SIGNAL_PROCESSOR,GstSignalProcessorClass))
|
|
||||||
#define GST_IS_SIGNAL_PROCESSOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SIGNAL_PROCESSOR))
|
|
||||||
#define GST_IS_SIGNAL_PROCESSOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SIGNAL_PROCESSOR))
|
|
||||||
|
|
||||||
#define GST_SIGNAL_PROCESSOR_IS_INITIALIZED(obj) \
|
|
||||||
(GST_SIGNAL_PROCESSOR (obj)->state >= GST_SIGNAL_PROCESSOR_STATE_INITIALIZED)
|
|
||||||
#define GST_SIGNAL_PROCESSOR_IS_RUNNING(obj) \
|
|
||||||
(GST_SIGNAL_PROCESSOR (obj)->state == GST_SIGNAL_PROCESSOR_STATE_RUNNING)
|
|
||||||
|
|
||||||
typedef struct _GstSignalProcessor GstSignalProcessor;
|
|
||||||
typedef struct _GstSignalProcessorClass GstSignalProcessorClass;
|
|
||||||
|
|
||||||
|
|
||||||
struct _GstSignalProcessor {
|
|
||||||
GstElement element;
|
|
||||||
|
|
||||||
GstCaps *caps;
|
|
||||||
|
|
||||||
guint sample_rate;
|
|
||||||
|
|
||||||
GstSignalProcessorState state;
|
|
||||||
|
|
||||||
GstFlowReturn flow_state;
|
|
||||||
|
|
||||||
GstActivateMode mode;
|
|
||||||
|
|
||||||
guint pending_in;
|
|
||||||
guint pending_out;
|
|
||||||
|
|
||||||
gfloat *control_in;
|
|
||||||
gfloat **audio_in;
|
|
||||||
gfloat *control_out;
|
|
||||||
gfloat **audio_out;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _GstSignalProcessorClass {
|
|
||||||
GstElementClass parent_class;
|
|
||||||
|
|
||||||
/*< public >*/
|
|
||||||
guint num_control_in;
|
|
||||||
guint num_audio_in;
|
|
||||||
guint num_control_out;
|
|
||||||
guint num_audio_out;
|
|
||||||
|
|
||||||
guint flags;
|
|
||||||
|
|
||||||
/* virtual methods for subclasses */
|
|
||||||
|
|
||||||
gboolean (*setup) (GstSignalProcessor *self, guint sample_rate);
|
|
||||||
gboolean (*start) (GstSignalProcessor *self);
|
|
||||||
void (*stop) (GstSignalProcessor *self);
|
|
||||||
void (*cleanup) (GstSignalProcessor *self);
|
|
||||||
void (*process) (GstSignalProcessor *self, guint num_frames);
|
|
||||||
gboolean (*event) (GstSignalProcessor *self, GstEvent *event);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
GType gst_signal_processor_get_type (void);
|
|
||||||
void gst_signal_processor_class_add_pad_template (GstSignalProcessorClass *klass,
|
|
||||||
const gchar *name, GstPadDirection direction, guint index);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
G_END_DECLS
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __GST_SIGNAL_PROCESSOR_H__ */
|
|
|
@ -1,195 +0,0 @@
|
||||||
/* load.c
|
|
||||||
|
|
||||||
Free software by Richard W.E. Furse. Do with as you will. No
|
|
||||||
warranty. */
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#include "ladspa.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
/* This function provides a wrapping of dlopen(). When the filename is
|
|
||||||
not an absolute path (i.e. does not begin with / character), this
|
|
||||||
routine will search the LADSPA_PATH for the file. */
|
|
||||||
static void *
|
|
||||||
dlopenLADSPA (const char *pcFilename, int iFlag)
|
|
||||||
{
|
|
||||||
|
|
||||||
char *pcBuffer;
|
|
||||||
const char *pcEnd;
|
|
||||||
const char *pcLADSPAPath;
|
|
||||||
const char *pcStart;
|
|
||||||
int iEndsInSO;
|
|
||||||
int iNeedSlash;
|
|
||||||
size_t iFilenameLength;
|
|
||||||
void *pvResult;
|
|
||||||
|
|
||||||
iFilenameLength = strlen (pcFilename);
|
|
||||||
pvResult = NULL;
|
|
||||||
|
|
||||||
if (pcFilename[0] == '/') {
|
|
||||||
|
|
||||||
/* The filename is absolute. Assume the user knows what he/she is
|
|
||||||
doing and simply dlopen() it. */
|
|
||||||
|
|
||||||
pvResult = dlopen (pcFilename, iFlag);
|
|
||||||
if (pvResult != NULL)
|
|
||||||
return pvResult;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
/* If the filename is not absolute then we wish to check along the
|
|
||||||
LADSPA_PATH path to see if we can find the file there. We do
|
|
||||||
NOT call dlopen() directly as this would find plugins on the
|
|
||||||
LD_LIBRARY_PATH, whereas the LADSPA_PATH is the correct place
|
|
||||||
to search. */
|
|
||||||
|
|
||||||
/* thomasvs: I'm sorry, but I'm going to add glib stuff here.
|
|
||||||
* I'm appending logical values for LADSPA_PATH here
|
|
||||||
*/
|
|
||||||
|
|
||||||
pcLADSPAPath = g_strdup_printf ("%s:/usr/lib/ladspa:/usr/local/lib/ladspa",
|
|
||||||
getenv ("LADSPA_PATH"));
|
|
||||||
|
|
||||||
if (pcLADSPAPath) {
|
|
||||||
|
|
||||||
pcStart = pcLADSPAPath;
|
|
||||||
while (*pcStart != '\0') {
|
|
||||||
pcEnd = pcStart;
|
|
||||||
while (*pcEnd != ':' && *pcEnd != '\0')
|
|
||||||
pcEnd++;
|
|
||||||
|
|
||||||
pcBuffer = malloc (iFilenameLength + 2 + (pcEnd - pcStart));
|
|
||||||
if (pcEnd > pcStart)
|
|
||||||
strncpy (pcBuffer, pcStart, pcEnd - pcStart);
|
|
||||||
iNeedSlash = 0;
|
|
||||||
if (pcEnd > pcStart)
|
|
||||||
if (*(pcEnd - 1) != '/') {
|
|
||||||
iNeedSlash = 1;
|
|
||||||
pcBuffer[pcEnd - pcStart] = '/';
|
|
||||||
}
|
|
||||||
strcpy (pcBuffer + iNeedSlash + (pcEnd - pcStart), pcFilename);
|
|
||||||
|
|
||||||
pvResult = dlopen (pcBuffer, iFlag);
|
|
||||||
|
|
||||||
free (pcBuffer);
|
|
||||||
if (pvResult != NULL)
|
|
||||||
return pvResult;
|
|
||||||
|
|
||||||
pcStart = pcEnd;
|
|
||||||
if (*pcStart == ':')
|
|
||||||
pcStart++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* As a last ditch effort, check if filename does not end with
|
|
||||||
".so". In this case, add this suffix and recurse. */
|
|
||||||
iEndsInSO = 0;
|
|
||||||
if (iFilenameLength > 3)
|
|
||||||
iEndsInSO = (strcmp (pcFilename + iFilenameLength - 3, ".so") == 0);
|
|
||||||
if (!iEndsInSO) {
|
|
||||||
pcBuffer = malloc (iFilenameLength + 4);
|
|
||||||
strcpy (pcBuffer, pcFilename);
|
|
||||||
strcat (pcBuffer, ".so");
|
|
||||||
pvResult = dlopenLADSPA (pcBuffer, iFlag);
|
|
||||||
free (pcBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pvResult != NULL)
|
|
||||||
return pvResult;
|
|
||||||
|
|
||||||
/* If nothing has worked, then at least we can make sure we set the
|
|
||||||
correct error message - and this should correspond to a call to
|
|
||||||
dlopen() with the actual filename requested. The dlopen() manual
|
|
||||||
page does not specify whether the first or last error message
|
|
||||||
will be kept when multiple calls are made to dlopen(). We've
|
|
||||||
covered the former case - now we can handle the latter by calling
|
|
||||||
dlopen() again here. */
|
|
||||||
return dlopen (pcFilename, iFlag);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
void *
|
|
||||||
loadLADSPAPluginLibrary (const char *pcPluginFilename)
|
|
||||||
{
|
|
||||||
|
|
||||||
void *pvPluginHandle;
|
|
||||||
|
|
||||||
pvPluginHandle = dlopenLADSPA (pcPluginFilename, RTLD_NOW);
|
|
||||||
if (!pvPluginHandle) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"Failed to load plugin \"%s\": %s\n", pcPluginFilename, dlerror ());
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return pvPluginHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
void
|
|
||||||
unloadLADSPAPluginLibrary (void *pvLADSPAPluginLibrary)
|
|
||||||
{
|
|
||||||
dlclose (pvLADSPAPluginLibrary);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
const LADSPA_Descriptor *
|
|
||||||
findLADSPAPluginDescriptor (void *pvLADSPAPluginLibrary,
|
|
||||||
const char *pcPluginLibraryFilename, const char *pcPluginLabel)
|
|
||||||
{
|
|
||||||
|
|
||||||
const LADSPA_Descriptor *psDescriptor;
|
|
||||||
LADSPA_Descriptor_Function pfDescriptorFunction;
|
|
||||||
unsigned long lPluginIndex;
|
|
||||||
|
|
||||||
dlerror ();
|
|
||||||
pfDescriptorFunction
|
|
||||||
= (LADSPA_Descriptor_Function) dlsym (pvLADSPAPluginLibrary,
|
|
||||||
"ladspa_descriptor");
|
|
||||||
if (!pfDescriptorFunction) {
|
|
||||||
const char *pcError = dlerror ();
|
|
||||||
|
|
||||||
if (pcError) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"Unable to find ladspa_descriptor() function in plugin "
|
|
||||||
"library file \"%s\": %s.\n"
|
|
||||||
"Are you sure this is a LADSPA plugin file?\n",
|
|
||||||
pcPluginLibraryFilename, pcError);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (lPluginIndex = 0;; lPluginIndex++) {
|
|
||||||
psDescriptor = pfDescriptorFunction (lPluginIndex);
|
|
||||||
if (psDescriptor == NULL) {
|
|
||||||
fprintf (stderr,
|
|
||||||
"Unable to find label \"%s\" in plugin library file \"%s\".\n",
|
|
||||||
pcPluginLabel, pcPluginLibraryFilename);
|
|
||||||
exit (1);
|
|
||||||
}
|
|
||||||
if (strcmp (psDescriptor->Label, pcPluginLabel) == 0)
|
|
||||||
return psDescriptor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
/* EOF */
|
|
|
@ -1,139 +0,0 @@
|
||||||
/* search.c
|
|
||||||
|
|
||||||
Free software by Richard W.E. Furse. Do with as you will. No
|
|
||||||
warranty. */
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
#include "config.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <dlfcn.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#include "ladspa.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
/* Search just the one directory. */
|
|
||||||
static void
|
|
||||||
LADSPADirectoryPluginSearch
|
|
||||||
(const char *pcDirectory,
|
|
||||||
LADSPAPluginSearchCallbackFunction fCallbackFunction)
|
|
||||||
{
|
|
||||||
|
|
||||||
char *pcFilename;
|
|
||||||
DIR *psDirectory;
|
|
||||||
LADSPA_Descriptor_Function fDescriptorFunction;
|
|
||||||
long lDirLength;
|
|
||||||
long iNeedSlash;
|
|
||||||
struct dirent *psDirectoryEntry;
|
|
||||||
void *pvPluginHandle;
|
|
||||||
|
|
||||||
lDirLength = strlen (pcDirectory);
|
|
||||||
if (!lDirLength)
|
|
||||||
return;
|
|
||||||
if (pcDirectory[lDirLength - 1] == '/')
|
|
||||||
iNeedSlash = 0;
|
|
||||||
else
|
|
||||||
iNeedSlash = 1;
|
|
||||||
|
|
||||||
psDirectory = opendir (pcDirectory);
|
|
||||||
if (!psDirectory)
|
|
||||||
return;
|
|
||||||
|
|
||||||
while (1) {
|
|
||||||
|
|
||||||
psDirectoryEntry = readdir (psDirectory);
|
|
||||||
if (!psDirectoryEntry) {
|
|
||||||
closedir (psDirectory);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcFilename = malloc (lDirLength + strlen (psDirectoryEntry->d_name)
|
|
||||||
+ 1 + iNeedSlash);
|
|
||||||
strcpy (pcFilename, pcDirectory);
|
|
||||||
if (iNeedSlash)
|
|
||||||
strcat (pcFilename, "/");
|
|
||||||
strcat (pcFilename, psDirectoryEntry->d_name);
|
|
||||||
|
|
||||||
pvPluginHandle = dlopen (pcFilename, RTLD_LAZY);
|
|
||||||
if (pvPluginHandle) {
|
|
||||||
/* This is a file and the file is a shared library! */
|
|
||||||
|
|
||||||
dlerror ();
|
|
||||||
fDescriptorFunction
|
|
||||||
= (LADSPA_Descriptor_Function) dlsym (pvPluginHandle,
|
|
||||||
"ladspa_descriptor");
|
|
||||||
if (dlerror () == NULL && fDescriptorFunction) {
|
|
||||||
/* We've successfully found a ladspa_descriptor function. Pass
|
|
||||||
it to the callback function. */
|
|
||||||
fCallbackFunction (pcFilename, pvPluginHandle, fDescriptorFunction);
|
|
||||||
} else {
|
|
||||||
/* It was a library, but not a LADSPA one. Unload it. */
|
|
||||||
dlclose (pvPluginHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free (pcFilename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
void
|
|
||||||
LADSPAPluginSearch (LADSPAPluginSearchCallbackFunction fCallbackFunction)
|
|
||||||
{
|
|
||||||
|
|
||||||
char *pcBuffer;
|
|
||||||
const char *pcEnd;
|
|
||||||
const char *pcLADSPAPath;
|
|
||||||
const char *pcStart;
|
|
||||||
|
|
||||||
/* thomasvs: I'm sorry, but I'm going to add glib stuff here.
|
|
||||||
* I'm appending logical values for LADSPA_PATH here
|
|
||||||
*/
|
|
||||||
|
|
||||||
pcLADSPAPath = g_strdup_printf ("%s:/usr/lib/ladspa:/usr/local/lib/ladspa",
|
|
||||||
getenv ("LADSPA_PATH"));
|
|
||||||
|
|
||||||
if (!pcLADSPAPath) {
|
|
||||||
/* fprintf(stderr, */
|
|
||||||
/* "Warning: You do not have a LADSPA_PATH " */
|
|
||||||
/* "environment variable set.\n"); */
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pcStart = pcLADSPAPath;
|
|
||||||
while (*pcStart != '\0') {
|
|
||||||
pcEnd = pcStart;
|
|
||||||
while (*pcEnd != ':' && *pcEnd != '\0')
|
|
||||||
pcEnd++;
|
|
||||||
|
|
||||||
pcBuffer = malloc (1 + pcEnd - pcStart);
|
|
||||||
if (pcEnd > pcStart)
|
|
||||||
strncpy (pcBuffer, pcStart, pcEnd - pcStart);
|
|
||||||
pcBuffer[pcEnd - pcStart] = '\0';
|
|
||||||
|
|
||||||
LADSPADirectoryPluginSearch (pcBuffer, fCallbackFunction);
|
|
||||||
free (pcBuffer);
|
|
||||||
|
|
||||||
pcStart = pcEnd;
|
|
||||||
if (*pcStart == ':')
|
|
||||||
pcStart++;
|
|
||||||
}
|
|
||||||
g_free ((gpointer) pcLADSPAPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
/* EOF */
|
|
|
@ -1,62 +0,0 @@
|
||||||
/* utils.h
|
|
||||||
|
|
||||||
Free software by Richard W.E. Furse. Do with as you will. No
|
|
||||||
warranty. */
|
|
||||||
|
|
||||||
#ifndef LADSPA_SDK_LOAD_PLUGIN_LIB
|
|
||||||
#define LADSPA_SDK_LOAD_PLUGIN_LIB
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#include <ladspa.h>
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
/* Functions in load.c: */
|
|
||||||
|
|
||||||
/* This function call takes a plugin library filename, searches for
|
|
||||||
the library along the LADSPA_PATH, loads it with dlopen() and
|
|
||||||
returns a plugin handle for use with findPluginDescriptor() or
|
|
||||||
unloadLADSPAPluginLibrary(). Errors are handled by writing a
|
|
||||||
message to stderr and calling exit(1). It is alright (although
|
|
||||||
inefficient) to call this more than once for the same file. */
|
|
||||||
void * loadLADSPAPluginLibrary(const char * pcPluginFilename);
|
|
||||||
|
|
||||||
/* This function unloads a LADSPA plugin library. */
|
|
||||||
void unloadLADSPAPluginLibrary(void * pvLADSPAPluginLibrary);
|
|
||||||
|
|
||||||
/* This function locates a LADSPA plugin within a plugin library
|
|
||||||
loaded with loadLADSPAPluginLibrary(). Errors are handled by
|
|
||||||
writing a message to stderr and calling exit(1). Note that the
|
|
||||||
plugin library filename is only included to help provide
|
|
||||||
informative error messages. */
|
|
||||||
const LADSPA_Descriptor *
|
|
||||||
findLADSPAPluginDescriptor(void * pvLADSPAPluginLibrary,
|
|
||||||
const char * pcPluginLibraryFilename,
|
|
||||||
const char * pcPluginLabel);
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
/* Functions in search.c: */
|
|
||||||
|
|
||||||
/* Callback function for use with LADSPAPluginSearch(). The callback
|
|
||||||
function passes the filename (full path), a plugin handle (dlopen()
|
|
||||||
style) and a LADSPA_DescriptorFunction (from which
|
|
||||||
LADSPA_Descriptors can be acquired). */
|
|
||||||
typedef void LADSPAPluginSearchCallbackFunction
|
|
||||||
(const char * pcFullFilename,
|
|
||||||
void * pvPluginHandle,
|
|
||||||
LADSPA_Descriptor_Function fDescriptorFunction);
|
|
||||||
|
|
||||||
/* Search through the $(LADSPA_PATH) (or a default path) for any
|
|
||||||
LADSPA plugin libraries. Each plugin library is tested using
|
|
||||||
dlopen() and dlsym(,"ladspa_descriptor"). After loading each
|
|
||||||
library, the callback function is called to process it. This
|
|
||||||
function leaves items passed to the callback function open. */
|
|
||||||
void LADSPAPluginSearch(LADSPAPluginSearchCallbackFunction fCallbackFunction);
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* EOF */
|
|
Loading…
Reference in a new issue