diff options
| -rw-r--r-- | gst/equalizer/gstiirequalizer.c | 118 | 
1 files changed, 70 insertions, 48 deletions
diff --git a/gst/equalizer/gstiirequalizer.c b/gst/equalizer/gstiirequalizer.c index dcd27c9f..8c87a664 100644 --- a/gst/equalizer/gstiirequalizer.c +++ b/gst/equalizer/gstiirequalizer.c @@ -83,7 +83,7 @@ enum  {    ARG_GAIN = 1,    ARG_FREQ, -  ARG_BAND_WIDTH +  ARG_BANDWIDTH  };  typedef struct _GstIirEqualizerBandClass GstIirEqualizerBandClass; @@ -110,9 +110,8 @@ struct _GstIirEqualizerBand    gdouble width;    /* second order iir filter */ -  gdouble alpha;                /* IIR coefficients for outputs */ -  gdouble beta;                 /* IIR coefficients for inputs */ -  gdouble gamma;                /* IIR coefficients for inputs */ +  gdouble b1, b2;               /* IIR coefficients for outputs */ +  gdouble a0, a1, a2;           /* IIR coefficients for inputs */  };  struct _GstIirEqualizerBandClass @@ -148,7 +147,25 @@ gst_iir_equalizer_band_set_property (GObject * object, guint prop_id,        }        break;      } -    case ARG_BAND_WIDTH:{ +    case ARG_FREQ:{ +      gdouble freq; + +      freq = g_value_get_double (value); +      GST_DEBUG_OBJECT (band, "freq = %lf -> %lf", band->freq, freq); +      if (freq != band->freq) { +        GstIirEqualizer *equ = +            GST_IIR_EQUALIZER (gst_object_get_parent (GST_OBJECT (band))); + +        band->freq = freq; +        if (GST_AUDIO_FILTER (equ)->format.rate) { +          setup_filter (equ, band); +        } +        gst_object_unref (equ); +        GST_DEBUG_OBJECT (band, "changed freq = %lf ", band->freq); +      } +      break; +    } +    case ARG_BANDWIDTH:{        gdouble width;        width = g_value_get_double (value); @@ -185,7 +202,7 @@ gst_iir_equalizer_band_get_property (GObject * object, guint prop_id,      case ARG_FREQ:        g_value_set_double (value, band->freq);        break; -    case ARG_BAND_WIDTH: +    case ARG_BANDWIDTH:        g_value_set_double (value, band->width);        break;      default: @@ -204,18 +221,18 @@ gst_iir_equalizer_band_class_init (GstIirEqualizerBandClass * klass)    g_object_class_install_property (gobject_class, ARG_GAIN,        g_param_spec_double ("gain", "gain", -          "gain for the frequency band ranging from -1.0 to +1.0", -          -1.0, 1.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); +          "gain for the frequency band ranging from -24.0 dB to +12.0 dB", +          -24.0, 12.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));    g_object_class_install_property (gobject_class, ARG_FREQ,        g_param_spec_double ("freq", "freq",            "center frequency of the band", -          0.0, 100000.0, 0.0, G_PARAM_READABLE)); +          0.0, 100000.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); -  g_object_class_install_property (gobject_class, ARG_BAND_WIDTH, -      g_param_spec_double ("band-width", "band-width", -          "band width calculated as distance between bands * this value", 0.1, -          10.0, 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE)); +  g_object_class_install_property (gobject_class, ARG_BANDWIDTH, +      g_param_spec_double ("bandwidth", "bandwidth", +          "difference between bandedges in Hz", +          1.0, 100000.0, 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));  }  static void @@ -330,53 +347,57 @@ gst_iir_equalizer_finalize (GObject * object)    G_OBJECT_CLASS (parent_class)->finalize (object);  } -/* - * converts gain values to scale factors. - * - * we map -1 ... 1 to a db range. - * A suitable range would be -12db ... 0 ... + 6db which expressed as - * a factor is about          0.06 ... 1 ... 4.0 - * - * We need to subtract one so that gain is centered around zero - * - * visualize via gnuplot: - *   set xrange [-1:1] - *   plot 10.0 ** (12*x/10.0) - */ -static gdouble +static inline gdouble  arg_to_scale (gdouble arg)  { -  return (pow (10.0, (6.0 * fabs (arg)) / 10.0) - 1.0); +  return (pow (10.0, arg / 20.0));  } +/* Filter taken from + * + * The Equivalence of Various Methods of Computing + * Biquad Coefficients for Audio Parametric Equalizers + * + * by Robert Bristow-Johnson + * + * http://www.aes.org/e-lib/browse.cfm?elib=6326 + * http://www.musicdsp.org/files/EQ-Coefficients.pdf + * + * The bandwidth method that we use here is the preferred + * one from this article transformed from octaves to frequency + * in Hz. + */  static void  setup_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)  {    g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate);    /* FIXME: we need better filters -   * - the band-width control is not good     * - we need shelf-filter for 1st and last band     */    {      gdouble gain = arg_to_scale (band->gain);      gdouble frequency = band->freq / GST_AUDIO_FILTER (equ)->format.rate; -    gdouble q = pow (HIGHEST_FREQ / LOWEST_FREQ, -        1.0 / (equ->freq_band_count - 1)) * band->width; +    gdouble omega = 2.0 * M_PI * frequency; +    gdouble bw = +        2.0 * M_PI * (band->width / GST_AUDIO_FILTER (equ)->format.rate); -    gdouble theta = frequency * 2 * M_PI; +    gdouble edge_gain = sqrt (gain); +    gdouble gamma = tan (bw / 2.0); -    band->beta = (q - theta / 2) / (2 * q + theta); -    band->gamma = (0.5 + band->beta) * cos (theta); -    band->alpha = (0.5 - band->beta) / 2; +    gdouble alpha = gamma * edge_gain; +    gdouble beta = gamma / edge_gain; -    band->beta *= 2.0; -    band->alpha *= 2.0 * gain; -    band->gamma *= 2.0; +    band->a0 = (1.0 + alpha) / (1.0 + beta); +    band->a1 = (-2.0 * cos (omega)) / (1.0 + beta); +    band->a2 = (1.0 - alpha) / (1.0 + beta); +    band->b1 = (2.0 * cos (omega)) / (1.0 + beta); +    band->b2 = -(1.0 - beta) / (1.0 + beta);      GST_INFO -        ("gain = %7.5g, frequency = %7.5g, alpha = %7.5g, beta = %7.5g, gamma=%7.5g", -        gain, frequency, band->alpha, band->beta, band->gamma); +        ("gain = %7.5g, , bandwidth= %7.5g, frequency = %7.5g, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g", +        gain, band->width, frequency, band->a0, band->a1, band->a2, band->b1, +        band->b2);    }  } @@ -425,11 +446,13 @@ gst_iir_equalizer_compute_frequencies (GstIirEqualizer * equ, guint new_count)     * FIXME: arg! we can't change the name of parented objects :(     *   application should read band->freq to get the name     */ +    step = pow (HIGHEST_FREQ / LOWEST_FREQ, 1.0 / new_count);    freq0 = LOWEST_FREQ;    for (i = 0; i < new_count; i++) {      freq1 = freq0 * step;      equ->bands[i]->freq = freq0 + ((freq1 - freq0) / 2.0); +    equ->bands[i]->width = freq1 - freq0;      GST_DEBUG ("band[%2d] = '%lf'", i, equ->bands[i]->freq);      /*         if(equ->bands[i]->freq<10000.0) @@ -442,6 +465,7 @@ gst_iir_equalizer_compute_frequencies (GstIirEqualizer * equ, guint new_count)      freq0 = freq1;    } +    if (GST_AUDIO_FILTER (equ)->format.rate) {      for (i = 0; i < new_count; i++) {        setup_filter (equ, equ->bands[i]); @@ -462,16 +486,16 @@ one_step_ ## TYPE (GstIirEqualizerBand *filter,                         \      SecondOrderHistory ## TYPE *history, TYPE input)                    \  {                                                                       \    /* calculate output */                                                \ -  TYPE output = filter->alpha * (input - history->x2) +                 \ -    filter->gamma * history->y1 - filter->beta * history->y2;           \ +  TYPE output = filter->a0 * input + filter->a1 * history->x1 +         \ +      filter->a2 * history->x2 + filter->b1 * history->y1 +             \ +      filter->b2 * history->y2;                                         \    /* update history */                                                  \    history->y2 = history->y1;                                            \    history->y1 = output;                                                 \    history->x2 = history->x1;                                            \    history->x1 = input;                                                  \                                                                          \ -  /* for negative gains we subtract */                                  \ -  return (filter->gain>0.0) ? output : -output;                         \ +  return output;                                                        \  }                                                                       \                                                                          \  static const guint                                                      \ @@ -484,17 +508,15 @@ guint size, guint channels)                                             \    guint frames = size / channels / sizeof (TYPE);                       \    guint i, c, f;                                                        \    BIG_TYPE cur;                                                         \ -  TYPE val;                                                             \                                                                          \    for (i = 0; i < frames; i++) {                                        \      for (c = 0; c < channels; c++) {                                    \        SecondOrderHistory ## TYPE *history = equ->history;               \ -      val = *((TYPE *) data);                                           \ -      cur = 0.25 * val; /* FIXME: should be without factor*/            \ +      cur = *((TYPE *) data);                                           \        for (f = 0; f < equ->freq_band_count; f++) {                      \          GstIirEqualizerBand *filter = equ->bands[f];                    \                                                                          \ -        cur += one_step_ ## TYPE (filter, history, val);                \ +        cur = one_step_ ## TYPE (filter, history, cur);                 \          history++;                                                      \        }                                                                 \        cur = CLAMP (cur, MIN_VAL, MAX_VAL);                              \  | 
