gst/audiofx/: Implement a base class for IIR filters.
authorSebastian Dröge <slomo@circular-chaos.org>
Mon, 5 Jan 2009 10:13:29 +0000 (10:13 +0000)
committerSebastian Dröge <slomo@circular-chaos.org>
Mon, 5 Jan 2009 10:13:29 +0000 (10:13 +0000)
Original commit message from CVS:
* gst/audiofx/Makefile.am:
* gst/audiofx/audiofxbaseiirfilter.c:
(gst_audio_fx_base_iir_filter_base_init),
(gst_audio_fx_base_iir_filter_dispose),
(gst_audio_fx_base_iir_filter_class_init),
(gst_audio_fx_base_iir_filter_init),
(gst_audio_fx_base_iir_filter_calculate_gain),
(gst_audio_fx_base_iir_filter_set_coefficients),
(gst_audio_fx_base_iir_filter_setup), (process),
(gst_audio_fx_base_iir_filter_transform_ip),
(gst_audio_fx_base_iir_filter_stop):
* gst/audiofx/audiofxbaseiirfilter.h:
Implement a base class for IIR filters.
* gst/audiofx/audiochebband.c: (gst_audio_cheb_band_base_init),
(gst_audio_cheb_band_class_init), (gst_audio_cheb_band_init),
(generate_coefficients), (gst_audio_cheb_band_set_property),
(gst_audio_cheb_band_setup):
* gst/audiofx/audiochebband.h:
* gst/audiofx/audiocheblimit.c: (gst_audio_cheb_limit_base_init),
(gst_audio_cheb_limit_class_init), (gst_audio_cheb_limit_init),
(generate_coefficients), (gst_audio_cheb_limit_set_property),
(gst_audio_cheb_limit_setup):
* gst/audiofx/audiocheblimit.h:
Use the IIR filter base class for the chebyshev filters.

ChangeLog
gst/audiofx/Makefile.am
gst/audiofx/audiochebband.c
gst/audiofx/audiochebband.h
gst/audiofx/audiocheblimit.c
gst/audiofx/audiocheblimit.h
gst/audiofx/audiofxbaseiirfilter.c [new file with mode: 0644]
gst/audiofx/audiofxbaseiirfilter.h [new file with mode: 0644]

index ff7a370..364df12 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2009-01-05  Sebastian Dröge  <sebastian.droege@collabora.co.uk>
+
+       * gst/audiofx/Makefile.am:
+       * gst/audiofx/audiofxbaseiirfilter.c:
+       (gst_audio_fx_base_iir_filter_base_init),
+       (gst_audio_fx_base_iir_filter_dispose),
+       (gst_audio_fx_base_iir_filter_class_init),
+       (gst_audio_fx_base_iir_filter_init),
+       (gst_audio_fx_base_iir_filter_calculate_gain),
+       (gst_audio_fx_base_iir_filter_set_coefficients),
+       (gst_audio_fx_base_iir_filter_setup), (process),
+       (gst_audio_fx_base_iir_filter_transform_ip),
+       (gst_audio_fx_base_iir_filter_stop):
+       * gst/audiofx/audiofxbaseiirfilter.h:
+       Implement a base class for IIR filters.
+
+       * gst/audiofx/audiochebband.c: (gst_audio_cheb_band_base_init),
+       (gst_audio_cheb_band_class_init), (gst_audio_cheb_band_init),
+       (generate_coefficients), (gst_audio_cheb_band_set_property),
+       (gst_audio_cheb_band_setup):
+       * gst/audiofx/audiochebband.h:
+       * gst/audiofx/audiocheblimit.c: (gst_audio_cheb_limit_base_init),
+       (gst_audio_cheb_limit_class_init), (gst_audio_cheb_limit_init),
+       (generate_coefficients), (gst_audio_cheb_limit_set_property),
+       (gst_audio_cheb_limit_setup):
+       * gst/audiofx/audiocheblimit.h:
+       Use the IIR filter base class for the chebyshev filters.
+
 2009-01-02  Michael Smith <msmith@songbirdnest.com>
 
          Patch by: Justin Karnegas <justin@affinix.com> and
index 364e827..ac6439b 100644 (file)
@@ -9,6 +9,7 @@ libgstaudiofx_la_SOURCES = audiofx.c\
        audioamplify.c \
        audiodynamic.c \
        audiokaraoke.c \
+       audiofxbaseiirfilter.c \
        audiocheblimit.c \
        audiochebband.c \
        audiowsincband.c \
@@ -34,6 +35,7 @@ noinst_HEADERS = audiopanorama.h \
        audioamplify.h \
        audiodynamic.h \
        audiokaraoke.h \
+       audiofxbaseiirfilter.h \
        audiocheblimit.h \
        audiochebband.h \
        audiowsincband.h \
