/* -*- c-basic-offset: 2 -*-
+ *
* GStreamer
* Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2006 Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>
+ * 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms 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.
- */
-
-/* this windowed sinc filter is taken from the freely downloadable DSP book,
+ *
+ *
+ * this windowed sinc filter is taken from the freely downloadable DSP book,
* "The Scientist and Engineer's Guide to Digital Signal Processing",
* chapter 16
* available at http://www.dspguide.com/
+ *
+ * For the window functions see
+ * http://en.wikipedia.org/wiki/Window_function
*/
-/* FIXME:
- * - this filter is totally unoptimized !
- * - we do not destroy the allocated memory for filters and residue
- * - this might be improved upon with bytestream
+/**
+ * SECTION:element-audiowsincband
+ *
+ * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency
+ * band. The length parameter controls the rolloff, the window parameter
+ * controls rolloff and stopband attenuation. The Hamming window provides a faster rolloff but a bit
+ * worse stopband attenuation, the other way around for the Blackman window.
+ *
+ * This element has the advantage over the Chebyshev bandpass and bandreject filter that it has
+ * a much better rolloff when using a larger kernel size and almost linear phase. The only
+ * disadvantage is the much slower execution time with larger kernels.
+ *
+ * <refsect2>
+ * <title>Example launch line</title>
+ * |[
+ * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiosincband mode=band-pass lower-frequency=3000 upper-frequency=10000 length=501 window=blackman ! audioconvert ! alsasink
+ * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiowsincband mode=band-reject lower-frequency=59 upper-frequency=61 length=10001 window=hamming ! audioconvert ! alsasink
+ * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiowsincband mode=band-pass lower-frequency=1000 upper-frequency=2000 length=31 ! audioconvert ! alsasink
+ * ]|
+ * </refsect2>
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+
+#include <string.h>
+#include <math.h>
#include <gst/gst.h>
-#include "gstfilter.h"
-#include <math.h> /* M_PI */
-#include <string.h> /* memmove */
-
-/* elementfactory information */
-GstElementDetails gst_bpwsinc_details = {
- "BPWSinc",
- "Filter/Audio/Effect",
- "LGPL",
- "Band-Pass Windowed sinc filter",
- VERSION,
- "Thomas <thomas@apestaart.org>",
- "(C) 2002 Steven W. Smith",
-};
+#include <gst/audio/gstaudiofilter.h>
+#include <gst/controller/gstcontroller.h>
-enum {
- /* FILL ME */
- LAST_SIGNAL
-};
+#include "audiowsincband.h"
-enum {
- ARG_0,
- ARG_LENGTH,
- ARG_LOWER_FREQUENCY,
- ARG_UPPER_FREQUENCY,
-};
+#define GST_CAT_DEFAULT gst_gst_audio_wsincband_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
-#define GST_TYPE_BPWSINC \
- (gst_bpwsinc_get_type())
-#define GST_BPWSINC(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BPWSINC,GstBPWSinc))
-#define GST_BPWSINC_CLASS(klass) \
- (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstBPWSinc))
-#define GST_IS_BPWSINC(obj) \
- (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BPWSINC))
-#define GST_IS_BPWSINC_CLASS(obj) \
- (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BPWSINC))
-
-typedef struct _GstBPWSinc GstBPWSinc;
-typedef struct _GstBPWSincClass GstBPWSincClass;
-
-struct _GstBPWSinc
+enum
{
- GstElement element;
-
- GstPad *sinkpad, *srcpad;
-
- double frequency;
- double lower_frequency, upper_frequency;
- int wing_size; /* length of a "wing" of the filter;
- actual length is 2 * wing_size + 1 */
-
- gfloat *residue; /* buffer for left-over samples from previous buffer */
- double *kernel;
+ PROP_0,
+ PROP_LENGTH,
+ PROP_LOWER_FREQUENCY,
+ PROP_UPPER_FREQUENCY,
+ PROP_MODE,
+ PROP_WINDOW
};
-struct _GstBPWSincClass
+enum
{
- GstElementClass parent_class;
+ MODE_BAND_PASS = 0,
+ MODE_BAND_REJECT
};
-static void gst_bpwsinc_class_init (GstBPWSincClass * klass);
-static void gst_bpwsinc_init (GstBPWSinc * filter);
-
-static void gst_bpwsinc_set_property (GObject * object, guint prop_id,
- const GValue * value,
- GParamSpec * pspec);
-static void gst_bpwsinc_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
+#define GST_TYPE_AUDIO_WSINC_BAND_MODE (gst_gst_audio_wsincband_mode_get_type ())
+static GType
+gst_gst_audio_wsincband_mode_get_type (void)
+{
+ static GType gtype = 0;
+
+ if (gtype == 0) {
+ static const GEnumValue values[] = {
+ {MODE_BAND_PASS, "Band pass (default)",
+ "band-pass"},
+ {MODE_BAND_REJECT, "Band reject",
+ "band-reject"},
+ {0, NULL, NULL}
+ };
-static void gst_bpwsinc_chain (GstPad * pad, GstData *_data);
-static GstPadLinkReturn
- gst_bpwsinc_sink_connect (GstPad * pad, GstCaps * caps);
+ gtype = g_enum_register_static ("GstAudioWSincBandMode", values);
+ }
+ return gtype;
+}
-static GstElementClass *parent_class = NULL;
-/*static guint gst_bpwsinc_signals[LAST_SIGNAL] = { 0 }; */
+enum
+{
+ WINDOW_HAMMING = 0,
+ WINDOW_BLACKMAN,
+ WINDOW_GAUSSIAN,
+ WINDOW_COSINE,
+ WINDOW_HANN
+};
-GType gst_bpwsinc_get_type (void)
+#define GST_TYPE_AUDIO_WSINC_BAND_WINDOW (gst_gst_audio_wsincband_window_get_type ())
+static GType
+gst_gst_audio_wsincband_window_get_type (void)
{
- static GType bpwsinc_type = 0;
-
- if (!bpwsinc_type) {
- static const GTypeInfo bpwsinc_info = {
- sizeof (GstBPWSincClass), NULL, NULL,
- (GClassInitFunc) gst_bpwsinc_class_init, NULL, NULL,
- sizeof (GstBPWSinc), 0,
- (GInstanceInitFunc) gst_bpwsinc_init,
+ static GType gtype = 0;
+
+ if (gtype == 0) {
+ static const GEnumValue values[] = {
+ {WINDOW_HAMMING, "Hamming window (default)",
+ "hamming"},
+ {WINDOW_BLACKMAN, "Blackman window",
+ "blackman"},
+ {WINDOW_GAUSSIAN, "Gaussian window",
+ "gaussian"},
+ {WINDOW_COSINE, "Cosine window",
+ "cosine"},
+ {WINDOW_HANN, "Hann window",
+ "hann"},
+ {0, NULL, NULL}
};
- bpwsinc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstBPWSinc",
- &bpwsinc_info, 0);
+ gtype = g_enum_register_static ("GstAudioWSincBandWindow", values);
}
- return bpwsinc_type;
+ return gtype;
}
+#define gst_audio_wsincband_parent_class parent_class
+G_DEFINE_TYPE (GstAudioWSincBand, gst_audio_wsincband,
+ GST_TYPE_AUDIO_FX_BASE_FIR_FILTER);
+
+static void gst_audio_wsincband_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec);
+static void gst_audio_wsincband_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+static void gst_audio_wsincband_finalize (GObject * object);
+
+static gboolean gst_audio_wsincband_setup (GstAudioFilter * base,
+ GstRingBufferSpec * format);
+
+
+#define POW2(x) (x)*(x)
+
static void
-gst_bpwsinc_class_init (GstBPWSincClass * klass)
+gst_audio_wsincband_class_init (GstAudioWSincBandClass * klass)
{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LOWER_FREQUENCY,
- g_param_spec_double ("lower-frequency", "Lower Frequency",
- "Cut-off lower frequency (relative to sample rate)",
- 0.0, 0.5,
- 0, G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_UPPER_FREQUENCY,
- g_param_spec_double ("upper-frequency", "Upper Frequency",
- "Cut-off upper frequency (relative to sample rate)",
- 0.0, 0.5,
- 0, G_PARAM_READWRITE));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_LENGTH,
- g_param_spec_int ("length", "Length",
- "N such that the filter length = 2N + 1",
- 1, G_MAXINT,
- 1, G_PARAM_READWRITE));
-
- gobject_class->set_property = gst_bpwsinc_set_property;
- gobject_class->get_property = gst_bpwsinc_get_property;
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+ GstElementClass *gstelement_class = (GstElementClass *) klass;
+ GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+ GST_DEBUG_CATEGORY_INIT (gst_gst_audio_wsincband_debug, "audiowsincband", 0,
+ "Band-pass and Band-reject Windowed sinc filter plugin");
+
+ gobject_class->set_property = gst_audio_wsincband_set_property;
+ gobject_class->get_property = gst_audio_wsincband_get_property;
+ gobject_class->finalize = gst_audio_wsincband_finalize;
+
+ /* FIXME: Don't use the complete possible range but restrict the upper boundary
+ * so automatically generated UIs can use a slider */
+ g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY,
+ g_param_spec_float ("lower-frequency", "Lower Frequency",
+ "Cut-off lower frequency (Hz)", 0.0, 100000.0, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_UPPER_FREQUENCY,
+ g_param_spec_float ("upper-frequency", "Upper Frequency",
+ "Cut-off upper frequency (Hz)", 0.0, 100000.0, 0,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+ g_object_class_install_property (gobject_class, PROP_LENGTH,
+ g_param_spec_int ("length", "Length",
+ "Filter kernel length, will be rounded to the next odd number", 3,
+ 256000, 101,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_MODE,
+ g_param_spec_enum ("mode", "Mode",
+ "Band pass or band reject mode", GST_TYPE_AUDIO_WSINC_BAND_MODE,
+ MODE_BAND_PASS,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (gobject_class, PROP_WINDOW,
+ g_param_spec_enum ("window", "Window",
+ "Window function to use", GST_TYPE_AUDIO_WSINC_BAND_WINDOW,
+ WINDOW_HAMMING,
+ G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+
+ gst_element_class_set_details_simple (gstelement_class,
+ "Band pass & band reject filter", "Filter/Effect/Audio",
+ "Band pass and band reject windowed sinc filter",
+ "Thomas Vander Stichele <thomas at apestaart dot org>, "
+ "Steven W. Smith, "
+ "Dreamlab Technologies Ltd. <mathis.hofer@dreamlab.net>, "
+ "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+ filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_wsincband_setup);
}
static void
-gst_bpwsinc_init (GstBPWSinc * filter)
+gst_audio_wsincband_init (GstAudioWSincBand * self)
{
- filter->sinkpad = gst_pad_new_from_template (gst_filter_sink_factory (), "sink");
- gst_pad_set_chain_function (filter->sinkpad, gst_bpwsinc_chain);
- gst_pad_set_link_function (filter->sinkpad, gst_bpwsinc_sink_connect);
- gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
-
- filter->srcpad = gst_pad_new_from_template (gst_filter_src_factory (), "src");
- gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
-
- filter->wing_size = 50;
- filter->lower_frequency = 0.25;
- filter->upper_frequency = 0.3;
- filter->kernel = NULL;
+ self->kernel_length = 101;
+ self->lower_frequency = 0.0;
+ self->upper_frequency = 0.0;
+ self->mode = MODE_BAND_PASS;
+ self->window = WINDOW_HAMMING;
+
+ self->lock = g_mutex_new ();
}
-static GstPadLinkReturn
-gst_bpwsinc_sink_connect (GstPad * pad, GstCaps * caps)
+static void
+gst_audio_wsincband_build_kernel (GstAudioWSincBand * self)
{
- int i = 0;
- double sum = 0.0;
- int len = 0;
- double *kernel_lp, *kernel_hp;
- GstPadLinkReturn set_retval;
-
- GstBPWSinc *filter = GST_BPWSINC (gst_pad_get_parent (pad));
-
- g_assert (GST_IS_PAD (pad));
- g_assert (caps != NULL);
-
- if (!GST_CAPS_IS_FIXED (caps))
- return GST_PAD_LINK_DELAYED;
-
- set_retval = gst_pad_try_set_caps (filter->srcpad, gst_caps_ref (caps));
-
- if (set_retval > 0)
- {
- len = filter->wing_size;
- /* fill the lp kernel */
- GST_DEBUG (
- "bpwsinc: initializing LP kernel of length %d with cut-off %f",
- len * 2 + 1, filter->lower_frequency);
- kernel_lp = (double *) g_malloc (sizeof (double) * (2 * len + 1));
- for (i = 0; i <= len * 2; ++i)
- {
- if (i == len)
- kernel_lp[i] = 2 * M_PI * filter->lower_frequency;
- else
- kernel_lp[i] = sin (2 * M_PI * filter->lower_frequency * (i - len))
- / (i - len);
- /* Blackman windowing */
- kernel_lp[i] *= (0.42 - 0.5 * cos (M_PI * i / len)
- + 0.08 * cos (2 * M_PI * i / len));
+ gint i = 0;
+ gdouble sum = 0.0;
+ gint len = 0;
+ gdouble *kernel_lp, *kernel_hp;
+ gdouble w;
+ gdouble *kernel;
+
+ len = self->kernel_length;
+
+ if (GST_AUDIO_FILTER (self)->format.rate == 0) {
+ GST_DEBUG ("rate not set yet");
+ return;
+ }
+
+ if (GST_AUDIO_FILTER (self)->format.channels == 0) {
+ GST_DEBUG ("channels not set yet");
+ return;
+ }
+
+ /* Clamp frequencies */
+ self->lower_frequency =
+ CLAMP (self->lower_frequency, 0.0,
+ GST_AUDIO_FILTER (self)->format.rate / 2);
+ self->upper_frequency =
+ CLAMP (self->upper_frequency, 0.0,
+ GST_AUDIO_FILTER (self)->format.rate / 2);
+ if (self->lower_frequency > self->upper_frequency) {
+ gint tmp = self->lower_frequency;
+
+ self->lower_frequency = self->upper_frequency;
+ self->upper_frequency = tmp;
+ }
+
+ GST_DEBUG ("gst_audio_wsincband: initializing filter kernel of length %d "
+ "with lower frequency %.2lf Hz "
+ ", upper frequency %.2lf Hz for mode %s",
+ len, self->lower_frequency, self->upper_frequency,
+ (self->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject");
+
+ /* fill the lp kernel */
+ w = 2 * G_PI * (self->lower_frequency / GST_AUDIO_FILTER (self)->format.rate);
+ kernel_lp = g_new (gdouble, len);
+ for (i = 0; i < len; ++i) {
+ if (i == (len - 1) / 2.0)
+ kernel_lp[i] = w;
+ else
+ kernel_lp[i] = sin (w * (i - (len - 1) / 2.0)) / (i - (len - 1) / 2.0);
+
+ /* windowing */
+ switch (self->window) {
+ case WINDOW_HAMMING:
+ kernel_lp[i] *= (0.54 - 0.46 * cos (2 * G_PI * i / (len - 1)));
+ break;
+ case WINDOW_BLACKMAN:
+ kernel_lp[i] *= (0.42 - 0.5 * cos (2 * G_PI * i / (len - 1)) +
+ 0.08 * cos (4 * G_PI * i / (len - 1)));
+ break;
+ case WINDOW_GAUSSIAN:
+ kernel_lp[i] *= exp (-0.5 * POW2 (3.0 / len * (2 * i - (len - 1))));
+ break;
+ case WINDOW_COSINE:
+ kernel_lp[i] *= cos (G_PI * i / (len - 1) - G_PI / 2);
+ break;
+ case WINDOW_HANN:
+ kernel_lp[i] *= 0.5 * (1 - cos (2 * G_PI * i / (len - 1)));
+ break;
}
+ }
- /* normalize for unity gain at DC
- * FIXME: sure this is not supposed to be quadratic ? */
- sum = 0.0;
- for (i = 0; i <= len * 2; ++i) sum += kernel_lp[i];
- for (i = 0; i <= len * 2; ++i) kernel_lp[i] /= sum;
-
- /* fill the hp kernel */
- GST_DEBUG (
- "bpwsinc: initializing HP kernel of length %d with cut-off %f",
- len * 2 + 1, filter->upper_frequency);
- kernel_hp = (double *) g_malloc (sizeof (double) * (2 * len + 1));
- for (i = 0; i <= len * 2; ++i)
- {
- if (i == len)
- kernel_hp[i] = 2 * M_PI * filter->upper_frequency;
- else
- kernel_hp[i] = sin (2 * M_PI * filter->upper_frequency * (i - len))
- / (i - len);
- /* Blackman windowing */
- kernel_hp[i] *= (0.42 - 0.5 * cos (M_PI * i / len)
- + 0.08 * cos (2 * M_PI * i / len));
+ /* normalize for unity gain at DC */
+ sum = 0.0;
+ for (i = 0; i < len; ++i)
+ sum += kernel_lp[i];
+ for (i = 0; i < len; ++i)
+ kernel_lp[i] /= sum;
+
+ /* fill the hp kernel */
+ w = 2 * G_PI * (self->upper_frequency / GST_AUDIO_FILTER (self)->format.rate);
+ kernel_hp = g_new (gdouble, len);
+ for (i = 0; i < len; ++i) {
+ if (i == (len - 1) / 2.0)
+ kernel_hp[i] = w;
+ else
+ kernel_hp[i] = sin (w * (i - (len - 1) / 2.0)) / (i - (len - 1) / 2.0);
+
+ /* Windowing */
+ switch (self->window) {
+ case WINDOW_HAMMING:
+ kernel_hp[i] *= (0.54 - 0.46 * cos (2 * G_PI * i / (len - 1)));
+ break;
+ case WINDOW_BLACKMAN:
+ kernel_hp[i] *= (0.42 - 0.5 * cos (2 * G_PI * i / (len - 1)) +
+ 0.08 * cos (4 * G_PI * i / (len - 1)));
+ break;
+ case WINDOW_GAUSSIAN:
+ kernel_hp[i] *= exp (-0.5 * POW2 (3.0 / len * (2 * i - (len - 1))));
+ break;
+ case WINDOW_COSINE:
+ kernel_hp[i] *= cos (G_PI * i / (len - 1) - G_PI / 2);
+ break;
+ case WINDOW_HANN:
+ kernel_hp[i] *= 0.5 * (1 - cos (2 * G_PI * i / (len - 1)));
+ break;
}
+ }
+
+ /* normalize for unity gain at DC */
+ sum = 0.0;
+ for (i = 0; i < len; ++i)
+ sum += kernel_hp[i];
+ for (i = 0; i < len; ++i)
+ kernel_hp[i] /= sum;
+
+ /* do spectral inversion to go from lowpass to highpass */
+ for (i = 0; i < len; ++i)
+ kernel_hp[i] = -kernel_hp[i];
+ if (len % 2 == 1) {
+ kernel_hp[(len - 1) / 2] += 1.0;
+ } else {
+ kernel_hp[len / 2 - 1] += 0.5;
+ kernel_hp[len / 2] += 0.5;
+ }
- /* normalize for unity gain at DC
- * FIXME: sure this is not supposed to be quadratic ? */
- sum = 0.0;
- for (i = 0; i <= len * 2; ++i) sum += kernel_hp[i];
- for (i = 0; i <= len * 2; ++i) kernel_hp[i] /= sum;
+ /* combine the two kernels */
+ kernel = g_new (gdouble, len);
- /* do spectral inversion to get a HP filter */
- for (i = 0; i <= len * 2; ++i) kernel_hp[i] = -kernel_hp[i];
- kernel_hp[len] += 1;
+ for (i = 0; i < len; ++i)
+ kernel[i] = kernel_lp[i] + kernel_hp[i];
- /* combine the two filters */
+ /* free the helper kernels */
+ g_free (kernel_lp);
+ g_free (kernel_hp);
- filter->kernel = (double *) g_malloc (sizeof (double) * (2 * len + 1));
+ /* do spectral inversion to go from bandreject to bandpass
+ * if specified */
+ if (self->mode == MODE_BAND_PASS) {
+ for (i = 0; i < len; ++i)
+ kernel[i] = -kernel[i];
+ kernel[len / 2] += 1;
+ }
- for (i = 0; i <= len * 2; ++i)
- filter->kernel[i] = kernel_lp[i] + kernel_hp[i];
+ gst_audio_fx_base_fir_filter_set_kernel (GST_AUDIO_FX_BASE_FIR_FILTER (self),
+ kernel, self->kernel_length, (len - 1) / 2);
+}
- /* do spectral inversion to go from band reject to bandpass */
- for (i = 0; i <= len * 2; ++i) filter->kernel[i] = -filter->kernel[i];
- filter->kernel[len] += 1;
+/* GstAudioFilter vmethod implementations */
- /* free the helper kernels */
- g_free (kernel_lp);
- g_free (kernel_hp);
+/* get notified of caps and plug in the correct process function */
+static gboolean
+gst_audio_wsincband_setup (GstAudioFilter * base, GstRingBufferSpec * format)
+{
+ GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (base);
- /* set up the residue memory space */
- filter->residue = (gfloat *) g_malloc (sizeof (gfloat) * (len * 2 + 1));
- for (i = 0; i <= len * 2; ++i) filter->residue[i] = 0.0;
- }
+ gst_audio_wsincband_build_kernel (self);
- return set_retval;
+ return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format);
}
static void
-gst_bpwsinc_chain (GstPad *pad, GstData *_data)
+gst_audio_wsincband_finalize (GObject * object)
{
- GstBuffer *buf = GST_BUFFER (_data);
- GstBPWSinc *filter;
- gfloat *src;
- gfloat *input;
- gint residue_samples;
- gint input_samples;
- gint total_samples;
- int i, j;
-
- filter = GST_BPWSINC (gst_pad_get_parent (pad));
-
- /* FIXME: out of laziness, we copy the left-over bit from last buffer
- * together with the incoming buffer to a new buffer to make the loop
- * easy; this could be a lot more optimized though
- * to make amends we keep the incoming buffer around and write our
- * output samples there */
-
- /* get a writable buffer */
- buf = gst_buffer_copy_on_write (buf);
-
- src = (gfloat *) GST_BUFFER_DATA (buf);
- residue_samples = filter->wing_size * 2 + 1;
- input_samples = GST_BUFFER_SIZE (buf) / sizeof (gfloat);
- total_samples = residue_samples + input_samples;
-
- input = (gfloat *) g_malloc (sizeof (gfloat) * total_samples);
-
- /* copy the left-over bit */
- memcpy (input, filter->residue, sizeof (gfloat) * residue_samples);
-
- /* copy the new buffer */
- memcpy (&input[residue_samples], src, sizeof (gfloat) * input_samples);
- /* copy the tail of the current input buffer to the residue */
- memcpy (filter->residue, &src[input_samples - residue_samples],
- sizeof (gfloat) * residue_samples);
-
- /* convolution */
- /* since we copied the previous set of samples we needed before the actual
- * input data, we need to add the filter length to our indices for input */
- for (i = 0; i < input_samples; ++i)
- {
- src[i] = 0.0;
- for (j = 0; j < residue_samples; ++j)
- src[i] += input[i - j + residue_samples] * filter->kernel[j];
- }
-
- g_free (input);
- gst_pad_push (filter->srcpad, GST_DATA (buf));
+ GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object);
+
+ g_mutex_free (self->lock);
+ self->lock = NULL;
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
-gst_bpwsinc_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
+gst_audio_wsincband_set_property (GObject * object, guint prop_id,
+ const GValue * value, GParamSpec * pspec)
{
- GstBPWSinc *filter;
-
- /* it's not null if we got it, but it might not be ours */
- g_return_if_fail (GST_IS_BPWSINC (object));
+ GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object);
- filter = GST_BPWSINC (object);
+ g_return_if_fail (GST_IS_AUDIO_WSINC_BAND (self));
switch (prop_id) {
- case ARG_LENGTH:
- filter->wing_size = g_value_get_int (value);
- break;
- case ARG_LOWER_FREQUENCY:
- filter->lower_frequency = g_value_get_double (value);
- break;
- case ARG_UPPER_FREQUENCY:
- filter->upper_frequency = g_value_get_double (value);
- break;
+ case PROP_LENGTH:{
+ gint val;
+
+ g_mutex_lock (self->lock);
+ val = g_value_get_int (value);
+ if (val % 2 == 0)
+ val++;
+
+ if (val != self->kernel_length) {
+ gst_audio_fx_base_fir_filter_push_residue (GST_AUDIO_FX_BASE_FIR_FILTER
+ (self));
+ self->kernel_length = val;
+ gst_audio_wsincband_build_kernel (self);
+ }
+ g_mutex_unlock (self->lock);
+ break;
+ }
+ case PROP_LOWER_FREQUENCY:
+ g_mutex_lock (self->lock);
+ self->lower_frequency = g_value_get_float (value);
+ gst_audio_wsincband_build_kernel (self);
+ g_mutex_unlock (self->lock);
+ break;
+ case PROP_UPPER_FREQUENCY:
+ g_mutex_lock (self->lock);
+ self->upper_frequency = g_value_get_float (value);
+ gst_audio_wsincband_build_kernel (self);
+ g_mutex_unlock (self->lock);
+ break;
+ case PROP_MODE:
+ g_mutex_lock (self->lock);
+ self->mode = g_value_get_enum (value);
+ gst_audio_wsincband_build_kernel (self);
+ g_mutex_unlock (self->lock);
+ break;
+ case PROP_WINDOW:
+ g_mutex_lock (self->lock);
+ self->window = g_value_get_enum (value);
+ gst_audio_wsincband_build_kernel (self);
+ g_mutex_unlock (self->lock);
+ break;
default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
-gst_bpwsinc_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
+gst_audio_wsincband_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
{
- GstBPWSinc *filter;
-
- /* it's not null if we got it, but it might not be ours */
- g_return_if_fail (GST_IS_BPWSINC (object));
-
- filter = GST_BPWSINC (object);
+ GstAudioWSincBand *self = GST_AUDIO_WSINC_BAND (object);
switch (prop_id) {
- case ARG_LENGTH:
- g_value_set_int (value, filter->wing_size);
+ case PROP_LENGTH:
+ g_value_set_int (value, self->kernel_length);
+ break;
+ case PROP_LOWER_FREQUENCY:
+ g_value_set_float (value, self->lower_frequency);
break;
- case ARG_LOWER_FREQUENCY:
- g_value_set_double (value, filter->lower_frequency);
+ case PROP_UPPER_FREQUENCY:
+ g_value_set_float (value, self->upper_frequency);
break;
- case ARG_UPPER_FREQUENCY:
- g_value_set_double (value, filter->upper_frequency);
+ case PROP_MODE:
+ g_value_set_enum (value, self->mode);
+ break;
+ case PROP_WINDOW:
+ g_value_set_enum (value, self->window);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
-}
-
+}