diff options
-rw-r--r-- | gst/filter/Makefile.am | 10 | ||||
-rw-r--r-- | gst/filter/gstfilter.c | 120 | ||||
-rw-r--r-- | gst/filter/gstfilter.h | 34 | ||||
-rw-r--r-- | gst/filter/gstiir.c | 259 | ||||
-rw-r--r-- | gst/filter/iir.c | 302 | ||||
-rw-r--r-- | gst/filter/iir.h | 37 |
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 |