index 40f35d2..36aeb8d 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
 #define GST_CAT_DEFAULT gst_audio_cheb_band_debug
 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
 
-static const GstElementDetails element_details =
-GST_ELEMENT_DETAILS ("Band pass & band reject filter",
-    "Filter/Effect/Audio",
-    "Chebyshev band pass and band reject filter",
-    "Sebastian Dröge <slomo@circular-chaos.org>");
-
-/* Filter signals and args */
-enum
-{
-  /* FILL ME */
-  LAST_SIGNAL
-};
-
 enum
 {
   PROP_0,
@@ -116,18 +103,11 @@ 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_cheb_band_debug, "audiochebband", 0, "audiochebband element");
 
 GST_BOILERPLATE_FULL (GstAudioChebBand, gst_audio_cheb_band,
-    GstAudioFilter, GST_TYPE_AUDIO_FILTER, DEBUG_INIT);
+    GstAudioFXBaseIIRFilter, GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, DEBUG_INIT);
 
 static void gst_audio_cheb_band_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec);
@@ -136,14 +116,6 @@ static void gst_audio_cheb_band_get_property (GObject * object,
 
 static gboolean gst_audio_cheb_band_setup (GstAudioFilter * filter,
     GstRingBufferSpec * format);
-static GstFlowReturn
-gst_audio_cheb_band_transform_ip (GstBaseTransform * base, GstBuffer * buf);
-static gboolean gst_audio_cheb_band_start (GstBaseTransform * base);
-
-static void process_64 (GstAudioChebBand * filter,
-    gdouble * data, guint num_samples);
-static void process_32 (GstAudioChebBand * filter,
-    gfloat * data, guint num_samples);
 
 enum
 {
@@ -177,98 +149,56 @@ static void
 gst_audio_cheb_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_cheb_band_dispose (GObject * object)
-{
-  GstAudioChebBand *filter = GST_AUDIO_CHEB_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) {
-    GstAudioChebBandChannelCtx *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);
+  gst_element_class_set_details_simple (element_class,
+      "Band pass & band reject filter", "Filter/Effect/Audio",
+      "Chebyshev band pass and band reject filter",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
 }
 
 static void
 gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass)
 {
-  GObjectClass *gobject_class;
-  GstBaseTransformClass *trans_class;
-  GstAudioFilterClass *filter_class;
-
-  gobject_class = (GObjectClass *) klass;
-  trans_class = (GstBaseTransformClass *) klass;
-  filter_class = (GstAudioFilterClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
 
   gobject_class->set_property = gst_audio_cheb_band_set_property;
   gobject_class->get_property = gst_audio_cheb_band_get_property;
-  gobject_class->dispose = gst_audio_cheb_band_dispose;
 
   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_cheb_band_setup);
-  trans_class->transform_ip =
-      GST_DEBUG_FUNCPTR (gst_audio_cheb_band_transform_ip);
-  trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_cheb_band_start);
 }
 
 static void
@@ -280,12 +210,6 @@ gst_audio_cheb_band_init (GstAudioChebBand * filter,
   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;
 }
 
 static void
@@ -474,98 +398,26 @@ generate_biquad_coefficients (GstAudioChebBand * filter,
   }
 }
 
