Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-good.git] / gst / audiofx / audiochebband.c
index e39a646..b6c01eb 100644 (file)
@@ -1,6 +1,6 @@
 /* 
  * GStreamer
- * Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
+ * Copyright (C) 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
  */
 
 /**
- * SECTION:element-audiochebyshevfreqband
- * @short_description: Chebyshev band pass and band reject filter
+ * SECTION:element-audiochebband
  *
- * <refsect2>
- * <para>
  * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency
  * band. The number of poles and the ripple parameter control the rolloff.
- * </para>
- * <para>
+ *
  * This element has the advantage over the windowed sinc bandpass and bandreject filter that it is
  * much faster and produces almost as good results. It's only disadvantages are the highly
  * non-linear phase and the slower rolloff compared to a windowed sinc filter with a large kernel.
- * </para>
- * <para>
+ *
  * For type 1 the ripple parameter specifies how much ripple in dB is allowed in the passband, i.e.
  * some frequencies in the passband will be amplified by that value. A higher ripple value will allow
  * a faster rolloff.
- * </para>
- * <para>
+ *
  * For type 2 the ripple parameter specifies the stopband attenuation. In the stopband the gain will
  * be at most this value. A lower ripple value will allow a faster rolloff.
- * </para>
- * <para>
+ *
  * As a special case, a Chebyshev type 1 filter with no ripple is a Butterworth filter.
- * </para>
- * <para><note>
+ *
+ * <note>
  * Be warned that a too large number of poles can produce noise. The most poles are possible with
  * a cutoff frequency at a quarter of the sampling rate.
- * </note></para>
+ * </note>
+ *
+ * <refsect2>
  * <title>Example launch line</title>
- * <para>
- * <programlisting>
- * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiochebyshevfreqband mode=band-pass lower-frequency=1000 upper-frequenc=6000 poles=4 ! audioconvert ! alsasink
- * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiochebyshevfreqband mode=band-reject lower-frequency=1000 upper-frequency=4000 ripple=0.2 ! audioconvert ! alsasink
- * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiochebyshevfreqband mode=band-pass lower-frequency=1000 upper-frequency=4000 type=2 ! audioconvert ! alsasink
- * </programlisting>
- * </para>
+ * |[
+ * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequenc=6000 poles=4 ! audioconvert ! alsasink
+ * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiochebband mode=band-reject lower-frequency=1000 upper-frequency=4000 ripple=0.2 ! audioconvert ! alsasink
+ * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequency=4000 type=2 ! audioconvert ! alsasink
+ * ]|
  * </refsect2>
  */
 
 #include "config.h"
 #endif
 
+#include <string.h>
+
 #include <gst/gst.h>
 #include <gst/base/gstbasetransform.h>
 #include <gst/audio/audio.h>
 #include <gst/audio/gstaudiofilter.h>
-#include <gst/controller/gstcontroller.h>
 
 #include <math.h>
 
-#include "audiochebyshevfreqband.h"
+#include "math_compat.h"
 
-#define GST_CAT_DEFAULT gst_audio_chebyshev_freq_band_debug
-GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+#include "audiochebband.h"
 
-static const GstElementDetails element_details =
-GST_ELEMENT_DETAILS ("AudioChebyshevFreqBand",
-    "Filter/Effect/Audio",
-    "Chebyshev band pass and band reject filter",
-    "Sebastian Dröge <slomo@circular-chaos.org>");
+#include "gst/glib-compat-private.h"
 
-/* Filter signals and args */
-enum
-{
-  /* FILL ME */
-  LAST_SIGNAL
-};
+#define GST_CAT_DEFAULT gst_audio_cheb_band_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
 
 enum
 {
@@ -114,35 +99,18 @@ enum
   PROP_POLES
 };
 
-#define ALLOWED_CAPS \
-    "audio/x-raw-float,"                                              \
-    " width = (int) { 32, 64 }, "                                     \
-    " endianness = (int) BYTE_ORDER,"                                 \
-    " rate = (int) [ 1, MAX ],"                                       \
-    " channels = (int) [ 1, MAX ]"
-
-#define DEBUG_INIT(bla) \
-  GST_DEBUG_CATEGORY_INIT (gst_audio_chebyshev_freq_band_debug, "audiochebyshevfreqband", 0, "audiochebyshevfreqband element");
+#define gst_audio_cheb_band_parent_class parent_class
+G_DEFINE_TYPE (GstAudioChebBand, gst_audio_cheb_band,
+    GST_TYPE_AUDIO_FX_BASE_IIR_FILTER);
 
