gst_plugins_good/gst/audiofx/audiochebband.c
changeset 27 d43ce56a1534
parent 23 29ecd5cb86b3
child 31 aec498aab1d3
equal deleted inserted replaced
23:29ecd5cb86b3 27:d43ce56a1534
     1 /* 
       
     2  * GStreamer
       
     3  * Copyright (C) 2007-2009 Sebastian Dröge <sebastian.droege@collabora.co.uk>
       
     4  *
       
     5  * This library is free software; you can redistribute it and/or
       
     6  * modify it under the terms of the GNU Library General Public
       
     7  * License as published by the Free Software Foundation; either
       
     8  * version 2 of the License, or (at your option) any later version.
       
     9  *
       
    10  * This library is distributed in the hope that it will be useful,
       
    11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    13  * Library General Public License for more details.
       
    14  *
       
    15  * You should have received a copy of the GNU Library General Public
       
    16  * License along with this library; if not, write to the
       
    17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    18  * Boston, MA 02111-1307, USA.
       
    19  */
       
    20 
       
    21 /* 
       
    22  * Chebyshev type 1 filter design based on
       
    23  * "The Scientist and Engineer's Guide to DSP", Chapter 20.
       
    24  * http://www.dspguide.com/
       
    25  *
       
    26  * For type 2 and Chebyshev filters in general read
       
    27  * http://en.wikipedia.org/wiki/Chebyshev_filter
       
    28  *
       
    29  * Transformation from lowpass to bandpass/bandreject:
       
    30  * http://docs.dewresearch.com/DspHelp/html/IDH_LinearSystems_LowpassToBandPassZ.htm
       
    31  * http://docs.dewresearch.com/DspHelp/html/IDH_LinearSystems_LowpassToBandStopZ.htm
       
    32  * 
       
    33  */
       
    34 
       
    35 /**
       
    36  * SECTION:element-audiochebband
       
    37  *
       
    38  * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency
       
    39  * band. The number of poles and the ripple parameter control the rolloff.
       
    40  *
       
    41  * This element has the advantage over the windowed sinc bandpass and bandreject filter that it is
       
    42  * much faster and produces almost as good results. It's only disadvantages are the highly
       
    43  * non-linear phase and the slower rolloff compared to a windowed sinc filter with a large kernel.
       
    44  *
       
    45  * For type 1 the ripple parameter specifies how much ripple in dB is allowed in the passband, i.e.
       
    46  * some frequencies in the passband will be amplified by that value. A higher ripple value will allow
       
    47  * a faster rolloff.
       
    48  *
       
    49  * For type 2 the ripple parameter specifies the stopband attenuation. In the stopband the gain will
       
    50  * be at most this value. A lower ripple value will allow a faster rolloff.
       
    51  *
       
    52  * As a special case, a Chebyshev type 1 filter with no ripple is a Butterworth filter.
       
    53  *
       
    54  * <note>
       
    55  * Be warned that a too large number of poles can produce noise. The most poles are possible with
       
    56  * a cutoff frequency at a quarter of the sampling rate.
       
    57  * </note>
       
    58  *
       
    59  * <refsect2>
       
    60  * <title>Example launch line</title>
       
    61  * |[
       
    62  * gst-launch audiotestsrc freq=1500 ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequenc=6000 poles=4 ! audioconvert ! alsasink
       
    63  * gst-launch filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiochebband mode=band-reject lower-frequency=1000 upper-frequency=4000 ripple=0.2 ! audioconvert ! alsasink
       
    64  * gst-launch audiotestsrc wave=white-noise ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequency=4000 type=2 ! audioconvert ! alsasink
       
    65  * ]|
       
    66  * </refsect2>
       
    67  */
       
    68 
       
    69 #ifdef HAVE_CONFIG_H
       
    70 #include "config.h"
       
    71 #endif
       
    72 
       
    73 #include <gst/gst.h>
       
    74 #include <gst/base/gstbasetransform.h>
       
    75 #include <gst/audio/audio.h>
       
    76 #include <gst/audio/gstaudiofilter.h>
       
    77 #include <gst/controller/gstcontroller.h>
       
    78 
       
    79 #include <math.h>
       
    80 
       
    81 #include "math_compat.h"
       
    82 
       
    83 #include "audiochebband.h"
       
    84 
       
    85 #define GST_CAT_DEFAULT gst_audio_cheb_band_debug
       
    86 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
       
    87 
       
    88 enum
       
    89 {
       
    90   PROP_0,
       
    91   PROP_MODE,
       
    92   PROP_TYPE,
       
    93   PROP_LOWER_FREQUENCY,
       
    94   PROP_UPPER_FREQUENCY,
       
    95   PROP_RIPPLE,
       
    96   PROP_POLES
       
    97 };
       
    98 
       
    99 #define DEBUG_INIT(bla) \
       
   100   GST_DEBUG_CATEGORY_INIT (gst_audio_cheb_band_debug, "audiochebband", 0, "audiochebband element");
       
   101 
       
   102 GST_BOILERPLATE_FULL (GstAudioChebBand, gst_audio_cheb_band,
       
   103     GstAudioFXBaseIIRFilter, GST_TYPE_AUDIO_FX_BASE_IIR_FILTER, DEBUG_INIT);
       
   104 
       
   105 static void gst_audio_cheb_band_set_property (GObject * object,
       
   106     guint prop_id, const GValue * value, GParamSpec * pspec);
       
   107 static void gst_audio_cheb_band_get_property (GObject * object,
       
   108     guint prop_id, GValue * value, GParamSpec * pspec);
       
   109 static void gst_audio_cheb_band_finalize (GObject * object);
       
   110 
       
   111 static gboolean gst_audio_cheb_band_setup (GstAudioFilter * filter,
       
   112     GstRingBufferSpec * format);
       
   113 
       
   114 enum
       
   115 {
       
   116   MODE_BAND_PASS = 0,
       
   117   MODE_BAND_REJECT
       
   118 };
       
   119 
       
   120 #define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE (gst_audio_cheb_band_mode_get_type ())
       
   121 static GType
       
   122 gst_audio_cheb_band_mode_get_type (void)
       
   123 {
       
   124   static GType gtype = 0;
       
   125 
       
   126   if (gtype == 0) {
       
   127     static const GEnumValue values[] = {
       
   128       {MODE_BAND_PASS, "Band pass (default)",
       
   129           "band-pass"},
       
   130       {MODE_BAND_REJECT, "Band reject",
       
   131           "band-reject"},
       
   132       {0, NULL, NULL}
       
   133     };
       
   134 
       
   135     gtype = g_enum_register_static ("GstAudioChebBandMode", values);
       
   136   }
       
   137   return gtype;
       
   138 }
       
   139 
       
   140 /* GObject vmethod implementations */
       
   141 
       
   142 static void
       
   143 gst_audio_cheb_band_base_init (gpointer klass)
       
   144 {
       
   145   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
       
   146 
       
   147   gst_element_class_set_details_simple (element_class,
       
   148       "Band pass & band reject filter", "Filter/Effect/Audio",
       
   149       "Chebyshev band pass and band reject filter",
       
   150       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
       
   151 }
       
   152 
       
   153 static void
       
   154 gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass)
       
   155 {
       
   156   GObjectClass *gobject_class = (GObjectClass *) klass;
       
   157   GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
       
   158 
       
   159   gobject_class->set_property = gst_audio_cheb_band_set_property;
       
   160   gobject_class->get_property = gst_audio_cheb_band_get_property;
       
   161   gobject_class->finalize = gst_audio_cheb_band_finalize;
       
   162 
       
   163   g_object_class_install_property (gobject_class, PROP_MODE,
       
   164       g_param_spec_enum ("mode", "Mode",
       
   165           "Low pass or high pass mode", GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE,
       
   166           MODE_BAND_PASS,
       
   167           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
       
   168   g_object_class_install_property (gobject_class, PROP_TYPE,
       
   169       g_param_spec_int ("type", "Type", "Type of the chebychev filter", 1, 2, 1,
       
   170           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
       
   171 
       
   172   /* FIXME: Don't use the complete possible range but restrict the upper boundary
       
   173    * so automatically generated UIs can use a slider without */
       
   174   g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY,
       
   175       g_param_spec_float ("lower-frequency", "Lower frequency",
       
   176           "Start frequency of the band (Hz)", 0.0, 100000.0,
       
   177           0.0,
       
   178           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
       
   179   g_object_class_install_property (gobject_class, PROP_UPPER_FREQUENCY,
       
   180       g_param_spec_float ("upper-frequency", "Upper frequency",
       
   181           "Stop frequency of the band (Hz)", 0.0, 100000.0, 0.0,
       
   182           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
       
   183   g_object_class_install_property (gobject_class, PROP_RIPPLE,
       
   184       g_param_spec_float ("ripple", "Ripple", "Amount of ripple (dB)", 0.0,
       
   185           200.0, 0.25,
       
   186           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
       
   187   /* FIXME: What to do about this upper boundary? With a frequencies near
       
   188    * rate/4 32 poles are completely possible, with frequencies very low
       
   189    * or very high 16 poles already produces only noise */
       
   190   g_object_class_install_property (gobject_class, PROP_POLES,
       
   191       g_param_spec_int ("poles", "Poles",
       
   192           "Number of poles to use, will be rounded up to the next multiply of four",
       
   193           4, 32, 4,
       
   194           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
       
   195 
       
   196   filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_band_setup);
       
   197 }
       
   198 
       
   199 static void
       
   200 gst_audio_cheb_band_init (GstAudioChebBand * filter,
       
   201     GstAudioChebBandClass * klass)
       
   202 {
       
   203   filter->lower_frequency = filter->upper_frequency = 0.0;
       
   204   filter->mode = MODE_BAND_PASS;
       
   205   filter->type = 1;
       
   206   filter->poles = 4;
       
   207   filter->ripple = 0.25;
       
   208 
       
   209   filter->lock = g_mutex_new ();
       
   210 }
       
   211 
       
   212 static void
       
   213 generate_biquad_coefficients (GstAudioChebBand * filter,
       
   214     gint p, gdouble * a0, gdouble * a1, gdouble * a2, gdouble * a3,
       
   215     gdouble * a4, gdouble * b1, gdouble * b2, gdouble * b3, gdouble * b4)
       
   216 {
       
   217   gint np = filter->poles / 2;
       
   218   gdouble ripple = filter->ripple;
       
   219 
       
   220   /* pole location in s-plane */
       
   221   gdouble rp, ip;
       
   222 
       
   223   /* zero location in s-plane */
       
   224   gdouble iz = 0.0;
       
   225 
       
   226   /* transfer function coefficients for the z-plane */
       
   227   gdouble x0, x1, x2, y1, y2;
       
   228   gint type = filter->type;
       
   229 
       
   230   /* Calculate pole location for lowpass at frequency 1 */
       
   231   {
       
   232     gdouble angle = (M_PI / 2.0) * (2.0 * p - 1) / np;
       
   233 
       
   234     rp = -sin (angle);
       
   235     ip = cos (angle);
       
   236   }
       
   237 
       
   238   /* If we allow ripple, move the pole from the unit
       
   239    * circle to an ellipse and keep cutoff at frequency 1 */
       
   240   if (ripple > 0 && type == 1) {
       
   241     gdouble es, vx;
       
   242 
       
   243     es = sqrt (pow (10.0, ripple / 10.0) - 1.0);
       
   244 
       
   245     vx = (1.0 / np) * asinh (1.0 / es);
       
   246     rp = rp * sinh (vx);
       
   247     ip = ip * cosh (vx);
       
   248   } else if (type == 2) {
       
   249     gdouble es, vx;
       
   250 
       
   251     es = sqrt (pow (10.0, ripple / 10.0) - 1.0);
       
   252     vx = (1.0 / np) * asinh (es);
       
   253     rp = rp * sinh (vx);
       
   254     ip = ip * cosh (vx);
       
   255   }
       
   256 
       
   257   /* Calculate inverse of the pole location to move from
       
   258    * type I to type II */
       
   259   if (type == 2) {
       
   260     gdouble mag2 = rp * rp + ip * ip;
       
   261 
       
   262     rp /= mag2;
       
   263     ip /= mag2;
       
   264   }
       
   265 
       
   266   /* Calculate zero location for frequency 1 on the
       
   267    * unit circle for type 2 */
       
   268   if (type == 2) {
       
   269     gdouble angle = M_PI / (np * 2.0) + ((p - 1) * M_PI) / (np);
       
   270     gdouble mag2;
       
   271 
       
   272     iz = cos (angle);
       
   273     mag2 = iz * iz;
       
   274     iz /= mag2;
       
   275   }
       
   276 
       
   277   /* Convert from s-domain to z-domain by
       
   278    * using the bilinear Z-transform, i.e.
       
   279    * substitute s by (2/t)*((z-1)/(z+1))
       
   280    * with t = 2 * tan(0.5).
       
   281    */
       
   282   if (type == 1) {
       
   283     gdouble t, m, d;
       
   284 
       
   285     t = 2.0 * tan (0.5);
       
   286     m = rp * rp + ip * ip;
       
   287     d = 4.0 - 4.0 * rp * t + m * t * t;
       
   288 
       
   289     x0 = (t * t) / d;
       
   290     x1 = 2.0 * x0;
       
   291     x2 = x0;
       
   292     y1 = (8.0 - 2.0 * m * t * t) / d;
       
   293     y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d;
       
   294   } else {
       
   295     gdouble t, m, d;
       
   296 
       
   297     t = 2.0 * tan (0.5);
       
   298     m = rp * rp + ip * ip;
       
   299     d = 4.0 - 4.0 * rp * t + m * t * t;
       
   300 
       
   301     x0 = (t * t * iz * iz + 4.0) / d;
       
   302     x1 = (-8.0 + 2.0 * iz * iz * t * t) / d;
       
   303     x2 = x0;
       
   304     y1 = (8.0 - 2.0 * m * t * t) / d;
       
   305     y2 = (-4.0 - 4.0 * rp * t - m * t * t) / d;
       
   306   }
       
   307 
       
   308   /* Convert from lowpass at frequency 1 to either bandpass
       
   309    * or band reject.
       
   310    *
       
   311    * For bandpass substitute z^(-1) with:
       
   312    *
       
   313    *   -2            -1
       
   314    * -z   + alpha * z   - beta
       
   315    * ----------------------------
       
   316    *         -2            -1
       
   317    * beta * z   - alpha * z   + 1
       
   318    *
       
   319    * alpha = (2*a*b)/(1+b)
       
   320    * beta = (b-1)/(b+1)
       
   321    * a = cos((w1 + w0)/2) / cos((w1 - w0)/2)
       
   322    * b = tan(1/2) * cot((w1 - w0)/2)
       
   323    *
       
   324    * For bandreject substitute z^(-1) with:
       
   325    * 
       
   326    *  -2            -1
       
   327    * z   - alpha * z   + beta
       
   328    * ----------------------------
       
   329    *         -2            -1
       
   330    * beta * z   - alpha * z   + 1
       
   331    *
       
   332    * alpha = (2*a)/(1+b)
       
   333    * beta = (1-b)/(1+b)
       
   334    * a = cos((w1 + w0)/2) / cos((w1 - w0)/2)
       
   335    * b = tan(1/2) * tan((w1 - w0)/2)
       
   336    *
       
   337    */
       
   338   {
       
   339     gdouble a, b, d;
       
   340     gdouble alpha, beta;
       
   341     gdouble w0 =
       
   342         2.0 * M_PI * (filter->lower_frequency /
       
   343         GST_AUDIO_FILTER (filter)->format.rate);
       
   344     gdouble w1 =
       
   345         2.0 * M_PI * (filter->upper_frequency /
       
   346         GST_AUDIO_FILTER (filter)->format.rate);
       
   347 
       
   348     if (filter->mode == MODE_BAND_PASS) {
       
   349       a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
       
   350       b = tan (1.0 / 2.0) / tan ((w1 - w0) / 2.0);
       
   351 
       
   352       alpha = (2.0 * a * b) / (1.0 + b);
       
   353       beta = (b - 1.0) / (b + 1.0);
       
   354 
       
   355       d = 1.0 + beta * (y1 - beta * y2);
       
   356 
       
   357       *a0 = (x0 + beta * (-x1 + beta * x2)) / d;
       
   358       *a1 = (alpha * (-2.0 * x0 + x1 + beta * x1 - 2.0 * beta * x2)) / d;
       
   359       *a2 =
       
   360           (-x1 - beta * beta * x1 + 2.0 * beta * (x0 + x2) +
       
   361           alpha * alpha * (x0 - x1 + x2)) / d;
       
   362       *a3 = (alpha * (x1 + beta * (-2.0 * x0 + x1) - 2.0 * x2)) / d;
       
   363       *a4 = (beta * (beta * x0 - x1) + x2) / d;
       
   364       *b1 = (alpha * (2.0 + y1 + beta * y1 - 2.0 * beta * y2)) / d;
       
   365       *b2 =
       
   366           (-y1 - beta * beta * y1 - alpha * alpha * (1.0 + y1 - y2) +
       
   367           2.0 * beta * (-1.0 + y2)) / d;
       
   368       *b3 = (alpha * (y1 + beta * (2.0 + y1) - 2.0 * y2)) / d;
       
   369       *b4 = (-beta * beta - beta * y1 + y2) / d;
       
   370     } else {
       
   371       a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
       
   372       b = tan (1.0 / 2.0) * tan ((w1 - w0) / 2.0);
       
   373 
       
   374       alpha = (2.0 * a) / (1.0 + b);
       
   375       beta = (1.0 - b) / (1.0 + b);
       
   376 
       
   377       d = -1.0 + beta * (beta * y2 + y1);
       
   378 
       
   379       *a0 = (-x0 - beta * x1 - beta * beta * x2) / d;
       
   380       *a1 = (alpha * (2.0 * x0 + x1 + beta * x1 + 2.0 * beta * x2)) / d;
       
   381       *a2 =
       
   382           (-x1 - beta * beta * x1 - 2.0 * beta * (x0 + x2) -
       
   383           alpha * alpha * (x0 + x1 + x2)) / d;
       
   384       *a3 = (alpha * (x1 + beta * (2.0 * x0 + x1) + 2.0 * x2)) / d;
       
   385       *a4 = (-beta * beta * x0 - beta * x1 - x2) / d;
       
   386       *b1 = (alpha * (-2.0 + y1 + beta * y1 + 2.0 * beta * y2)) / d;
       
   387       *b2 =
       
   388           -(y1 + beta * beta * y1 + 2.0 * beta * (-1.0 + y2) +
       
   389           alpha * alpha * (-1.0 + y1 + y2)) / d;
       
   390       *b3 = (alpha * (beta * (-2.0 + y1) + y1 + 2.0 * y2)) / d;
       
   391       *b4 = -(-beta * beta + beta * y1 + y2) / d;
       
   392     }
       
   393   }
       
   394 }
       
   395 
       
   396 static void
       
   397 generate_coefficients (GstAudioChebBand * filter)
       
   398 {
       
   399   if (GST_AUDIO_FILTER (filter)->format.rate == 0) {
       
   400     gdouble *a = g_new0 (gdouble, 1);
       
   401 
       
   402     a[0] = 1.0;
       
   403     gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
       
   404         (filter), a, 1, NULL, 0);
       
   405     GST_LOG_OBJECT (filter, "rate was not set yet");
       
   406     return;
       
   407   }
       
   408 
       
   409   if (filter->upper_frequency <= filter->lower_frequency) {
       
   410     gdouble *a = g_new0 (gdouble, 1);
       
   411 
       
   412     a[0] = (filter->mode == MODE_BAND_PASS) ? 0.0 : 1.0;
       
   413     gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
       
   414         (filter), a, 1, NULL, 0);
       
   415 
       
   416     GST_LOG_OBJECT (filter, "frequency band had no or negative dimension");
       
   417     return;
       
   418   }
       
   419 
       
   420   if (filter->upper_frequency > GST_AUDIO_FILTER (filter)->format.rate / 2) {
       
   421     filter->upper_frequency = GST_AUDIO_FILTER (filter)->format.rate / 2;
       
   422     GST_LOG_OBJECT (filter, "clipped upper frequency to nyquist frequency");
       
   423   }
       
   424 
       
   425   if (filter->lower_frequency < 0.0) {
       
   426     filter->lower_frequency = 0.0;
       
   427     GST_LOG_OBJECT (filter, "clipped lower frequency to 0.0");
       
   428   }
       
   429 
       
   430   /* Calculate coefficients for the chebyshev filter */
       
   431   {
       
   432     gint np = filter->poles;
       
   433     gdouble *a, *b;
       
   434     gint i, p;
       
   435 
       
   436     a = g_new0 (gdouble, np + 5);
       
   437     b = g_new0 (gdouble, np + 5);
       
   438 
       
   439     /* Calculate transfer function coefficients */
       
   440     a[4] = 1.0;
       
   441     b[4] = 1.0;
       
   442 
       
   443     for (p = 1; p <= np / 4; p++) {
       
   444       gdouble a0, a1, a2, a3, a4, b1, b2, b3, b4;
       
   445       gdouble *ta = g_new0 (gdouble, np + 5);
       
   446       gdouble *tb = g_new0 (gdouble, np + 5);
       
   447 
       
   448       generate_biquad_coefficients (filter, p, &a0, &a1, &a2, &a3, &a4, &b1,
       
   449           &b2, &b3, &b4);
       
   450 
       
   451       memcpy (ta, a, sizeof (gdouble) * (np + 5));
       
   452       memcpy (tb, b, sizeof (gdouble) * (np + 5));
       
   453 
       
   454       /* add the new coefficients for the new two poles
       
   455        * to the cascade by multiplication of the transfer
       
   456        * functions */
       
   457       for (i = 4; i < np + 5; i++) {
       
   458         a[i] =
       
   459             a0 * ta[i] + a1 * ta[i - 1] + a2 * ta[i - 2] + a3 * ta[i - 3] +
       
   460             a4 * ta[i - 4];
       
   461         b[i] =
       
   462             tb[i] - b1 * tb[i - 1] - b2 * tb[i - 2] - b3 * tb[i - 3] -
       
   463             b4 * tb[i - 4];
       
   464       }
       
   465       g_free (ta);
       
   466       g_free (tb);
       
   467     }
       
   468 
       
   469     /* Move coefficients to the beginning of the array
       
   470      * and multiply the b coefficients with -1 to move from
       
   471      * the transfer function's coefficients to the difference
       
   472      * equation's coefficients */
       
   473     b[4] = 0.0;
       
   474     for (i = 0; i <= np; i++) {
       
   475       a[i] = a[i + 4];
       
   476       b[i] = -b[i + 4];
       
   477     }
       
   478 
       
   479     /* Normalize to unity gain at frequency 0 and frequency
       
   480      * 0.5 for bandreject and unity gain at band center frequency
       
   481      * for bandpass */
       
   482     if (filter->mode == MODE_BAND_REJECT) {
       
   483       /* gain is sqrt(H(0)*H(0.5)) */
       
   484 
       
   485       gdouble gain1 =
       
   486           gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
       
   487           1.0, 0.0);
       
   488       gdouble gain2 =
       
   489           gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
       
   490           -1.0, 0.0);
       
   491 
       
   492       gain1 = sqrt (gain1 * gain2);
       
   493 
       
   494       for (i = 0; i <= np; i++) {
       
   495         a[i] /= gain1;
       
   496       }
       
   497     } else {
       
   498       /* gain is H(wc), wc = center frequency */
       
   499 
       
   500       gdouble w1 =
       
   501           2.0 * M_PI * (filter->lower_frequency /
       
   502           GST_AUDIO_FILTER (filter)->format.rate);
       
   503       gdouble w2 =
       
   504           2.0 * M_PI * (filter->upper_frequency /
       
   505           GST_AUDIO_FILTER (filter)->format.rate);
       
   506       gdouble w0 = (w2 + w1) / 2.0;
       
   507       gdouble zr = cos (w0), zi = sin (w0);
       
   508       gdouble gain =
       
   509           gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr,
       
   510           zi);
       
   511 
       
   512       for (i = 0; i <= np; i++) {
       
   513         a[i] /= gain;
       
   514       }
       
   515     }
       
   516 
       
   517     gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
       
   518         (filter), a, np + 1, b, np + 1);
       
   519 
       
   520     GST_LOG_OBJECT (filter,
       
   521         "Generated IIR coefficients for the Chebyshev filter");
       
   522     GST_LOG_OBJECT (filter,
       
   523         "mode: %s, type: %d, poles: %d, lower-frequency: %.2f Hz, upper-frequency: %.2f Hz, ripple: %.2f dB",
       
   524         (filter->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject",
       
   525         filter->type, filter->poles, filter->lower_frequency,
       
   526         filter->upper_frequency, filter->ripple);
       
   527 
       
   528     GST_LOG_OBJECT (filter, "%.2f dB gain @ 0Hz",
       
   529         20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
       
   530                 np + 1, 1.0, 0.0)));
       
   531     {
       
   532       gdouble w1 =
       
   533           2.0 * M_PI * (filter->lower_frequency /
       
   534           GST_AUDIO_FILTER (filter)->format.rate);
       
   535       gdouble w2 =
       
   536           2.0 * M_PI * (filter->upper_frequency /
       
   537           GST_AUDIO_FILTER (filter)->format.rate);
       
   538       gdouble w0 = (w2 + w1) / 2.0;
       
   539       gdouble zr, zi;
       
   540 
       
   541       zr = cos (w1);
       
   542       zi = sin (w1);
       
   543       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
       
   544           20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
       
   545                   b, np + 1, zr, zi)), (int) filter->lower_frequency);
       
   546       zr = cos (w0);
       
   547       zi = sin (w0);
       
   548       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
       
   549           20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
       
   550                   b, np + 1, zr, zi)),
       
   551           (int) ((filter->lower_frequency + filter->upper_frequency) / 2.0));
       
   552       zr = cos (w2);
       
   553       zi = sin (w2);
       
   554       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
       
   555           20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
       
   556                   b, np + 1, zr, zi)), (int) filter->upper_frequency);
       
   557     }
       
   558     GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
       
   559         20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
       
   560                 np + 1, -1.0, 0.0)),
       
   561         GST_AUDIO_FILTER (filter)->format.rate / 2);
       
   562   }
       
   563 }
       
   564 
       
   565 static void
       
   566 gst_audio_cheb_band_finalize (GObject * object)
       
   567 {
       
   568   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
       
   569 
       
   570   g_mutex_free (filter->lock);
       
   571   filter->lock = NULL;
       
   572 
       
   573   G_OBJECT_CLASS (parent_class)->finalize (object);
       
   574 }
       
   575 
       
   576 static void
       
   577 gst_audio_cheb_band_set_property (GObject * object, guint prop_id,
       
   578     const GValue * value, GParamSpec * pspec)
       
   579 {
       
   580   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
       
   581 
       
   582   switch (prop_id) {
       
   583     case PROP_MODE:
       
   584       g_mutex_lock (filter->lock);
       
   585       filter->mode = g_value_get_enum (value);
       
   586       generate_coefficients (filter);
       
   587       g_mutex_unlock (filter->lock);
       
   588       break;
       
   589     case PROP_TYPE:
       
   590       g_mutex_lock (filter->lock);
       
   591       filter->type = g_value_get_int (value);
       
   592       generate_coefficients (filter);
       
   593       g_mutex_unlock (filter->lock);
       
   594       break;
       
   595     case PROP_LOWER_FREQUENCY:
       
   596       g_mutex_lock (filter->lock);
       
   597       filter->lower_frequency = g_value_get_float (value);
       
   598       generate_coefficients (filter);
       
   599       g_mutex_unlock (filter->lock);
       
   600       break;
       
   601     case PROP_UPPER_FREQUENCY:
       
   602       g_mutex_lock (filter->lock);
       
   603       filter->upper_frequency = g_value_get_float (value);
       
   604       generate_coefficients (filter);
       
   605       g_mutex_unlock (filter->lock);
       
   606       break;
       
   607     case PROP_RIPPLE:
       
   608       g_mutex_lock (filter->lock);
       
   609       filter->ripple = g_value_get_float (value);
       
   610       generate_coefficients (filter);
       
   611       g_mutex_unlock (filter->lock);
       
   612       break;
       
   613     case PROP_POLES:
       
   614       g_mutex_lock (filter->lock);
       
   615       filter->poles = GST_ROUND_UP_4 (g_value_get_int (value));
       
   616       generate_coefficients (filter);
       
   617       g_mutex_unlock (filter->lock);
       
   618       break;
       
   619     default:
       
   620       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   621       break;
       
   622   }
       
   623 }
       
   624 
       
   625 static void
       
   626 gst_audio_cheb_band_get_property (GObject * object, guint prop_id,
       
   627     GValue * value, GParamSpec * pspec)
       
   628 {
       
   629   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
       
   630 
       
   631   switch (prop_id) {
       
   632     case PROP_MODE:
       
   633       g_value_set_enum (value, filter->mode);
       
   634       break;
       
   635     case PROP_TYPE:
       
   636       g_value_set_int (value, filter->type);
       
   637       break;
       
   638     case PROP_LOWER_FREQUENCY:
       
   639       g_value_set_float (value, filter->lower_frequency);
       
   640       break;
       
   641     case PROP_UPPER_FREQUENCY:
       
   642       g_value_set_float (value, filter->upper_frequency);
       
   643       break;
       
   644     case PROP_RIPPLE:
       
   645       g_value_set_float (value, filter->ripple);
       
   646       break;
       
   647     case PROP_POLES:
       
   648       g_value_set_int (value, filter->poles);
       
   649       break;
       
   650     default:
       
   651       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   652       break;
       
   653   }
       
   654 }
       
   655 
       
   656 /* GstAudioFilter vmethod implementations */
       
   657 
       
   658 static gboolean
       
   659 gst_audio_cheb_band_setup (GstAudioFilter * base, GstRingBufferSpec * format)
       
   660 {
       
   661   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base);
       
   662 
       
   663   generate_coefficients (filter);
       
   664 
       
   665   return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, format);
       
   666 }