-/* 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 (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) {
-    GstAudioChebBandChannelCtx *ctx;
-    gint i;
-
-    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;
-  }
-
   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 (GstAudioChebBandChannelCtx, channels);
+    gdouble *a = g_new0 (gdouble, 1);
+
+    a[0] = 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, NULL, 0);
     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 (GstAudioChebBandChannelCtx, channels);
+    gdouble *a = g_new0 (gdouble, 1);
+
+    a[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, NULL, 0);
+
     GST_LOG_OBJECT (filter, "frequency band had no or negative dimension");
     return;
   }
@@ -586,18 +438,8 @@ generate_coefficients (GstAudioChebBand * 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 (GstAudioChebBandChannelCtx, channels);
-    for (i = 0; i < channels; i++) {
-      GstAudioChebBandChannelCtx *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;
@@ -645,8 +487,12 @@ generate_coefficients (GstAudioChebBand * 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);
 
@@ -664,13 +510,18 @@ generate_coefficients (GstAudioChebBand * filter)
           GST_AUDIO_FILTER (filter)->format.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;
       }
     }
 
+    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,7 +531,8 @@ generate_coefficients (GstAudioChebBand * 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 /
@@ -694,21 +546,23 @@ generate_coefficients (GstAudioChebBand * filter)
       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)),
+        20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
+                np + 1, -1.0, 0.0)),
         GST_AUDIO_FILTER (filter)->format.rate / 2);
   }
 }
@@ -721,40 +575,40 @@ gst_audio_cheb_band_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_MODE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->mode = g_value_get_enum (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_TYPE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->type = g_value_get_int (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_LOWER_FREQUENCY:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->lower_frequency = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_UPPER_FREQUENCY:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->upper_frequency = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_RIPPLE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->ripple = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_POLES:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->poles = GST_ROUND_UP_4 (g_value_get_int (value));
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -799,122 +653,8 @@ static gboolean
 gst_audio_cheb_band_setup (GstAudioFilter * base, GstRingBufferSpec * format)
 {
   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base);
-  gboolean ret = TRUE;
-
-  if (format->width == 32)
-    filter->process = (GstAudioChebBandProcessFunc)
-        process_32;
-  else if (format->width == 64)
-    filter->process = (GstAudioChebBandProcessFunc)
-        process_64;
-  else
-    ret = FALSE;
-
-  filter->have_coeffs = FALSE;
-
-  return ret;
-}
-
-static inline gdouble
-process (GstAudioChebBand * filter,
-    GstAudioChebBandChannelCtx * 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 (GstAudioChebBand * 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_cheb_band_transform_ip (GstBaseTransform * base, GstBuffer * buf)
-{
-  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base);
-  guint num_samples =
-      GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8);
-
-  if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf)))
-    gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf));
-
-  if (gst_base_transform_is_passthrough (base))
-    return GST_FLOW_OK;
 
-  if (!filter->have_coeffs)
-    generate_coefficients (filter);
-
-  filter->process (filter, GST_BUFFER_DATA (buf), num_samples);
-
-  return GST_FLOW_OK;
-}
+  generate_coefficients (filter);
 
-static gboolean
-gst_audio_cheb_band_start (GstBaseTransform * base)
-{
-  GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base);
-  gint channels = GST_AUDIO_FILTER (filter)->format.channels;
-  GstAudioChebBandChannelCtx *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, format);
 }
index ece011a..fae1a0c 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
@@ -26,6 +26,8 @@
 #include <gst/audio/audio.h>
 #include <gst/audio/gstaudiofilter.h>
 
+#include "audiofxbaseiirfilter.h"
+
 G_BEGIN_DECLS
 #define GST_TYPE_AUDIO_CHEB_BAND            (gst_audio_cheb_band_get_type())
 #define GST_AUDIO_CHEB_BAND(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CHEB_BAND,GstAudioChebBand))
@@ -36,19 +38,9 @@ G_BEGIN_DECLS
 typedef struct _GstAudioChebBand GstAudioChebBand;
 typedef struct _GstAudioChebBandClass GstAudioChebBandClass;
 
-typedef void (*GstAudioChebBandProcessFunc) (GstAudioChebBand *, guint8 *, guint);
-
-typedef struct
-{
-  gdouble *x;
-  gint x_pos;
-  gdouble *y;
-  gint y_pos;
-} GstAudioChebBandChannelCtx;
-
 struct _GstAudioChebBand
 {
-  GstAudioFilter audiofilter;
+  GstAudioFXBaseIIRFilter parent;
 
   gint mode;
   gint type;
@@ -56,21 +48,11 @@ struct _GstAudioChebBand
   gfloat lower_frequency;
   gfloat upper_frequency;
   gfloat ripple;
-
-  /* < private > */
-  GstAudioChebBandProcessFunc process;
-
-  gboolean have_coeffs;
-  gdouble *a;
-  gint num_a;
-  gdouble *b;
-  gint num_b;
-  GstAudioChebBandChannelCtx *channels;
 };
 
 struct _GstAudioChebBandClass
 {
-  GstAudioFilterClass parent;
+  GstAudioFXBaseIIRFilterClass parent;
 };
 
 GType gst_audio_cheb_band_get_type (void);
index e4da0ca..4d8d311 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
 #define GST_CAT_DEFAULT gst_audio_cheb_limit_debug
 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
 
-static const GstElementDetails element_details =
-GST_ELEMENT_DETAILS ("Low pass & high pass filter",
-    "Filter/Effect/Audio",
-    "Chebyshev low pass and high pass filter",
-    "Sebastian Dröge <slomo@circular-chaos.org>");
-
-/* Filter signals and args */
-enum
-{
-  /* FILL ME */
-  LAST_SIGNAL
-};
-
 enum
 {
   PROP_0,
@@ -111,18 +98,12 @@ 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_cheb_limit_debug, "audiocheblimit", 0, "audiocheblimit element");
 
 GST_BOILERPLATE_FULL (GstAudioChebLimit,
-    gst_audio_cheb_limit, GstAudioFilter, GST_TYPE_AUDIO_FILTER, DEBUG_INIT);
+    gst_audio_cheb_limit, GstAudioFXBaseIIRFilter,
+    GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, DEBUG_INIT);
 
 static void gst_audio_cheb_limit_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec);