-GST_BOILERPLATE_FULL (GstAudioChebyshevFreqBand, gst_audio_chebyshev_freq_band,
-    GstAudioFilter, GST_TYPE_AUDIO_FILTER, DEBUG_INIT);
-
-static void gst_audio_chebyshev_freq_band_set_property (GObject * object,
+static void gst_audio_cheb_band_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_audio_chebyshev_freq_band_get_property (GObject * object,
+static void gst_audio_cheb_band_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_audio_cheb_band_finalize (GObject * object);
 
-static gboolean gst_audio_chebyshev_freq_band_setup (GstAudioFilter * filter,
-    GstRingBufferSpec * format);
-static GstFlowReturn
-gst_audio_chebyshev_freq_band_transform_ip (GstBaseTransform * base,
-    GstBuffer * buf);
-static gboolean gst_audio_chebyshev_freq_band_start (GstBaseTransform * base);
-
-static void process_64 (GstAudioChebyshevFreqBand * filter,
-    gdouble * data, guint num_samples);
-static void process_32 (GstAudioChebyshevFreqBand * filter,
-    gfloat * data, guint num_samples);
+static gboolean gst_audio_cheb_band_setup (GstAudioFilter * filter,
+    const GstAudioInfo * info);
 
 enum
 {
@@ -150,9 +118,9 @@ enum
   MODE_BAND_REJECT
 };
 
-#define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE (gst_audio_chebyshev_freq_band_mode_get_type ())
+#define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE (gst_audio_cheb_band_mode_get_type ())
 static GType
-gst_audio_chebyshev_freq_band_mode_get_type (void)
+gst_audio_cheb_band_mode_get_type (void)
 {
   static GType gtype = 0;
 
@@ -165,7 +133,7 @@ gst_audio_chebyshev_freq_band_mode_get_type (void)
       {0, NULL, NULL}
     };
 
-    gtype = g_enum_register_static ("GstAudioChebyshevFreqBandMode", values);
+    gtype = g_enum_register_static ("GstAudioChebBandMode", values);
   }
   return gtype;
 }
@@ -173,134 +141,86 @@ gst_audio_chebyshev_freq_band_mode_get_type (void)
 /* GObject vmethod implementations */
 
 static void
