"Fossies" - the Fresh Open Source Software Archive

Member "gst-plugins-good-1.20.3/gst/audiofx/audiochebband.c" (15 Jun 2022, 21657 Bytes) of package /linux/misc/gst-plugins-good-1.20.3.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "audiochebband.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.18.6_vs_1.20.0.

    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., 51 Franklin St, Fifth Floor,
   18  * Boston, MA 02110-1301, 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  * @title: audiochebband
   38  *
   39  * Attenuates all frequencies outside (bandpass) or inside (bandreject) of a frequency
   40  * band. The number of poles and the ripple parameter control the rolloff.
   41  *
   42  * This element has the advantage over the windowed sinc bandpass and bandreject filter that it is
   43  * much faster and produces almost as good results. It's only disadvantages are the highly
   44  * non-linear phase and the slower rolloff compared to a windowed sinc filter with a large kernel.
   45  *
   46  * For type 1 the ripple parameter specifies how much ripple in dB is allowed in the passband, i.e.
   47  * some frequencies in the passband will be amplified by that value. A higher ripple value will allow
   48  * a faster rolloff.
   49  *
   50  * For type 2 the ripple parameter specifies the stopband attenuation. In the stopband the gain will
   51  * be at most this value. A lower ripple value will allow a faster rolloff.
   52  *
   53  * As a special case, a Chebyshev type 1 filter with no ripple is a Butterworth filter.
   54  *
   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  *
   58  * ## Example launch line
   59  * |[
   60  * gst-launch-1.0 audiotestsrc freq=1500 ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequency=6000 poles=4 ! audioconvert ! alsasink
   61  * gst-launch-1.0 filesrc location="melo1.ogg" ! oggdemux ! vorbisdec ! audioconvert ! audiochebband mode=band-reject lower-frequency=1000 upper-frequency=4000 ripple=0.2 ! audioconvert ! alsasink
   62  * gst-launch-1.0 audiotestsrc wave=white-noise ! audioconvert ! audiochebband mode=band-pass lower-frequency=1000 upper-frequency=4000 type=2 ! audioconvert ! alsasink
   63  * ]|
   64  *
   65  */
   66 
   67 #ifdef HAVE_CONFIG_H
   68 #include "config.h"
   69 #endif
   70 
   71 #include <string.h>
   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 
   78 #include <math.h>
   79 
   80 #include "math_compat.h"
   81 
   82 #include "audiochebband.h"
   83 
   84 #include "gst/glib-compat-private.h"
   85 
   86 #define GST_CAT_DEFAULT gst_audio_cheb_band_debug
   87 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
   88 
   89 enum
   90 {
   91   PROP_0,
   92   PROP_MODE,
   93   PROP_TYPE,
   94   PROP_LOWER_FREQUENCY,
   95   PROP_UPPER_FREQUENCY,
   96   PROP_RIPPLE,
   97   PROP_POLES
   98 };
   99 
  100 #define gst_audio_cheb_band_parent_class parent_class
  101 G_DEFINE_TYPE (GstAudioChebBand, gst_audio_cheb_band,
  102     GST_TYPE_AUDIO_FX_BASE_IIR_FILTER);
  103 GST_ELEMENT_REGISTER_DEFINE (audiochebband, "audiochebband",
  104     GST_RANK_NONE, GST_TYPE_AUDIO_CHEB_BAND);
  105 
  106 static void gst_audio_cheb_band_set_property (GObject * object,
  107     guint prop_id, const GValue * value, GParamSpec * pspec);
  108 static void gst_audio_cheb_band_get_property (GObject * object,
  109     guint prop_id, GValue * value, GParamSpec * pspec);
  110 static void gst_audio_cheb_band_finalize (GObject * object);
  111 
  112 static gboolean gst_audio_cheb_band_setup (GstAudioFilter * filter,
  113     const GstAudioInfo * info);
  114 
  115 enum
  116 {
  117   MODE_BAND_PASS = 0,
  118   MODE_BAND_REJECT
  119 };
  120 
  121 #define GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE (gst_audio_cheb_band_mode_get_type ())
  122 static GType
  123 gst_audio_cheb_band_mode_get_type (void)
  124 {
  125   static GType gtype = 0;
  126 
  127   if (gtype == 0) {
  128     static const GEnumValue values[] = {
  129       {MODE_BAND_PASS, "Band pass (default)",
  130           "band-pass"},
  131       {MODE_BAND_REJECT, "Band reject",
  132           "band-reject"},
  133       {0, NULL, NULL}
  134     };
  135 
  136     gtype = g_enum_register_static ("GstAudioChebBandMode", values);
  137   }
  138   return gtype;
  139 }
  140 
  141 /* GObject vmethod implementations */
  142 
  143 static void
  144 gst_audio_cheb_band_class_init (GstAudioChebBandClass * klass)
  145 {
  146   GObjectClass *gobject_class = (GObjectClass *) klass;
  147   GstElementClass *gstelement_class = (GstElementClass *) klass;
  148   GstAudioFilterClass *filter_class = (GstAudioFilterClass *) klass;
  149 
  150   GST_DEBUG_CATEGORY_INIT (gst_audio_cheb_band_debug, "audiochebband", 0,
  151       "audiochebband element");
  152 
  153   gobject_class->set_property = gst_audio_cheb_band_set_property;
  154   gobject_class->get_property = gst_audio_cheb_band_get_property;
  155   gobject_class->finalize = gst_audio_cheb_band_finalize;
  156 
  157   g_object_class_install_property (gobject_class, PROP_MODE,
  158       g_param_spec_enum ("mode", "Mode",
  159           "Low pass or high pass mode", GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE,
  160           MODE_BAND_PASS,
  161           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  162   g_object_class_install_property (gobject_class, PROP_TYPE,
  163       g_param_spec_int ("type", "Type", "Type of the chebychev filter", 1, 2, 1,
  164           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  165 
  166   /* FIXME: Don't use the complete possible range but restrict the upper boundary
  167    * so automatically generated UIs can use a slider without */
  168   g_object_class_install_property (gobject_class, PROP_LOWER_FREQUENCY,
  169       g_param_spec_float ("lower-frequency", "Lower frequency",
  170           "Start frequency of the band (Hz)", 0.0, 100000.0,
  171           0.0,
  172           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  173   g_object_class_install_property (gobject_class, PROP_UPPER_FREQUENCY,
  174       g_param_spec_float ("upper-frequency", "Upper frequency",
  175           "Stop frequency of the band (Hz)", 0.0, 100000.0, 0.0,
  176           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  177   g_object_class_install_property (gobject_class, PROP_RIPPLE,
  178       g_param_spec_float ("ripple", "Ripple", "Amount of ripple (dB)", 0.0,
  179           200.0, 0.25,
  180           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  181   /* FIXME: What to do about this upper boundary? With a frequencies near
  182    * rate/4 32 poles are completely possible, with frequencies very low
  183    * or very high 16 poles already produces only noise */
  184   g_object_class_install_property (gobject_class, PROP_POLES,
  185       g_param_spec_int ("poles", "Poles",
  186           "Number of poles to use, will be rounded up to the next multiply of four",
  187           4, 32, 4,
  188           G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
  189 
  190   gst_element_class_set_static_metadata (gstelement_class,
  191       "Band pass & band reject filter", "Filter/Effect/Audio",
  192       "Chebyshev band pass and band reject filter",
  193       "Sebastian Dröge <sebastian.droege@collabora.co.uk>");
  194 
  195   filter_class->setup = GST_DEBUG_FUNCPTR (gst_audio_cheb_band_setup);
  196 
  197   gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_CHEBYSHEV_FREQ_BAND_MODE, 0);
  198 }
  199 
  200 static void
  201 gst_audio_cheb_band_init (GstAudioChebBand * filter)
  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   g_mutex_init (&filter->lock);
  210 }
  211 
  212 static void
  213 generate_biquad_coefficients (GstAudioChebBand * filter,
  214     gint p, gint rate, gdouble * b0, gdouble * b1, gdouble * b2, gdouble * b3,
  215     gdouble * b4, gdouble * a1, gdouble * a2, gdouble * a3, gdouble * a4)
  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 = (G_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 = G_PI / (np * 2.0) + ((p - 1) * G_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 = 2.0 * G_PI * (filter->lower_frequency / rate);
  342     gdouble w1 = 2.0 * G_PI * (filter->upper_frequency / rate);
  343 
  344     if (filter->mode == MODE_BAND_PASS) {
  345       a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
  346       b = tan (1.0 / 2.0) / tan ((w1 - w0) / 2.0);
  347 
  348       alpha = (2.0 * a * b) / (1.0 + b);
  349       beta = (b - 1.0) / (b + 1.0);
  350 
  351       d = 1.0 + beta * (y1 - beta * y2);
  352 
  353       *b0 = (x0 + beta * (-x1 + beta * x2)) / d;
  354       *b1 = (alpha * (-2.0 * x0 + x1 + beta * x1 - 2.0 * beta * x2)) / d;
  355       *b2 =
  356           (-x1 - beta * beta * x1 + 2.0 * beta * (x0 + x2) +
  357           alpha * alpha * (x0 - x1 + x2)) / d;
  358       *b3 = (alpha * (x1 + beta * (-2.0 * x0 + x1) - 2.0 * x2)) / d;
  359       *b4 = (beta * (beta * x0 - x1) + x2) / d;
  360       *a1 = (alpha * (2.0 + y1 + beta * y1 - 2.0 * beta * y2)) / d;
  361       *a2 =
  362           (-y1 - beta * beta * y1 - alpha * alpha * (1.0 + y1 - y2) +
  363           2.0 * beta * (-1.0 + y2)) / d;
  364       *a3 = (alpha * (y1 + beta * (2.0 + y1) - 2.0 * y2)) / d;
  365       *a4 = (-beta * beta - beta * y1 + y2) / d;
  366     } else {
  367       a = cos ((w1 + w0) / 2.0) / cos ((w1 - w0) / 2.0);
  368       b = tan (1.0 / 2.0) * tan ((w1 - w0) / 2.0);
  369 
  370       alpha = (2.0 * a) / (1.0 + b);
  371       beta = (1.0 - b) / (1.0 + b);
  372 
  373       d = -1.0 + beta * (beta * y2 + y1);
  374 
  375       *b0 = (-x0 - beta * x1 - beta * beta * x2) / d;
  376       *b1 = (alpha * (2.0 * x0 + x1 + beta * x1 + 2.0 * beta * x2)) / d;
  377       *b2 =
  378           (-x1 - beta * beta * x1 - 2.0 * beta * (x0 + x2) -
  379           alpha * alpha * (x0 + x1 + x2)) / d;
  380       *b3 = (alpha * (x1 + beta * (2.0 * x0 + x1) + 2.0 * x2)) / d;
  381       *b4 = (-beta * beta * x0 - beta * x1 - x2) / d;
  382       *a1 = (alpha * (-2.0 + y1 + beta * y1 + 2.0 * beta * y2)) / d;
  383       *a2 =
  384           -(y1 + beta * beta * y1 + 2.0 * beta * (-1.0 + y2) +
  385           alpha * alpha * (-1.0 + y1 + y2)) / d;
  386       *a3 = (alpha * (beta * (-2.0 + y1) + y1 + 2.0 * y2)) / d;
  387       *a4 = -(-beta * beta + beta * y1 + y2) / d;
  388     }
  389   }
  390 }
  391 
  392 static void
  393 generate_coefficients (GstAudioChebBand * filter, const GstAudioInfo * info)
  394 {
  395   gint rate;
  396 
  397   if (info) {
  398     rate = GST_AUDIO_INFO_RATE (info);
  399   } else {
  400     rate = GST_AUDIO_FILTER_RATE (filter);
  401   }
  402 
  403   if (rate == 0) {
  404     gdouble *a = g_new0 (gdouble, 1);
  405     gdouble *b = g_new0 (gdouble, 1);
  406 
  407     a[0] = 1.0;
  408     b[0] = 1.0;
  409     gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
  410         (filter), a, 1, b, 1);
  411     GST_LOG_OBJECT (filter, "rate was not set yet");
  412     return;
  413   }
  414 
  415   if (filter->upper_frequency <= filter->lower_frequency) {
  416     gdouble *a = g_new0 (gdouble, 1);
  417     gdouble *b = g_new0 (gdouble, 1);
  418 
  419     a[0] = 1.0;
  420     b[0] = (filter->mode == MODE_BAND_PASS) ? 0.0 : 1.0;
  421     gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
  422         (filter), a, 1, b, 1);
  423 
  424     GST_LOG_OBJECT (filter, "frequency band had no or negative dimension");
  425     return;
  426   }
  427 
  428   if (filter->upper_frequency > rate / 2) {
  429     filter->upper_frequency = rate / 2;
  430     GST_LOG_OBJECT (filter, "clipped upper frequency to nyquist frequency");
  431   }
  432 
  433   if (filter->lower_frequency < 0.0) {
  434     filter->lower_frequency = 0.0;
  435     GST_LOG_OBJECT (filter, "clipped lower frequency to 0.0");
  436   }
  437 
  438   /* Calculate coefficients for the chebyshev filter */
  439   {
  440     gint np = filter->poles;
  441     gdouble *a, *b;
  442     gint i, p;
  443 
  444     a = g_new0 (gdouble, np + 5);
  445     b = g_new0 (gdouble, np + 5);
  446 
  447     /* Calculate transfer function coefficients */
  448     a[4] = 1.0;
  449     b[4] = 1.0;
  450 
  451     for (p = 1; p <= np / 4; p++) {
  452       gdouble b0, b1, b2, b3, b4, a1, a2, a3, a4;
  453       gdouble *ta = g_new0 (gdouble, np + 5);
  454       gdouble *tb = g_new0 (gdouble, np + 5);
  455 
  456       generate_biquad_coefficients (filter, p, rate,
  457           &b0, &b1, &b2, &b3, &b4, &a1, &a2, &a3, &a4);
  458 
  459       memcpy (ta, a, sizeof (gdouble) * (np + 5));
  460       memcpy (tb, b, sizeof (gdouble) * (np + 5));
  461 
  462       /* add the new coefficients for the new two poles
  463        * to the cascade by multiplication of the transfer
  464        * functions */
  465       for (i = 4; i < np + 5; i++) {
  466         b[i] =
  467             b0 * tb[i] + b1 * tb[i - 1] + b2 * tb[i - 2] + b3 * tb[i - 3] +
  468             b4 * tb[i - 4];
  469         a[i] =
  470             ta[i] - a1 * ta[i - 1] - a2 * ta[i - 2] - a3 * ta[i - 3] -
  471             a4 * ta[i - 4];
  472       }
  473       g_free (ta);
  474       g_free (tb);
  475     }
  476 
  477     /* Move coefficients to the beginning of the array to move from
  478      * the transfer function's coefficients to the difference
  479      * equation's coefficients */
  480     for (i = 0; i <= np; i++) {
  481       a[i] = a[i + 4];
  482       b[i] = b[i + 4];
  483     }
  484 
  485     /* Normalize to unity gain at frequency 0 and frequency
  486      * 0.5 for bandreject and unity gain at band center frequency
  487      * for bandpass */
  488     if (filter->mode == MODE_BAND_REJECT) {
  489       /* gain is sqrt(H(0)*H(0.5)) */
  490 
  491       gdouble gain1 =
  492           gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
  493           1.0, 0.0);
  494       gdouble gain2 =
  495           gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1,
  496           -1.0, 0.0);
  497 
  498       gain1 = sqrt (gain1 * gain2);
  499 
  500       for (i = 0; i <= np; i++) {
  501         b[i] /= gain1;
  502       }
  503     } else {
  504       /* gain is H(wc), wc = center frequency */
  505 
  506       gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / rate);
  507       gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / rate);
  508       gdouble w0 = (w2 + w1) / 2.0;
  509       gdouble zr = cos (w0), zi = sin (w0);
  510       gdouble gain =
  511           gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b, np + 1, zr,
  512           zi);
  513 
  514       for (i = 0; i <= np; i++) {
  515         b[i] /= gain;
  516       }
  517     }
  518 
  519     gst_audio_fx_base_iir_filter_set_coefficients (GST_AUDIO_FX_BASE_IIR_FILTER
  520         (filter), a, np + 1, b, np + 1);
  521 
  522     GST_LOG_OBJECT (filter,
  523         "Generated IIR coefficients for the Chebyshev filter");
  524     GST_LOG_OBJECT (filter,
  525         "mode: %s, type: %d, poles: %d, lower-frequency: %.2f Hz, upper-frequency: %.2f Hz, ripple: %.2f dB",
  526         (filter->mode == MODE_BAND_PASS) ? "band-pass" : "band-reject",
  527         filter->type, filter->poles, filter->lower_frequency,
  528         filter->upper_frequency, filter->ripple);
  529 
  530     GST_LOG_OBJECT (filter, "%.2f dB gain @ 0Hz",
  531         20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
  532                 np + 1, 1.0, 0.0)));
  533     {
  534       gdouble w1 = 2.0 * G_PI * (filter->lower_frequency / rate);
  535       gdouble w2 = 2.0 * G_PI * (filter->upper_frequency / rate);
  536       gdouble w0 = (w2 + w1) / 2.0;
  537       gdouble zr, zi;
  538 
  539       zr = cos (w1);
  540       zi = sin (w1);
  541       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
  542           20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
  543                   b, np + 1, zr, zi)), (int) filter->lower_frequency);
  544       zr = cos (w0);
  545       zi = sin (w0);
  546       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
  547           20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
  548                   b, np + 1, zr, zi)),
  549           (int) ((filter->lower_frequency + filter->upper_frequency) / 2.0));
  550       zr = cos (w2);
  551       zi = sin (w2);
  552       GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
  553           20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1,
  554                   b, np + 1, zr, zi)), (int) filter->upper_frequency);
  555     }
  556     GST_LOG_OBJECT (filter, "%.2f dB gain @ %dHz",
  557         20.0 * log10 (gst_audio_fx_base_iir_filter_calculate_gain (a, np + 1, b,
  558                 np + 1, -1.0, 0.0)), rate / 2);
  559   }
  560 }
  561 
  562 static void
  563 gst_audio_cheb_band_finalize (GObject * object)
  564 {
  565   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
  566 
  567   g_mutex_clear (&filter->lock);
  568 
  569   G_OBJECT_CLASS (parent_class)->finalize (object);
  570 }
  571 
  572 static void
  573 gst_audio_cheb_band_set_property (GObject * object, guint prop_id,
  574     const GValue * value, GParamSpec * pspec)
  575 {
  576   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
  577 
  578   switch (prop_id) {
  579     case PROP_MODE:
  580       g_mutex_lock (&filter->lock);
  581       filter->mode = g_value_get_enum (value);
  582       generate_coefficients (filter, NULL);
  583       g_mutex_unlock (&filter->lock);
  584       break;
  585     case PROP_TYPE:
  586       g_mutex_lock (&filter->lock);
  587       filter->type = g_value_get_int (value);
  588       generate_coefficients (filter, NULL);
  589       g_mutex_unlock (&filter->lock);
  590       break;
  591     case PROP_LOWER_FREQUENCY:
  592       g_mutex_lock (&filter->lock);
  593       filter->lower_frequency = g_value_get_float (value);
  594       generate_coefficients (filter, NULL);
  595       g_mutex_unlock (&filter->lock);
  596       break;
  597     case PROP_UPPER_FREQUENCY:
  598       g_mutex_lock (&filter->lock);
  599       filter->upper_frequency = g_value_get_float (value);
  600       generate_coefficients (filter, NULL);
  601       g_mutex_unlock (&filter->lock);
  602       break;
  603     case PROP_RIPPLE:
  604       g_mutex_lock (&filter->lock);
  605       filter->ripple = g_value_get_float (value);
  606       generate_coefficients (filter, NULL);
  607       g_mutex_unlock (&filter->lock);
  608       break;
  609     case PROP_POLES:
  610       g_mutex_lock (&filter->lock);
  611       filter->poles = GST_ROUND_UP_4 (g_value_get_int (value));
  612       generate_coefficients (filter, NULL);
  613       g_mutex_unlock (&filter->lock);
  614       break;
  615     default:
  616       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  617       break;
  618   }
  619 }
  620 
  621 static void
  622 gst_audio_cheb_band_get_property (GObject * object, guint prop_id,
  623     GValue * value, GParamSpec * pspec)
  624 {
  625   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (object);
  626 
  627   switch (prop_id) {
  628     case PROP_MODE:
  629       g_value_set_enum (value, filter->mode);
  630       break;
  631     case PROP_TYPE:
  632       g_value_set_int (value, filter->type);
  633       break;
  634     case PROP_LOWER_FREQUENCY:
  635       g_value_set_float (value, filter->lower_frequency);
  636       break;
  637     case PROP_UPPER_FREQUENCY:
  638       g_value_set_float (value, filter->upper_frequency);
  639       break;
  640     case PROP_RIPPLE:
  641       g_value_set_float (value, filter->ripple);
  642       break;
  643     case PROP_POLES:
  644       g_value_set_int (value, filter->poles);
  645       break;
  646     default:
  647       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
  648       break;
  649   }
  650 }
  651 
  652 /* GstAudioFilter vmethod implementations */
  653 
  654 static gboolean
  655 gst_audio_cheb_band_setup (GstAudioFilter * base, const GstAudioInfo * info)
  656 {
  657   GstAudioChebBand *filter = GST_AUDIO_CHEB_BAND (base);
  658 
  659   generate_coefficients (filter, info);
  660 
  661   return GST_AUDIO_FILTER_CLASS (parent_class)->setup (base, info);
  662 }