@@ -131,14 +112,6 @@ static void gst_audio_cheb_limit_get_property (GObject * object,
 
 static gboolean gst_audio_cheb_limit_setup (GstAudioFilter * filter,
     GstRingBufferSpec * format);
-static GstFlowReturn
-gst_audio_cheb_limit_transform_ip (GstBaseTransform * base, GstBuffer * buf);
-static gboolean gst_audio_cheb_limit_start (GstBaseTransform * base);
-
-static void process_64 (GstAudioChebLimit * filter,
-    gdouble * data, guint num_samples);
-static void process_32 (GstAudioChebLimit * filter,
-    gfloat * data, guint num_samples);
 
 enum
 {
@@ -172,80 +145,42 @@ static void
 gst_audio_cheb_limit_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_cheb_limit_dispose (GObject * object)
-{
-  GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (object);
-
-  if (filter->a) {
-    g_free (filter->a);
-    filter->a = NULL;
-  }
-
-  if (filter->b) {
-    g_free (filter->b);
-    filter->b = NULL;
-  }
-
-  if (filter->channels) {
-    GstAudioChebLimitChannelCtx *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);
+  gst_element_class_set_details_simple (element_class,
+      "Low pass & high pass filter",
+      "Filter/Effect/Audio",
+      "Chebyshev low pass and high pass filter",
+      "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
 }
 
 static void
 gst_audio_cheb_limit_class_init (GstAudioChebLimitClass * klass)
 {
-  GObjectClass *gobject_class;
-  GstBaseTransformClass *trans_class;
-  GstAudioFilterClass *filter_class;
-
-  gobject_class = (GObjectClass *) klass;
-  trans_class = (GstBaseTransformClass *) klass;
-  filter_class = (GstAudioFilterClass *) klass;
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
 
   gobject_class->set_property = gst_audio_cheb_limit_set_property;
   gobject_class->get_property = gst_audio_cheb_limit_get_property;
-  gobject_class->dispose = gst_audio_cheb_limit_dispose;
 
   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_LIMIT_MODE, MODE_LOW_PASS,
-          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+          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_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_CUTOFF,
       g_param_spec_float ("cutoff", "Cutoff", "Cut off frequency (Hz)", 0.0,
-          100000.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+          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));
+          200.0, 0.25,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
 
   /* FIXME: What to do about this upper boundary? With a cutoff frequency of
    * rate/4 32 poles are completely possible, with a cutoff frequency very low
@@ -253,12 +188,10 @@ gst_audio_cheb_limit_class_init (GstAudioChebLimitClass * klass)
   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 even number",
-          2, 32, 4, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
+          2, 32, 4,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
 
   filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_limit_setup);
-  trans_class->transform_ip =
-      GST_DEBUG_FUNCPTR (gst_audio_cheb_limit_transform_ip);
-  trans_class->start = GST_DEBUG_FUNCPTR (gst_audio_cheb_limit_start);
 }
 
 static void
@@ -270,12 +203,6 @@ gst_audio_cheb_limit_init (GstAudioChebLimit * filter,
   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;
 }
 
 static void
@@ -423,106 +350,34 @@ generate_biquad_coefficients (GstAudioChebLimit * filter,
   }
 }
 
-/* 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 (GstAudioChebLimit * 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) {
-    GstAudioChebLimitChannelCtx *ctx;
-    gint i;
-
-    for (i = 0; i < channels; i++) {
-      ctx = &filter->channels[i];
-      g_free (ctx->x);
-      g_free (ctx->y);
-    }
+  if (GST_AUDIO_FILTER (filter)->format.rate == 0) {
+    gdouble *a = g_new0 (gdouble, 1);
 
-    g_free (filter->channels);
-    filter->channels = NULL;
-  }
+    a[0] = 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, NULL, 0);
 
-  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 (GstAudioChebLimitChannelCtx, channels);
     GST_LOG_OBJECT (filter, "rate was not set yet");
     return;
   }
 
-  filter->have_coeffs = TRUE;
-
   if (filter->cutoff >= GST_AUDIO_FILTER (filter)->format.rate / 2.0) {
-    filter->num_a = 1;
-    filter->a = g_new0 (gdouble, 1);
-    filter->a[0] = (filter->mode == MODE_LOW_PASS) ? 1.0 : 0.0;
-    filter->num_b = 0;
-    filter->channels = g_new0 (GstAudioChebLimitChannelCtx, channels);
+    gdouble *a = g_new0 (gdouble, 1);
+
+    a[0] = (filter->mode == MODE_LOW_PASS) ? 1.0 : 0.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, NULL, 0);
     GST_LOG_OBJECT (filter, "cutoff was higher than nyquist frequency");
     return;
   } else if (filter->cutoff <= 0.0) {
-    filter->num_a = 1;
-    filter->a = g_new0 (gdouble, 1);
-    filter->a[0] = (filter->mode == MODE_LOW_PASS) ? 0.0 : 1.0;
-    filter->num_b = 0;
-    filter->channels = g_new0 (GstAudioChebLimitChannelCtx, channels);
+    gdouble *a = g_new0 (gdouble, 1);
+
+    a[0] = (filter->mode == MODE_LOW_PASS) ? 0.0 : 1.0;
+    gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
+        (filter), a, 1, NULL, 0);
     GST_LOG_OBJECT (filter, "cutoff is lower than zero");
     return;
   }
@@ -533,18 +388,8 @@ generate_coefficients (GstAudioChebLimit * filter)
     gdouble *a, *b;
     gint i, p;
 
-    filter->num_a = np + 1;
-    filter->a = a = g_new0 (gdouble, np + 3);
-    filter->num_b = np + 1;
-    filter->b = b = g_new0 (gdouble, np + 3);
-
-    filter->channels = g_new0 (GstAudioChebLimitChannelCtx, channels);
-    for (i = 0; i < channels; i++) {
-      GstAudioChebLimitChannelCtx *ctx = &filter->channels[i];
-
-      ctx->x = g_new0 (gdouble, np + 1);
-      ctx->y = g_new0 (gdouble, np + 1);
-    }
+    a = g_new0 (gdouble, np + 3);
+    b = g_new0 (gdouble, np + 3);
 
     /* Calculate transfer function coefficients */
     a[2] = 1.0;
@@ -587,15 +432,22 @@ generate_coefficients (GstAudioChebLimit * filter)
       gdouble gain;
 
       if (filter->mode == MODE_LOW_PASS)
-        gain = calculate_gain (a, b, np, np, 1.0, 0.0);
+        gain =
+            gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+            1.0, 0.0);
       else
-        gain = calculate_gain (a, b, np, np, -1.0, 0.0);
+        gain =
+            gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
+            -1.0, 0.0);
 
       for (i = 0; i <= np; i++) {
         a[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,
@@ -603,7 +455,8 @@ generate_coefficients (GstAudioChebLimit * filter)
         (filter->mode == MODE_LOW_PASS) ? "low-pass" : "high-pass",
         filter->type, filter->poles, filter->cutoff, filter->ripple);
     GST_LOG_OBJECT (filter, "%.2f dB gain @ 0 Hz",
-        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)));
 
 #ifndef GST_DISABLE_GST_DEBUG
     {
@@ -613,13 +466,14 @@ generate_coefficients (GstAudioChebLimit * filter)
       gdouble zr = cos (wc), zi = sin (wc);
 
       GST_LOG_OBJECT (filter, "%.2f dB gain @ %d Hz",
-          20.0 * log10 (calculate_gain (a, b, np, np, zr, zi)),
-          (int) filter->cutoff);
+          20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
+                  b, np + 1, zr, zi)), (int) filter->cutoff);
     }
 #endif
 
     GST_LOG_OBJECT (filter, "%.2f dB gain @ %d Hz",
-        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)),
         GST_AUDIO_FILTER (filter)->format.rate / 2);
   }
 }