-gst_audio_chebyshev_freq_band_base_init (gpointer klass)
-{
-  GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
-  GstCaps *caps;
-
-  gst_element_class_set_details (element_class, &element_details);
-
-  caps = gst_caps_from_string (ALLOWED_CAPS);
-  gst_audio_filter_class_add_pad_templates (GST_AUDIO_FILTER_CLASS (klass),
-      caps);
-  gst_caps_unref (caps);
-}
-
-static void
-gst_audio_chebyshev_freq_band_dispose (GObject * object)
-{
-  GstAudioChebyshevFreqBand *filter = GST_AUDIO_CHEBYSHEV_FREQ_BAND (object);
-
-  if (filter->a) {
-    g_free (filter->a);
-    filter->a = NULL;
-  }
-
-  if (filter->b) {
-    g_free (filter->b);
-    filter->b = NULL;
-  }
-
-  if (filter->channels) {
-    GstAudioChebyshevFreqBandChannelCtx *ctx;
-    gint i, channels = GST_AUDIO_FILTER (filter)->format.channels;
-
-    for (i = 0; i < channels; i++) {
-      ctx = &filter->channels[i];
-      g_free (ctx->x);
-      g_free (ctx->y);
-    }
-
-    g_free (filter->channels);
-    filter->channels = NULL;
-  }
-
-  G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static void
-gst_audio_chebyshev_freq_band_class_init (GstAudioChebyshevFreqBandClass *
-    klass)
+gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass)
 {
-  GObjectClass *gobject_class;
-  GstBaseTransformClass *trans_class;
-  GstAudioFilterClass *filter_class;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstElementClass *gstelement_class = (GstElementClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
 
-  gobject_class = (GObjectClass *) klass;
-  trans_class = (GstBaseTransformClass *) klass;
-  filter_class = (GstAudioFilterClass *) klass;
+  GST_DEBUG_CATEGORY_INIT (gst_audio_cheb_band_debug, "audiochebband", 0,
+      "audiochebband element");
 
-  gobject_class->set_property = gst_audio_chebyshev_freq_band_set_property;
-  gobject_class->get_property = gst_audio_chebyshev_freq_band_get_property;
-  gobject_class->dispose = gst_audio_chebyshev_freq_band_dispose;
+  gobject_class->set_property = gst_audio_cheb_band_set_property;
+  gobject_class->get_property = gst_audio_cheb_band_get_property;
+  gobject_class->finalize = gst_audio_cheb_band_finalize;
 
   g_object_class_install_property (gobject_class, PROP_MODE,
       g_param_spec_enum ("mode", "Mode",
           "Low pass or high pass mode", GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE,
-          MODE_BAND_PASS, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+          MODE_BAND_PASS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_TYPE,
-      g_param_spec_int ("type", "Type",
-          "Type of the chebychev filter", 1, 2,
-          1, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+      g_param_spec_int ("type", "Type", "Type of the chebychev filter", 1, 2, 1,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
 
   /* FIXME: Don't use the complete possible range but restrict the upper boundary
    * so automatically generated UIs can use a slider without */
   g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY,
       g_param_spec_float ("lower-frequency", "Lower frequency",
           "Start frequency of the band (Hz)", 0.0, 100000.0,
-          0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+          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",
-          "Stop frequency of the band (Hz)", 0.0, 100000.0,
-          0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+          "Stop frequency of the band (Hz)", 0.0, 100000.0, 0.0,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
   g_object_class_install_property (gobject_class, PROP_RIPPLE,
-      g_param_spec_float ("ripple", "Ripple",
-          "Amount of ripple (dB)", 0.0, 200.0,
-          0.25, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+      g_param_spec_float ("ripple", "Ripple", "Amount of ripple (dB)", 0.0,
+          200.0, 0.25,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
   /* FIXME: What to do about this upper boundary? With a frequencies near
    * rate/4 32 poles are completely possible, with frequencies very low
    * or very high 16 poles already produces only noise */
   g_object_class_install_property (gobject_class, PROP_POLES,
       g_param_spec_int ("poles", "Poles",
           "Number of poles to use, will be rounded up to the next multiply of four",
-          4, 32, 4, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+          4, 32, 4,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
 
-  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_chebyshev_freq_band_setup);
-  trans_class->transform_ip =
-      GST_DEBUG_FUNCPTR (gst_audio_chebyshev_freq_band_transform_ip);
-  trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_chebyshev_freq_band_start);
+  gst_element_class_set_details_simple (gstelement_class,
+      "Band pass & band reject filter", "Filter/Effect/Audio",
+      "Chebyshev band pass and band reject filter",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_band_setup);
 }
 
 static void
-gst_audio_chebyshev_freq_band_init (GstAudioChebyshevFreqBand * filter,
-    GstAudioChebyshevFreqBandClass * klass)
+gst_audio_cheb_band_init (GstAudioChebBand * filter)
 {
   filter->lower_frequency = filter->upper_frequency = 0.0;
   filter->mode = MODE_BAND_PASS;
   filter->type = 1;
   filter->poles = 4;
   filter->ripple = 0.25;
-  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
 
-  filter->have_coeffs = FALSE;
-  filter->num_a = 0;
-  filter->num_b = 0;
-  filter->channels = NULL;
+  g_mutex_init (&filter->lock);
 }
 
 static void
-generate_biquad_coefficients (GstAudioChebyshevFreqBand * filter,
-    gint p, gdouble * a0, gdouble * a1, gdouble * a2, gdouble * a3,
-    gdouble * a4, gdouble * b1, gdouble * b2, gdouble * b3, gdouble * b4)
+generate_biquad_coefficients (GstAudioChebBand * filter,
+    gint p, gdouble * b0, gdouble * b1, gdouble * b2, gdouble * b3,
+    gdouble * b4, gdouble * a1, gdouble * a2, gdouble * a3, gdouble * a4)
 {
   gint np = filter->poles / 2;
   gdouble ripple = filter->ripple;
+  gint rate = GST_AUDIO_FILTER_RATE (filter);
 
   /* pole location in s-plane */
   gdouble rp, ip;
 
   /* zero location in s-plane */
-  gdouble rz = 0.0, iz = 0.0;
+  gdouble iz = 0.0;
 
   /* transfer function coefficients for the z-plane */
   gdouble x0, x1, x2, y1, y2;
@@ -308,7 +228,7 @@ generate_biquad_coefficients (GstAudioChebyshevFreqBand * filter,
 
   /* Calculate pole location for lowpass at frequency 1 */
   {
-    gdouble angle = (M_PI / 2.0) * (2.0 * p - 1) / np;
+    gdouble angle = (G_PI / 2.0) * (2.0 * p - 1) / np;
 
     rp = -sin (angle);
     ip = cos (angle);
@@ -345,13 +265,11 @@ generate_biquad_coefficients (GstAudioChebyshevFreqBand * filter,
   /* Calculate zero location for frequency 1 on the
    * unit circle for type 2 */
   if (type == 2) {
-    gdouble angle = M_PI / (np * 2.0) + ((p - 1) * M_PI) / (np);
+    gdouble angle = G_PI / (np * 2.0) + ((p - 1) * G_PI) / (np);
     gdouble mag2;
 
-    rz = 0.0;
     iz = cos (angle);
-    mag2 = rz * rz + iz * iz;
-    rz /= mag2;
+    mag2 = iz * iz;
     iz /= mag2;
   }
 
@@ -419,12 +337,8 @@ generate_biquad_coefficients (GstAudioChebyshevFreqBand * filter,
   {
     gdouble a, b, d;
     gdouble alpha, beta;
-    gdouble w0 =
-        2.0 * M_PI * (filter->lower_frequency /
-        GST_AUDIO_FILTER (filter)->format.rate);
-    gdouble w1 =
-        2.0 * M_PI * (filter->upper_frequency /
-        GST_AUDIO_FILTER (filter)->format.rate);
+    gdouble w0 = 2.0 * G_PI * (filter->lower_frequency / rate);
+    gdouble w1 = 2.0 * G_PI * (filter->upper_frequency / rate);
 
     if (filter->mode == MODE_BAND_PASS) {
       a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
@@ -435,19 +349,19 @@ generate_biquad_coefficients (GstAudioChebyshevFreqBand * filter,
 
       d = 1.0 + beta * (y1 - beta * y2);
 
-      *a0 = (x0 + beta * (-x1 + beta * x2)) / d;
-      *a1 = (alpha * (-2.0 * x0 + x1 + beta * x1 - 2.0 * beta * x2)) / d;
-      *a2 =
+      *b0 = (x0 + beta * (-x1 + beta * x2)) / d;
+      *b1 = (alpha * (-2.0 * x0 + x1 + beta * x1 - 2.0 * beta * x2)) / d;
+      *b2 =
           (-x1 - beta * beta * x1 + 2.0 * beta * (x0 + x2) +
           alpha * alpha * (x0 - x1 + x2)) / d;
-      *a3 = (alpha * (x1 + beta * (-2.0 * x0 + x1) - 2.0 * x2)) / d;
-      *a4 = (beta * (beta * x0 - x1) + x2) / d;
-      *b1 = (alpha * (2.0 + y1 + beta * y1 - 2.0 * beta * y2)) / d;
-      *b2 =
+      *b3 = (alpha * (x1 + beta * (-2.0 * x0 + x1) - 2.0 * x2)) / d;
+      *b4 = (beta * (beta * x0 - x1) + x2) / d;
+      *a1 = (alpha * (2.0 + y1 + beta * y1 - 2.0 * beta * y2)) / d;
+      *a2 =
           (-y1 - beta * beta * y1 - alpha * alpha * (1.0 + y1 - y2) +
           2.0 * beta * (-1.0 + y2)) / d;
-      *b3 = (alpha * (y1 + beta * (2.0 + y1) - 2.0 * y2)) / d;
-      *b4 = (-beta * beta - beta * y1 + y2) / d;
+      *a3 = (alpha * (y1 + beta * (2.0 + y1) - 2.0 * y2)) / d;
+      *a4 = (-beta * beta - beta * y1 + y2) / d;
     } else {
       a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
       b = tan (1.0 / 2.0) * tan ((w1 - w0) / 2.0);
@@ -457,121 +371,55 @@ generate_biquad_coefficients (GstAudioChebyshevFreqBand * filter,
 
       d = -1.0 + beta * (beta * y2 + y1);
 
-      *a0 = (-x0 - beta * x1 - beta * beta * x2) / d;
-      *a1 = (alpha * (2.0 * x0 + x1 + beta * x1 + 2.0 * beta * x2)) / d;
-      *a2 =
+      *b0 = (-x0 - beta * x1 - beta * beta * x2) / d;
+      *b1 = (alpha * (2.0 * x0 + x1 + beta * x1 + 2.0 * beta * x2)) / d;
+      *b2 =
           (-x1 - beta * beta * x1 - 2.0 * beta * (x0 + x2) -
           alpha * alpha * (x0 + x1 + x2)) / d;
-      *a3 = (alpha * (x1 + beta * (2.0 * x0 + x1) + 2.0 * x2)) / d;
-      *a4 = (-beta * beta * x0 - beta * x1 - x2) / d;
-      *b1 = (alpha * (-2.0 + y1 + beta * y1 + 2.0 * beta * y2)) / d;
-      *b2 =
+      *b3 = (alpha * (x1 + beta * (2.0 * x0 + x1) + 2.0 * x2)) / d;
+      *b4 = (-beta * beta * x0 - beta * x1 - x2) / d;
+      *a1 = (alpha * (-2.0 + y1 + beta * y1 + 2.0 * beta * y2)) / d;
+      *a2 =
           -(y1 + beta * beta * y1 + 2.0 * beta * (-1.0 + y2) +
           alpha * alpha * (-1.0 + y1 + y2)) / d;
-      *b3 = (alpha * (beta * (-2.0 + y1) + y1 + 2.0 * y2)) / d;
-      *b4 = -(-beta * beta + beta * y1 + y2) / d;
+      *a3 = (alpha * (beta * (-2.0 + y1) + y1 + 2.0 * y2)) / d;
+      *a4 = -(-beta * beta + beta * y1 + y2) / d;
     }
   }
 }
 
-/* Evaluate the transfer function that corresponds to the IIR
- * coefficients at zr + zi*I and return the magnitude */
-static gdouble
-calculate_gain (gdouble * a, gdouble * b, gint num_a, gint num_b, gdouble zr,
-    gdouble zi)
-{
-  gdouble sum_ar, sum_ai;
-  gdouble sum_br, sum_bi;
-  gdouble gain_r, gain_i;
-
-  gdouble sum_r_old;
-  gdouble sum_i_old;
-
-  gint i;
-
-  sum_ar = 0.0;
-  sum_ai = 0.0;
-  for (i = num_a; i >= 0; i--) {
-    sum_r_old = sum_ar;
-    sum_i_old = sum_ai;
-
-    sum_ar = (sum_r_old * zr - sum_i_old * zi) + a[i];
-    sum_ai = (sum_r_old * zi + sum_i_old * zr) + 0.0;
-  }
-
-  sum_br = 0.0;
-  sum_bi = 0.0;
-  for (i = num_b; i >= 0; i--) {
-    sum_r_old = sum_br;
-    sum_i_old = sum_bi;
-
-    sum_br = (sum_r_old * zr - sum_i_old * zi) - b[i];
-    sum_bi = (sum_r_old * zi + sum_i_old * zr) - 0.0;
-  }
-  sum_br += 1.0;
-  sum_bi += 0.0;
-
-  gain_r =
-      (sum_ar * sum_br + sum_ai * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi);
-  gain_i =
-      (sum_ai * sum_br - sum_ar * sum_bi) / (sum_br * sum_br + sum_bi * sum_bi);
-
-  return (sqrt (gain_r * gain_r + gain_i * gain_i));
-}
-
 static void
-generate_coefficients (GstAudioChebyshevFreqBand * filter)
+generate_coefficients (GstAudioChebBand * filter)
 {
-  gint channels = GST_AUDIO_FILTER (filter)->format.channels;
-
-  if (filter->a) {
-    g_free (filter->a);
-    filter->a = NULL;
-  }
-
-  if (filter->b) {
-    g_free (filter->b);
-    filter->b = NULL;
-  }
-
-  if (filter->channels) {
-    GstAudioChebyshevFreqBandChannelCtx *ctx;
-    gint i;
+  gint rate = GST_AUDIO_FILTER_RATE (filter);
 
-    for (i = 0; i < channels; i++) {
-      ctx = &filter->channels[i];
-      g_free (ctx->x);
-      g_free (ctx->y);
-    }
+  if (rate == 0) {
+    gdouble *a = g_new0 (gdouble, 1);
+    gdouble *b = g_new0 (gdouble, 1);
 
-    g_free (filter->channels);
-    filter->channels = NULL;
-  }
-
-  if (GST_AUDIO_FILTER (filter)->format.rate == 0) {
-    filter->num_a = 1;
-    filter->a = g_new0 (gdouble, 1);
-    filter->a[0] = 1.0;
-    filter->num_b = 0;
-    filter->channels = g_new0 (GstAudioChebyshevFreqBandChannelCtx, channels);
+    a[0] = 1.0;
+    b[0] = 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, b, 1);
     GST_LOG_OBJECT (filter, "rate was not set yet");
     return;
   }
 
-  filter->have_coeffs = TRUE;
-
   if (filter->upper_frequency <= filter->lower_frequency) {
-    filter->num_a = 1;
-    filter->a = g_new0 (gdouble, 1);
-    filter->a[0] = (filter->mode == MODE_BAND_PASS) ? 0.0 : 1.0;
-    filter->num_b = 0;
-    filter->channels = g_new0 (GstAudioChebyshevFreqBandChannelCtx, channels);
+    gdouble *a = g_new0 (gdouble, 1);
+    gdouble *b = g_new0 (gdouble, 1);
+
+    a[0] = 1.0;
+    b[0] = (filter->mode == MODE_BAND_PASS) ? 0.0 : 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, b, 1);
+
     GST_LOG_OBJECT (filter, "frequency band had no or negative dimension");
     return;
   }
 
-  if (filter->upper_frequency > GST_AUDIO_FILTER (filter)->format.rate / 2) {
-    filter->upper_frequency = GST_AUDIO_FILTER (filter)->format.rate / 2;
+  if (filter->upper_frequency > rate / 2) {
+    filter->upper_frequency = rate / 2;
     GST_LOG_OBJECT (filter, "clipped upper frequency to nyquist frequency");
   }
 
@@ -586,30 +434,20 @@ generate_coefficients (GstAudioChebyshevFreqBand * filter)
     gdouble *a, *b;
     gint i, p;
 
-    filter->num_a = np + 1;
-    filter->a = a = g_new0 (gdouble, np + 5);
-    filter->num_b = np + 1;
-    filter->b = b = g_new0 (gdouble, np + 5);
-
-    filter->channels = g_new0 (GstAudioChebyshevFreqBandChannelCtx, channels);
-    for (i = 0; i < channels; i++) {
-      GstAudioChebyshevFreqBandChannelCtx *ctx = &filter->channels[i];
-
-      ctx->x = g_new0 (gdouble, np + 1);
-      ctx->y = g_new0 (gdouble, np + 1);
-    }
+    a = g_new0 (gdouble, np + 5);
+    b = g_new0 (gdouble, np + 5);
 
     /* Calculate transfer function coefficients */
     a[4] = 1.0;
     b[4] = 1.0;
 
     for (p = 1; p <= np / 4; p++) {
-      gdouble a0, a1, a2, a3, a4, b1, b2, b3, b4;
+      gdouble b0, b1, b2, b3, b4, a1, a2, a3, a4;
       gdouble *ta = g_new0 (gdouble, np + 5);
       gdouble *tb = g_new0 (gdouble, np + 5);
 
-      generate_biquad_coefficients (filter, p, &a0, &a1, &a2, &a3, &a4, &b1,
-          &b2, &b3, &b4);
+      generate_biquad_coefficients (filter, p, &b0, &b1, &b2, &b3, &b4, &a1,
+          &a2, &a3, &a4);
 
       memcpy (ta, a, sizeof (gdouble) * (np + 5));
       memcpy (tb, b, sizeof (gdouble) * (np + 5));
@@ -618,25 +456,23 @@ generate_coefficients (GstAudioChebyshevFreqBand * filter)
        * to the cascade by multiplication of the transfer
        * functions */
       for (i = 4; i < np + 5; i++) {
-        a[i] =
-            a0 * ta[i] + a1 * ta[i - 1] + a2 * ta[i - 2] + a3 * ta[i - 3] +
-            a4 * ta[i - 4];
         b[i] =
-            tb[i] - b1 * tb[i - 1] - b2 * tb[i - 2] - b3 * tb[i - 3] -
+            b0 * tb[i] + b1 * tb[i - 1] + b2 * tb[i - 2] + b3 * tb[i - 3] +
             b4 * tb[i - 4];
+        a[i] =
+            ta[i] - a1 * ta[i - 1] - a2 * ta[i - 2] - a3 * ta[i - 3] -
+            a4 * ta[i - 4];
       }
       g_free (ta);
       g_free (tb);
     }
 
-    /* Move coefficients to the beginning of the array
-     * and multiply the b coefficients with -1 to move from
+    /* Move coefficients to the beginning of the array to move from
      * the transfer function's coefficients to the difference
      * equation's coefficients */
-    b[4] = 0.0;
     for (i = 0; i <= np; i++) {
       a[i] = a[i + 4];
-      b[i] = -b[i + 4];
+      b[i] = b[i + 4];
     }
 
     /* Normalize to unity gain at frequency 0 and frequency
@@ -645,32 +481,37 @@ generate_coefficients (GstAudioChebyshevFreqBand * filter)
     if (filter->mode == MODE_BAND_REJECT) {
       /* gain is sqrt(H(0)*H(0.5)) */
 
-      gdouble gain1 = calculate_gain (a, b, np, np, 1.0, 0.0);
-      gdouble gain2 = calculate_gain (a, b, np, np, -1.0, 0.0);
+      gdouble gain1 =
+          gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+          1.0, 0.0);
+      gdouble gain2 =
+          gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+          -1.0, 0.0);
 
       gain1 = sqrt (gain1 * gain2);
 
       for (i = 0; i <= np; i++) {
-        a[i] /= gain1;
+        b[i] /= gain1;
       }
     } else {
       /* gain is H(wc), wc = center frequency */
 
-      gdouble w1 =
-          2.0 * M_PI * (filter->lower_frequency /
-          GST_AUDIO_FILTER (filter)->format.rate);
-      gdouble w2 =
-          2.0 * M_PI * (filter->upper_frequency /
-          GST_AUDIO_FILTER (filter)->format.rate);
+      gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / rate);
+      gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / rate);
       gdouble w0 = (w2 + w1) / 2.0;
       gdouble zr = cos (w0), zi = sin (w0);
-      gdouble gain = calculate_gain (a, b, np, np, zr, zi);
+      gdouble gain =
+          gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr,
+          zi);
 
       for (i = 0; i <= np; i++) {
-        a[i] /= gain;
+        b[i] /= gain;
       }
     }
 
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, np + 1, b, np + 1);
+
     GST_LOG_OBJECT (filter,
         "Generated IIR coefficients for the Chebyshev filter");
     GST_LOG_OBJECT (filter,
@@ -680,81 +521,89 @@ generate_coefficients (GstAudioChebyshevFreqBand * filter)
         filter->upper_frequency, filter->ripple);
 
     GST_LOG_OBJECT (filter, "%.2f dB gain @ 0Hz",
-        20.0 * log10 (calculate_gain (a, b, np, np, 1.0, 0.0)));
+        20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
+                np + 1, 1.0, 0.0)));
     {
-      gdouble w1 =
-          2.0 * M_PI * (filter->lower_frequency /
-          GST_AUDIO_FILTER (filter)->format.rate);
-      gdouble w2 =
-          2.0 * M_PI * (filter->upper_frequency /
-          GST_AUDIO_FILTER (filter)->format.rate);
+      gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / rate);
+      gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / rate);
       gdouble w0 = (w2 + w1) / 2.0;
       gdouble zr, zi;
 
       zr = cos (w1);
       zi = sin (w1);
       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
-          20.0 * log10 (calculate_gain (a, b, np, np, zr, zi)),
-          (int) filter->lower_frequency);
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)), (int) filter->lower_frequency);
       zr = cos (w0);
       zi = sin (w0);
       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
-          20.0 * log10 (calculate_gain (a, b, np, np, zr, zi)),
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)),
           (int) ((filter->lower_frequency + filter->upper_frequency) / 2.0));
       zr = cos (w2);
       zi = sin (w2);
       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
