summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--gst/filter/Makefile.am10
-rw-r--r--gst/filter/gstfilter.c120
-rw-r--r--gst/filter/gstfilter.h34
-rw-r--r--gst/filter/gstiir.c259
-rw-r--r--gst/filter/iir.c302
-rw-r--r--gst/filter/iir.h37
6 files changed, 762 insertions, 0 deletions
diff --git a/gst/filter/Makefile.am b/gst/filter/Makefile.am
new file mode 100644
index 00000000..4204955f
--- /dev/null
+++ b/gst/filter/Makefile.am
@@ -0,0 +1,10 @@
+plugindir = $(libdir)/gst
+
+plugin_LTLIBRARIES = libgstfilter.la
+
+libgstfilter_la_SOURCES = gstfilter.c gstiir.c iir.c
+libgstfilter_la_CFLAGS = $(GST_CFLAGS)
+libgstfilter_la_LIBADD =
+libgstfilter_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+
+noinst_HEADERS = gstfilter.h iir.h
diff --git a/gst/filter/gstfilter.c b/gst/filter/gstfilter.c
new file mode 100644
index 00000000..2ed416c1
--- /dev/null
+++ b/gst/filter/gstfilter.c
@@ -0,0 +1,120 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstfilter.c: element for filter plug-ins
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "gstfilter.h"
+
+
+struct _elements_entry {
+ gchar *name;
+ GType (*type) (void);
+ GstElementDetails *details;
+ gboolean (*factoryinit) (GstElementFactory *factory);
+};
+
+static struct _elements_entry _elements[] = {
+ { "iir", gst_iir_get_type, &gst_iir_details, NULL },
+ { NULL, 0 },
+};
+
+GstPadTemplate*
+gst_filter_src_factory (void)
+{
+ static GstPadTemplate *templ = NULL;
+ if (!templ) {
+ templ = GST_PAD_TEMPLATE_NEW (
+ "src",
+ GST_PAD_SRC,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "filter_src",
+ "audio/raw",
+ "format", GST_PROPS_STRING ("float"),
+ "rate", GST_PROPS_INT_RANGE (1, G_MAXINT),
+ "layout", GST_PROPS_STRING ("gfloat"),
+ "intercept", GST_PROPS_FLOAT(0.0),
+ "slope", GST_PROPS_FLOAT(1.0),
+ "channels", GST_PROPS_INT (1)
+ )
+ );
+ }
+ return templ;
+}
+
+GstPadTemplate*
+gst_filter_sink_factory (void)
+{
+ static GstPadTemplate *templ = NULL;
+ if (!templ) {
+ templ = GST_PAD_TEMPLATE_NEW (
+ "sink",
+ GST_PAD_SINK,
+ GST_PAD_ALWAYS,
+ GST_CAPS_NEW (
+ "filter_src",
+ "audio/raw",
+ "format", GST_PROPS_STRING ("float"),
+ "rate", GST_PROPS_INT_RANGE (1, G_MAXINT),
+ "layout", GST_PROPS_STRING ("gfloat"),
+ "intercept", GST_PROPS_FLOAT(0.0),
+ "slope", GST_PROPS_FLOAT(1.0),
+ "channels", GST_PROPS_INT (1)
+ )
+ );
+ }
+ return templ;
+}
+
+static gboolean
+plugin_init (GModule * module, GstPlugin * plugin)
+{
+ GstElementFactory *factory;
+ gint i = 0;
+
+ while (_elements[i].name) {
+ factory = gst_element_factory_new (_elements[i].name,
+ (_elements[i].type) (),
+ _elements[i].details);
+
+ if (!factory) {
+ g_warning ("gst_filter_new failed for `%s'",
+ _elements[i].name);
+ continue;
+ }
+ gst_element_factory_add_pad_template (factory, gst_filter_src_factory ());
+ gst_element_factory_add_pad_template (factory, gst_filter_sink_factory ());
+
+ gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (factory));
+ if (_elements[i].factoryinit) {
+ _elements[i].factoryinit (factory);
+ }
+ i++;
+ }
+
+ return TRUE;
+}
+
+GstPluginDesc plugin_desc = {
+ GST_VERSION_MAJOR,
+ GST_VERSION_MINOR,
+ "filter",
+ plugin_init
+};
diff --git a/gst/filter/gstfilter.h b/gst/filter/gstfilter.h
new file mode 100644
index 00000000..a806bb4d
--- /dev/null
+++ b/gst/filter/gstfilter.h
@@ -0,0 +1,34 @@
+/* GStreamer
+ * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
+ * 2000 Wim Taymans <wtay@chello.be>
+ *
+ * gstfilter.h: element for filter plug-ins
+ *
+ * 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_FILTER_H__
+#define __GST_FILTER_H__
+
+#include <gst/gst.h>
+GType gst_iir_get_type (void);
+extern GstElementDetails gst_iir_details;
+
+extern GstPadTemplate *gst_filter_sink_factory ();
+extern GstPadTemplate *gst_filter_src_factory ();
+
+#endif /* __GST_FILTER_H__ */
diff --git a/gst/filter/gstiir.c b/gst/filter/gstiir.c
new file mode 100644
index 00000000..811b6a12
--- /dev/null
+++ b/gst/filter/gstiir.c
@@ -0,0 +1,259 @@
+/* -*- c-basic-offset: 2 -*-
+ * GStreamer
+ * Copyright (C) 1999-2001 Erik Walthinsen <omega@cse.ogi.edu>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gst/gst.h>
+#include "gstfilter.h"
+#include "iir.h"
+
+GstElementDetails gst_iir_details = {
+ "IIR",
+ "Filter/Audio/Effect",
+ "IIR filter based on vorbis code",
+ VERSION,
+ "Monty <monty@xiph.org>, "\
+ "Thomas <thomas@apestaart.org>",
+ "(C) 2001",
+};
+
+enum {
+ /* FILL ME */
+ LAST_SIGNAL
+};
+
+enum {
+ ARG_0,
+ ARG_A,
+ ARG_B,
+ ARG_GAIN,
+ ARG_STAGES,
+};
+
+#define GST_TYPE_IIR \
+ (gst_iir_get_type())
+#define GST_IIR(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_IIR,GstIIR))
+#define GST_IIR_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ULAW,GstIIR))
+#define GST_IS_IIR(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_IIR))
+#define GST_IS_IIR_CLASS(obj) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_IIR))
+
+typedef struct _GstIIR GstIIR;
+typedef struct _GstIIRClass GstIIRClass;
+
+struct _GstIIR
+{
+ GstElement element;
+
+ GstPad *sinkpad, *srcpad;
+
+ double A, B;
+ double gain;
+ int stages;
+ IIR_state *state;
+};
+
+struct _GstIIRClass
+{
+ GstElementClass parent_class;
+};
+
+static void gst_iir_class_init (GstIIRClass * klass);
+static void gst_iir_init (GstIIR * filter);
+
+static void gst_iir_set_property (GObject * object, guint prop_id,
+ const GValue * value,
+ GParamSpec * pspec);
+static void gst_iir_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec);
+
+static void gst_iir_chain (GstPad * pad, GstBuffer * buf);
+static GstPadConnectReturn
+ gst_iir_sink_connect (GstPad * pad, GstCaps * caps);
+
+static GstElementClass *parent_class = NULL;
+/*static guint gst_iir_signals[LAST_SIGNAL] = { 0 }; */
+
+GType gst_iir_get_type (void)
+{
+ static GType iir_type = 0;
+
+ if (!iir_type) {
+ static const GTypeInfo iir_info = {
+ sizeof (GstIIRClass), NULL, NULL,
+ (GClassInitFunc) gst_iir_class_init, NULL, NULL,
+ sizeof (GstIIR), 0,
+ (GInstanceInitFunc) gst_iir_init,
+ };
+
+ iir_type = g_type_register_static (GST_TYPE_ELEMENT, "GstIIR",
+ &iir_info, 0);
+ }
+ return iir_type;
+}
+
+static void
+gst_iir_class_init (GstIIRClass * klass)
+{
+ GObjectClass *gobject_class;
+ GstElementClass *gstelement_class;
+
+ gobject_class = (GObjectClass *) klass;
+ gstelement_class = (GstElementClass *) klass;
+
+ parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
+
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_A,
+ g_param_spec_double ("A", "A", "A filter coefficient",
+ -G_MAXDOUBLE, G_MAXDOUBLE,
+ 0, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_B,
+ g_param_spec_double ("B", "B", "B filter coefficient",
+ -G_MAXDOUBLE, G_MAXDOUBLE,
+ 0, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_GAIN,
+ g_param_spec_double ("gain", "Gain", "Filter gain",
+ -G_MAXDOUBLE, G_MAXDOUBLE,
+ 0, G_PARAM_READWRITE));
+ g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_STAGES,
+ g_param_spec_int ("stages", "Stages", "Number of filter stages",
+ 1, G_MAXINT,
+ 0, G_PARAM_READWRITE));
+
+ gobject_class->set_property = gst_iir_set_property;
+ gobject_class->get_property = gst_iir_get_property;
+}
+
+static void
+gst_iir_init (GstIIR * filter)
+{
+ filter->sinkpad = gst_pad_new_from_template (gst_filter_sink_factory (), "sink");
+ gst_pad_set_chain_function (filter->sinkpad, gst_iir_chain);
+ gst_pad_set_connect_function (filter->sinkpad, gst_iir_sink_connect);
+ gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
+
+ filter->srcpad = gst_pad_new_from_template (gst_filter_src_factory (), "src");
+ gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
+
+ filter->A = 0.0;
+ filter->B = 0.0;
+ filter->gain = 1.0; /* unity gain as default */
+ filter->stages = 1;
+ filter->state = NULL;
+}
+
+static GstPadConnectReturn
+gst_iir_sink_connect (GstPad * pad, GstCaps * caps)
+{
+ GstIIR *filter;
+
+ filter = GST_IIR (gst_pad_get_parent (pad));
+
+ if (!GST_CAPS_IS_FIXED (caps))
+ return GST_PAD_CONNECT_DELAYED;
+
+ if (gst_pad_try_set_caps (filter->srcpad, caps)) {
+ /* connection works, so init the filter */
+ /* FIXME: remember to free it */
+ filter->state = (IIR_state *) g_malloc (sizeof (IIR_state));
+ IIR_init (filter->state, filter->stages,
+ filter->gain, &(filter->A), &(filter->B));
+ return GST_PAD_CONNECT_OK;
+ }
+
+ return GST_PAD_CONNECT_REFUSED;
+}
+
+static void
+gst_iir_chain (GstPad * pad, GstBuffer * buf)
+{
+ GstIIR *filter;
+ gfloat *src;
+ int i;
+
+ filter = GST_IIR (gst_pad_get_parent (pad));
+
+ src = (gfloat *) GST_BUFFER_DATA (buf);
+
+ /* do an in-place edit */
+ for (i = 0; i < GST_BUFFER_SIZE (buf) / sizeof (gfloat); ++i)
+ *(src + i) = (gfloat) IIR_filter (filter->state, (double) *(src + i));
+
+ gst_pad_push (filter->srcpad, buf);
+}
+
+static void
+gst_iir_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+ GstIIR *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_IIR (object));
+
+ filter = GST_IIR (object);
+
+ switch (prop_id) {
+ case ARG_A:
+ filter->A = g_value_get_double (value);
+ break;
+ case ARG_B:
+ filter->B = g_value_get_double (value);
+ break;
+ case ARG_GAIN:
+ filter->gain = g_value_get_double (value);
+ break;
+ case ARG_STAGES:
+ filter->stages = g_value_get_int (value);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gst_iir_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec)
+{
+ GstIIR *filter;
+
+ /* it's not null if we got it, but it might not be ours */
+ g_return_if_fail (GST_IS_IIR (object));
+
+ filter = GST_IIR (object);
+
+ switch (prop_id) {
+ case ARG_A:
+ g_value_set_double (value, filter->A);
+ break;
+ case ARG_B:
+ g_value_set_double (value, filter->B);
+ break;
+ case ARG_GAIN:
+ g_value_set_double (value, filter->gain);
+ break;
+ case ARG_STAGES:
+ g_value_set_int (value, filter->stages);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
diff --git a/gst/filter/iir.c b/gst/filter/iir.c
new file mode 100644
index 00000000..1ef31540
--- /dev/null
+++ b/gst/filter/iir.c
@@ -0,0 +1,302 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
+ * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: Direct Form I, II IIR filters, plus some specializations
+ last mod: $Id$
+
+ ********************************************************************/
+
+/* LPC is actually a degenerate case of form I/II filters, but we need
+ both */
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "iir.h"
+
+void IIR_init(IIR_state *s,int stages,double gain, double *A, double *B){
+ memset(s,0,sizeof(IIR_state));
+ s->stages=stages;
+ s->gain=gain;
+ s->coeff_A=malloc(stages*sizeof(double));
+ s->coeff_B=malloc((stages+1)*sizeof(double));
+ s->z_A=calloc(stages*2,sizeof(double));
+ s->z_B=calloc(stages*2,sizeof(double));
+
+ memcpy(s->coeff_A,A,stages*sizeof(double));
+ memcpy(s->coeff_B,B,(stages+1)*sizeof(double));
+}
+
+void IIR_clear(IIR_state *s){
+ if(s){
+ free(s->coeff_A);
+ free(s->coeff_B);
+ free(s->z_A);
+ free(s->z_B);
+ memset(s,0,sizeof(IIR_state));
+ }
+}
+
+double IIR_filter(IIR_state *s,double in){
+ int stages=s->stages,i;
+ double newA;
+ double newB=0;
+ double *zA=s->z_A+s->ring;
+
+ newA=in/=s->gain;
+ for(i=0;i<stages;i++){
+ newA+= s->coeff_A[i] * zA[i];
+ newB+= s->coeff_B[i] * zA[i];
+ }
+ newB+=newA*s->coeff_B[stages];
+
+ zA[0]=zA[stages]=newA;
+ if(++s->ring>=stages)s->ring=0;
+
+ return(newB);
+}
+
+/* this assumes the symmetrical structure of the feed-forward stage of
+ a Chebyshev bandpass to save multiplies */
+double IIR_filter_ChebBand(IIR_state *s,double in){
+ int stages=s->stages,i;
+ double newA;
+ double newB=0;
+ double *zA=s->z_A+s->ring;
+
+ newA=in/=s->gain;
+
+ newA+= s->coeff_A[0] * zA[0];
+ for(i=1;i<(stages>>1);i++){
+ newA+= s->coeff_A[i] * zA[i];
+ newB+= s->coeff_B[i] * (zA[i]-zA[stages-i]);
+ }
+ newB+= s->coeff_B[i] * zA[i];
+ for(;i<stages;i++)
+ newA+= s->coeff_A[i] * zA[i];
+
+ newB+= newA-zA[0];
+
+ zA[0]=zA[stages]=newA;
+ if(++s->ring>=stages)s->ring=0;
+
+ return(newB);
+}
+
+#ifdef _V_SELFTEST
+
+/* z^-stage, z^-stage+1... */
+static double cheb_bandpass_B[]={-1.,0.,5.,0.,-10.,0.,10.,0.,-5.,0.,1};
+static double cheb_bandpass_A[]={-0.6665900311,
+ 1.0070146601,
+ -3.1262875409,
+ 3.5017171569,
+ -6.2779211945,
+ 5.2966481740,
+ -6.7570216587,
+ 4.0760335768,
+ -3.9134284363,
+ 1.3997338886};
+
+static double data[128]={
+ 0.0426331,
+ 0.0384521,
+ 0.0345764,
+ 0.0346069,
+ 0.0314636,
+ 0.0310059,
+ 0.0318604,
+ 0.0336304,
+ 0.036438,
+ 0.0348511,
+ 0.0354919,
+ 0.0343628,
+ 0.0325623,
+ 0.0318909,
+ 0.0263367,
+ 0.0225525,
+ 0.0195618,
+ 0.0160828,
+ 0.0168762,
+ 0.0145569,
+ 0.0126343,
+ 0.0127258,
+ 0.00820923,
+ 0.00787354,
+ 0.00558472,
+ 0.00204468,
+ 3.05176e-05,
+ -0.00357056,
+ -0.00570679,
+ -0.00991821,
+ -0.0101013,
+ -0.00881958,
+ -0.0108948,
+ -0.0110168,
+ -0.0119324,
+ -0.0161438,
+ -0.0194702,
+ -0.0229187,
+ -0.0260315,
+ -0.0282288,
+ -0.0306091,
+ -0.0330505,
+ -0.0364685,
+ -0.0385742,
+ -0.0428772,
+ -0.043457,
+ -0.0425415,
+ -0.0462341,
+ -0.0467529,
+ -0.0489807,
+ -0.0520325,
+ -0.0558167,
+ -0.0596924,
+ -0.0591431,
+ -0.0612793,
+ -0.0618591,
+ -0.0615845,
+ -0.0634155,
+ -0.0639648,
+ -0.0683594,
+ -0.0718079,
+ -0.0729675,
+ -0.0791931,
+ -0.0860901,
+ -0.0885315,
+ -0.088623,
+ -0.089386,
+ -0.0899353,
+ -0.0886841,
+ -0.0910645,
+ -0.0948181,
+ -0.0919495,
+ -0.0891418,
+ -0.0916443,
+ -0.096344,
+ -0.100464,
+ -0.105499,
+ -0.108612,
+ -0.112213,
+ -0.117676,
+ -0.120911,
+ -0.124329,
+ -0.122162,
+ -0.120605,
+ -0.12326,
+ -0.12619,
+ -0.128998,
+ -0.13205,
+ -0.134247,
+ -0.137939,
+ -0.143555,
+ -0.14389,
+ -0.14859,
+ -0.153717,
+ -0.159851,
+ -0.164551,
+ -0.162811,
+ -0.164276,
+ -0.156952,
+ -0.140564,
+ -0.123291,
+ -0.10321,
+ -0.0827637,
+ -0.0652466,
+ -0.053772,
+ -0.0509949,
+ -0.0577698,
+ -0.0818176,
+ -0.114929,
+ -0.148895,
+ -0.181122,
+ -0.200714,
+ -0.21048,
+ -0.203644,
+ -0.179413,
+ -0.145325,
+ -0.104492,
+ -0.0658264,
+ -0.0332031,
+ -0.0106201,
+ -0.00363159,
+ -0.00909424,
+ -0.0244141,
+ -0.0422058,
+ -0.0537415,
+ -0.0610046,
+ -0.0609741,
+ -0.0547791};
+
+/* comparison test code from http://www-users.cs.york.ac.uk/~fisher/mkfilter/
+ (the above page kicks ass, BTW)*/
+
+#define NZEROS 10
+#define NPOLES 10
+#define GAIN 4.599477515e+02
+
+static float xv[NZEROS+1], yv[NPOLES+1];
+
+static double filterloop(double next){
+ xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5];
+ xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8]; xv[8] = xv[9]; xv[9] = xv[10];
+ xv[10] = next / GAIN;
+ yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5];
+ yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8]; yv[8] = yv[9]; yv[9] = yv[10];
+ yv[10] = (xv[10] - xv[0]) + 5 * (xv[2] - xv[8]) + 10 * (xv[6] - xv[4])
+ + ( -0.6665900311 * yv[0]) + ( 1.0070146601 * yv[1])
+ + ( -3.1262875409 * yv[2]) + ( 3.5017171569 * yv[3])
+ + ( -6.2779211945 * yv[4]) + ( 5.2966481740 * yv[5])
+ + ( -6.7570216587 * yv[6]) + ( 4.0760335768 * yv[7])
+ + ( -3.9134284363 * yv[8]) + ( 1.3997338886 * yv[9]);
+ return(yv[10]);
+}
+
+#include <stdio.h>
+int main(){
+
+ /* run the pregenerated Chebyshev filter, then our own distillation
+ through the generic and specialized code */
+ double *work=malloc(128*sizeof(double));
+ IIR_state iir;
+ int i;
+
+ for(i=0;i<128;i++)work[i]=filterloop(data[i]);
+ {
+ FILE *out=fopen("IIR_ref.m","w");
+ for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
+ fclose(out);
+ }
+
+ IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
+ for(i=0;i<128;i++)work[i]=IIR_filter(&iir,data[i]);
+ {
+ FILE *out=fopen("IIR_gen.m","w");
+ for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
+ fclose(out);
+ }
+ IIR_clear(&iir);
+
+ IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
+ for(i=0;i<128;i++)work[i]=IIR_filter_ChebBand(&iir,data[i]);
+ {
+ FILE *out=fopen("IIR_cheb.m","w");
+ for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
+ fclose(out);
+ }
+ IIR_clear(&iir);
+
+ return(0);
+}
+
+#endif
diff --git a/gst/filter/iir.h b/gst/filter/iir.h
new file mode 100644
index 00000000..241cc1d2
--- /dev/null
+++ b/gst/filter/iir.h
@@ -0,0 +1,37 @@
+/********************************************************************
+ * *
+ * THIS FILE IS PART OF THE Ogg Vorbis SOFTWARE CODEC SOURCE CODE. *
+ * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
+ * THE GNU PUBLIC LICENSE 2, WHICH IS INCLUDED WITH THIS SOURCE. *
+ * PLEASE READ THESE TERMS DISTRIBUTING. *
+ * *
+ * THE OggSQUISH SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
+ * by Monty <monty@xiph.org> and The XIPHOPHORUS Company *
+ * http://www.xiph.org/ *
+ * *
+ ********************************************************************
+
+ function: Direct Form I, II IIR filters, plus some specializations
+ last mod: $Id$
+
+ ********************************************************************/
+
+#ifndef _V_IIR_H_
+#define _V_IIR_H_
+
+typedef struct {
+ int stages;
+ double *coeff_A;
+ double *coeff_B;
+ double *z_A;
+ double *z_B;
+ int ring;
+ double gain;
+} IIR_state;
+
+void IIR_init(IIR_state *s,int stages,double gain, double *A, double *B);
+void IIR_clear(IIR_state *s);
+double IIR_filter(IIR_state *s,double in);
+double IIR_filter_ChebBand(IIR_state *s,double in);
+
+#endif