@@ -632,34 +486,34 @@ gst_audio_cheb_limit_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case PROP_MODE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->mode = g_value_get_enum (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_TYPE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->type = g_value_get_int (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_CUTOFF:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->cutoff = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_RIPPLE:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->ripple = g_value_get_float (value);
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     case PROP_POLES:
-      GST_BASE_TRANSFORM_LOCK (filter);
+      GST_OBJECT_LOCK (filter);
       filter->poles = GST_ROUND_UP_2 (g_value_get_int (value));
       generate_coefficients (filter);
-      GST_BASE_TRANSFORM_UNLOCK (filter);
+      GST_OBJECT_UNLOCK (filter);
       break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -701,123 +555,8 @@ static gboolean
 gst_audio_cheb_limit_setup (GstAudioFilter * base, GstRingBufferSpec * format)
 {
   GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (base);
-  gboolean ret = TRUE;
-
-  if (format->width == 32)
-    filter->process = (GstAudioChebLimitProcessFunc)
-        process_32;
-  else if (format->width == 64)
-    filter->process = (GstAudioChebLimitProcessFunc)
-        process_64;
-  else
-    ret = FALSE;
-
-  filter->have_coeffs = FALSE;
-
-  return ret;
-}
-
-static inline gdouble
-process (GstAudioChebLimit * filter,
-    GstAudioChebLimitChannelCtx * 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 (GstAudioChebLimit * 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_cheb_limit_transform_ip (GstBaseTransform * base, GstBuffer * buf)
-{
-  GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (base);
-  guint num_samples =
-      GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8);
 
-  if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf)))
-    gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf));
+  generate_coefficients (filter);
 