-          20.0 * log10 (calculate_gain (a, b, np, np, zr, zi)),
-          (int) filter->upper_frequency);
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)), (int) filter->upper_frequency);
     }
     GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
-        20.0 * log10 (calculate_gain (a, b, np, np, -1.0, 0.0)),
-        GST_AUDIO_FILTER (filter)->format.rate / 2);
+        20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
+                np + 1, -1.0, 0.0)), rate / 2);
   }
 }
 
 static void
-gst_audio_chebyshev_freq_band_set_property (GObject * object, guint prop_id,
+gst_audio_cheb_band_finalize (GObject * object)
+{
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
+
+  g_mutex_clear (&filter->lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_audio_cheb_band_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
-  GstAudioChebyshevFreqBand *filter = GST_AUDIO_CHEBYSHEV_FREQ_BAND (object);
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
 
   switch (prop_id) {
     case PROP_MODE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      g_mutex_lock (&filter->lock);
       filter->mode = g_value_get_enum (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      g_mutex_unlock (&filter->lock);
       break;
     case PROP_TYPE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      g_mutex_lock (&filter->lock);
       filter->type = g_value_get_int (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      g_mutex_unlock (&filter->lock);
       break;
     case PROP_LOWER_FREQUENCY:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      g_mutex_lock (&filter->lock);
       filter->lower_frequency = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      g_mutex_unlock (&filter->lock);
       break;
     case PROP_UPPER_FREQUENCY:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      g_mutex_lock (&filter->lock);
       filter->upper_frequency = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      g_mutex_unlock (&filter->lock);
       break;
     case PROP_RIPPLE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      g_mutex_lock (&filter->lock);
       filter->ripple = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      g_mutex_unlock (&filter->lock);
       break;
     case PROP_POLES:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      g_mutex_lock (&filter->lock);
       filter->poles = GST_ROUND_UP_4 (g_value_get_int (value));
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      g_mutex_unlock (&filter->lock);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -763,10 +612,10 @@ gst_audio_chebyshev_freq_band_set_property (GObject * object, guint prop_id,
 }
 
 static void
-gst_audio_chebyshev_freq_band_get_property (GObject * object, guint prop_id,
+gst_audio_cheb_band_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec)
 {
-  GstAudioChebyshevFreqBand *filter = GST_AUDIO_CHEBYSHEV_FREQ_BAND (object);
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
 
   switch (prop_id) {
     case PROP_MODE:
@@ -796,127 +645,11 @@ gst_audio_chebyshev_freq_band_get_property (GObject * object, guint prop_id,
 /* GstAudioFilter vmethod implementations */
 
 static gboolean
-gst_audio_chebyshev_freq_band_setup (GstAudioFilter * base,
-    GstRingBufferSpec * format)
+gst_audio_cheb_band_setup (GstAudioFilter * base, const GstAudioInfo * info)
 {
-  GstAudioChebyshevFreqBand *filter = GST_AUDIO_CHEBYSHEV_FREQ_BAND (base);
-  gboolean ret = TRUE;
+  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base);
 
-  if (format->width == 32)
-    filter->process = (GstAudioChebyshevFreqBandProcessFunc)
-        process_32;
-  else if (format->width == 64)
-    filter->process = (GstAudioChebyshevFreqBandProcessFunc)
-        process_64;
-  else
-    ret = FALSE;
-
-  filter->have_coeffs = FALSE;
-
-  return ret;
-}
+  generate_coefficients (filter);
 
-static inline gdouble
-process (GstAudioChebyshevFreqBand * filter,
-    GstAudioChebyshevFreqBandChannelCtx * ctx, gdouble x0)
-{
-  gdouble val = filter->a[0] * x0;
-  gint i, j;
-
-  for (i = 1, j = ctx->x_pos; i < filter->num_a; i++) {
-    val += filter->a[i] * ctx->x[j];
-    j--;
-    if (j < 0)
-      j = filter->num_a - 1;
-  }
-
-  for (i = 1, j = ctx->y_pos; i < filter->num_b; i++) {
-    val += filter->b[i] * ctx->y[j];
-    j--;
-    if (j < 0)
-      j = filter->num_b - 1;
-  }
-
-  if (ctx->x) {
-    ctx->x_pos++;
-    if (ctx->x_pos > filter->num_a - 1)
-      ctx->x_pos = 0;
-    ctx->x[ctx->x_pos] = x0;
-  }
-
-  if (ctx->y) {
-    ctx->y_pos++;
-    if (ctx->y_pos > filter->num_b - 1)
-      ctx->y_pos = 0;
-
-    ctx->y[ctx->y_pos] = val;
-  }
-
-  return val;
-}
-
-#define DEFINE_PROCESS_FUNC(width,ctype) \
-static void \
-process_##width (GstAudioChebyshevFreqBand * filter, \
-    g##ctype * data, guint num_samples) \
-{ \
-  gint i, j, channels = GST_AUDIO_FILTER (filter)->format.channels; \
-  gdouble val; \
-  \
-  for (i = 0; i < num_samples / channels; i++) { \
-    for (j = 0; j < channels; j++) { \
-      val = process (filter, &filter->channels[j], *data); \
-      *data++ = val; \
-    } \
-  } \
-}
-
-DEFINE_PROCESS_FUNC (32, float);
-DEFINE_PROCESS_FUNC (64, double);
-
-#undef DEFINE_PROCESS_FUNC
-
-/* GstBaseTransform vmethod implementations */
-static GstFlowReturn
-gst_audio_chebyshev_freq_band_transform_ip (GstBaseTransform * base,
-    GstBuffer * buf)
-{
-  GstAudioChebyshevFreqBand *filter = GST_AUDIO_CHEBYSHEV_FREQ_BAND (base);
-  guint num_samples =
-      GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8);
-
-  if (!gst_buffer_is_writable (buf))
-    return GST_FLOW_OK;
-
-  if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf)))
-    gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf));
-
-  if (!filter->have_coeffs)
-    generate_coefficients (filter);
-
-  filter->process (filter, GST_BUFFER_DATA (buf), num_samples);
-
-  return GST_FLOW_OK;
-}
-
-static gboolean
-gst_audio_chebyshev_freq_band_start (GstBaseTransform * base)
-{
-  GstAudioChebyshevFreqBand *filter = GST_AUDIO_CHEBYSHEV_FREQ_BAND (base);
-  gint channels = GST_AUDIO_FILTER (filter)->format.channels;
-  GstAudioChebyshevFreqBandChannelCtx *ctx;
-  gint i;
-
-  /* Reset the history of input and output values if
-   * already existing */
-  if (channels && filter->channels) {
-    for (i = 0; i < channels; i++) {
-      ctx = &filter->channels[i];
-      if (ctx->x)
-        memset (ctx->x, 0, (filter->poles + 1) * sizeof (gdouble));
-      if (ctx->y)
-        memset (ctx->y, 0, (filter->poles + 1) * sizeof (gdouble));
-    }
-  }
-  return TRUE;
+  return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
 }