-  if (gst_base_transform_is_passthrough (base))
-    return GST_FLOW_OK;
-
-  if (!filter->have_coeffs)
-    generate_coefficients (filter);
-
-  filter->process (filter, GST_BUFFER_DATA (buf), num_samples);
-
-  return GST_FLOW_OK;
-}
-
-
-static gboolean
-gst_audio_cheb_limit_start (GstBaseTransform * base)
-{
-  GstAudioChebLimit *filter = GST_AUDIO_CHEB_LIMIT (base);
-  gint channels = GST_AUDIO_FILTER (filter)->format.channels;
-  GstAudioChebLimitChannelCtx *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, format);
 }
index c2fe6c2..491f749 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
 #include <gst/audio/audio.h>
 #include <gst/audio/gstaudiofilter.h>
 
+#include "audiofxbaseiirfilter.h"
+
 G_BEGIN_DECLS
+
 #define GST_TYPE_AUDIO_CHEB_LIMIT            (gst_audio_cheb_limit_get_type())
 #define GST_AUDIO_CHEB_LIMIT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimit))
 #define GST_IS_AUDIO_CHEB_LIMIT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_CHEB_LIMIT))
 #define GST_AUDIO_CHEB_LIMIT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimitClass))
 #define GST_IS_AUDIO_CHEB_LIMIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_CHEB_LIMIT))
 #define GST_AUDIO_CHEB_LIMIT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_CHEB_LIMIT,GstAudioChebLimitClass))
+
 typedef struct _GstAudioChebLimit GstAudioChebLimit;
 typedef struct _GstAudioChebLimitClass GstAudioChebLimitClass;
 
-typedef void (*GstAudioChebLimitProcessFunc) (GstAudioChebLimit *, guint8 *, guint);
-
-typedef struct
-{
-  gdouble *x;
-  gint x_pos;
-  gdouble *y;
-  gint y_pos;
-} GstAudioChebLimitChannelCtx;
-
 struct _GstAudioChebLimit
 {
-  GstAudioFilter audiofilter;
+  GstAudioFXBaseIIRFilter parent;
 
   gint mode;
   gint type;
   gint poles;
   gfloat cutoff;
   gfloat ripple;
-
-  /* < private > */
-  GstAudioChebLimitProcessFunc process;
-
-  gboolean have_coeffs;
-  gdouble *a;
-  gint num_a;
-  gdouble *b;
-  gint num_b;
-  GstAudioChebLimitChannelCtx *channels;
 };
 
 struct _GstAudioChebLimitClass
 {
-  GstAudioFilterClass parent;
+  GstAudioFXBaseIIRFilterClass parent;
 };
 
 GType gst_audio_cheb_limit_get_type (void);
 
 G_END_DECLS
+
 #endif /* __GST_AUDIO_CHEB_LIMIT_H__ */
diff --git a/gst/audiofx/audiofxbaseiirfilter.c b/gst/audiofx/audiofxbaseiirfilter.c
new file mode 100644 (file)
index 0000000..29cb244
--- /dev/null
@@ -0,0 +1,396 @@
+/* 
+ * GStreamer
+ * 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
+ * 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 <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 "audiofxbaseiirfilter.h"
+
+#define GST_CAT_DEFAULT gst_audio_fx_base_iir_filter_debug
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
+
+#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_fx_base_iir_filter_debug, "audiobaseiirfilter", 0, "Audio IIR Filter Base Class");
+
+GST_BOILERPLATE_FULL (GstAudioFXBaseIIRFilter,
+    gst_audio_fx_base_iir_filter, GstAudioFilter, GST_TYPE_AUDIO_FILTER,
+    DEBUG_INIT);
+
+static gboolean gst_audio_fx_base_iir_filter_setup (GstAudioFilter * filter,
+    GstRingBufferSpec * format);
+static GstFlowReturn
+gst_audio_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf);
+static gboolean gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base);
+
+static void process_64 (GstAudioFXBaseIIRFilter * filter,
+    gdouble * data, guint num_samples);
+static void process_32 (GstAudioFXBaseIIRFilter * filter,
+    gfloat * data, guint num_samples);
+
+/* GObject vmethod implementations */
+
+static void
+gst_audio_fx_base_iir_filter_base_init (gpointer klass)
+{
+  GstCaps *caps;
+
+  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_fx_base_iir_filter_dispose (GObject * object)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (object);
+
+  if (filter->a) {
+    g_free (filter->a);
+    filter->a = NULL;
+  }
+
+  if (filter->b) {
+    g_free (filter->b);
+    filter->b = NULL;
+  }
+
+  if (filter->channels) {
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+    guint i;
+
+    for (i = 0; i < filter->nchannels; 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_fx_base_iir_filter_class_init (GstAudioFXBaseIIRFilterClass * klass)
+{
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstBaseTransformClass *trans_class = (GstBaseTransformClass *) klass;
+  GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
+
+  gobject_class->dispose = gst_audio_fx_base_iir_filter_dispose;
+
+  filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_setup);
+
+  trans_class->transform_ip =
+      GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_transform_ip);
+  trans_class->stop = GST_DEBUG_FUNCPTR (gst_audio_fx_base_iir_filter_stop);
+}
+
+static void
+gst_audio_fx_base_iir_filter_init (GstAudioFXBaseIIRFilter * filter,
+    GstAudioFXBaseIIRFilterClass * klass)
+{
+  gst_base_transform_set_in_place (GST_BASE_TRANSFORM (filter), TRUE);
+
+  filter->a = NULL;
+  filter->na = 0;
+  filter->b = NULL;
+  filter->nb = 0;
+  filter->channels = NULL;
+  filter->nchannels = 0;
+}
+
+/* Evaluate the transfer function that corresponds to the IIR
+ * coefficients at zr + zi*I and return the magnitude */
+gdouble
+gst_audio_fx_base_iir_filter_calculate_gain (gdouble * a, guint na, gdouble * b,
+    guint nb, 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 = na - 1; 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 = nb - 1; 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));
+}
+
+void
+gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter * filter,
+    gdouble * a, guint na, gdouble * b, guint nb)
+{
+  guint i;
+
+  g_return_if_fail (GST_IS_AUDIO_FX_BASE_IIR_FILTER (filter));
+
+  GST_BASE_TRANSFORM_LOCK (filter);
+
+  g_free (filter->a);
+  g_free (filter->b);
+
+  filter->a = filter->b = NULL;
+
+  if (filter->channels) {
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+    gboolean free = (na != filter->na || nb != filter->nb);
+
+    for (i = 0; i < filter->nchannels; i++) {
+      ctx = &filter->channels[i];
+
+      if (free)
+        g_free (ctx->x);
+      else
+        memset (ctx->x, 0, filter->na * sizeof (gdouble));
+
+      if (free)
+        g_free (ctx->y);
+      else
+        memset (ctx->y, 0, filter->nb * sizeof (gdouble));
+    }
+
+    g_free (filter->channels);
+    filter->channels = NULL;
+  }
+
+  filter->na = na;
+  filter->nb = nb;
+
+  filter->a = a;
+  filter->b = b;
+
+  if (filter->nchannels && !filter->channels) {
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+
+    filter->channels =
+        g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels);
+    for (i = 0; i < filter->nchannels; i++) {
+      ctx = &filter->channels[i];
+
+      ctx->x = g_new0 (gdouble, filter->na);
+      ctx->y = g_new0 (gdouble, filter->nb);
+    }
+  }
+
+  GST_BASE_TRANSFORM_UNLOCK (filter);
+}
+
+/* GstAudioFilter vmethod implementations */
+
+static gboolean
+gst_audio_fx_base_iir_filter_setup (GstAudioFilter * base,
+    GstRingBufferSpec * format)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
+  gboolean ret = TRUE;
+
+  if (format->width == 32)
+    filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
+        process_32;
+  else if (format->width == 64)
+    filter->process = (GstAudioFXBaseIIRFilterProcessFunc)
+        process_64;
+  else
+    ret = FALSE;
+
+  if (format->channels != filter->nchannels) {
+    guint i;
+    GstAudioFXBaseIIRFilterChannelCtx *ctx;
+
+    if (filter->channels) {
+
+      for (i = 0; i < filter->nchannels; i++) {
+        ctx = &filter->channels[i];
+
+        g_free (ctx->x);
+        g_free (ctx->y);
+      }
+
+      g_free (filter->channels);
+      filter->channels = NULL;
+    }
+
+    filter->nchannels = format->channels;
+
+    filter->channels =
+        g_new0 (GstAudioFXBaseIIRFilterChannelCtx, filter->nchannels);
+    for (i = 0; i < filter->nchannels; i++) {
+      ctx = &filter->channels[i];
+
+      ctx->x = g_new0 (gdouble, filter->na);
+      ctx->y = g_new0 (gdouble, filter->nb);
+    }
+  }
+
+  return ret;
+}
+
+static inline gdouble
+process (GstAudioFXBaseIIRFilter * filter,
+    GstAudioFXBaseIIRFilterChannelCtx * ctx, gdouble x0)
+{
+  gdouble val = filter->a[0] * x0;
+  gint i, j;
+
+  for (i = 1, j = ctx->x_pos; i < filter->na; i++) {
+    val += filter->a[i] * ctx->x[j];
+    j--;
+    if (j < 0)
+      j = filter->na - 1;
+  }
+
+  for (i = 1, j = ctx->y_pos; i < filter->nb; i++) {
+    val += filter->b[i] * ctx->y[j];
+    j--;
+    if (j < 0)
+      j = filter->nb - 1;
+  }
+
+  if (ctx->x) {
+    ctx->x_pos++;
+    if (ctx->x_pos >= filter->na)
+      ctx->x_pos = 0;
+    ctx->x[ctx->x_pos] = x0;
+  }
+  if (ctx->y) {
+    ctx->y_pos++;
+    if (ctx->y_pos >= filter->nb)
+      ctx->y_pos = 0;
+
+    ctx->y[ctx->y_pos] = val;
+  }
+
+  return val;
+}
+
+#define DEFINE_PROCESS_FUNC(width,ctype) \
+static void \
+process_##width (GstAudioFXBaseIIRFilter * 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_fx_base_iir_filter_transform_ip (GstBaseTransform * base,
+    GstBuffer * buf)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
+  guint num_samples =
+      GST_BUFFER_SIZE (buf) / (GST_AUDIO_FILTER (filter)->format.width / 8);
+
+  if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buf)))
+    gst_object_sync_values (G_OBJECT (filter), GST_BUFFER_TIMESTAMP (buf));
+
+  if (gst_base_transform_is_passthrough (base))
+    return GST_FLOW_OK;
+
+  g_return_val_if_fail (filter->a != NULL, GST_FLOW_ERROR);
+
+  filter->process (filter, GST_BUFFER_DATA (buf), num_samples);
+
+  return GST_FLOW_OK;
+}
+
+
+static gboolean
+gst_audio_fx_base_iir_filter_stop (GstBaseTransform * base)
+{
+  GstAudioFXBaseIIRFilter *filter = GST_AUDIO_FX_BASE_IIR_FILTER (base);
+  guint channels = GST_AUDIO_FILTER (filter)->format.channels;
+  GstAudioFXBaseIIRFilterChannelCtx *ctx;
+  guint 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];
+      g_free (ctx->x);
+      g_free (ctx->y);
+    }
+    g_free (filter->channels);
+  }
+  filter->channels = NULL;
+
+  return TRUE;
+}
diff --git a/gst/audiofx/audiofxbaseiirfilter.h b/gst/audiofx/audiofxbaseiirfilter.h
new file mode 100644 (file)
index 0000000..0534343
--- /dev/null
@@ -0,0 +1,77 @@
+/* 
+ * GStreamer
+ * 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
+ * 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_AUDIO_FX_BASE_IIR_FILTER_H__
+#define __GST_AUDIO_FX_BASE_IIR_FILTER_H__
+
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+#include <gst/audio/audio.h>
+#include <gst/audio/gstaudiofilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_AUDIO_FX_BASE_IIR_FILTER            (gst_audio_fx_base_iir_filter_get_type())
+#define GST_AUDIO_FX_BASE_IIR_FILTER(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilter))
+#define GST_IS_AUDIO_FX_BASE_IIR_FILTER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_FX_BASE_IIR_FILTER))
+#define GST_AUDIO_FX_BASE_IIR_FILTER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilterClass))
+#define GST_IS_AUDIO_FX_BASE_IIR_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER))
+#define GST_AUDIO_FX_BASE_IIR_FILTER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_AUDIO_FX_BASE_IIR_FILTER,GstAudioFXBaseIIRFilterClass))
+typedef struct _GstAudioFXBaseIIRFilter GstAudioFXBaseIIRFilter;
+typedef struct _GstAudioFXBaseIIRFilterClass GstAudioFXBaseIIRFilterClass;
+
+typedef void (*GstAudioFXBaseIIRFilterProcessFunc) (GstAudioFXBaseIIRFilter *, guint8 *, guint);
+
+typedef struct
+{
+  gdouble *x;
+  gint x_pos;
+  gdouble *y;
+  gint y_pos;
+} GstAudioFXBaseIIRFilterChannelCtx;
+
+struct _GstAudioFXBaseIIRFilter
+{
+  GstAudioFilter audiofilter;
+
+  /* < private > */
+  GstAudioFXBaseIIRFilterProcessFunc process;
+
+  gboolean have_coeffs;
+  gdouble *a;
+  guint na;
+  gdouble *b;
+  guint nb;
+  GstAudioFXBaseIIRFilterChannelCtx *channels;
+  guint nchannels;
+};
+
+struct _GstAudioFXBaseIIRFilterClass
+{
+  GstAudioFilterClass parent;
+};
+
+GType gst_audio_fx_base_iir_filter_get_type (void);
+void gst_audio_fx_base_iir_filter_set_coefficients (GstAudioFXBaseIIRFilter *filter, gdouble *a, guint na, gdouble *b, guint nb);
+gdouble gst_audio_fx_base_iir_filter_calculate_gain (gdouble *a, guint na, gdouble *b, guint nb, gdouble zr, gdouble zi);
+
+G_END_DECLS
+
+#endif /* __GST_AUDIO_FX_BASE_IIR_FILTER_H__ */