summaryrefslogtreecommitdiffstats
path: root/gst/equalizer/gstiirequalizer.c
diff options
context:
space:
mode:
authorSebastian Dröge <slomo@circular-chaos.org>2007-10-30 21:18:45 +0000
committerSebastian Dröge <slomo@circular-chaos.org>2007-10-30 21:18:45 +0000
commit3b838968c2a34e1031b8b67ae7b9dc784ec6d209 (patch)
treee74b3bcc0718a1fdbcef8bb180f61f4f66de0a04 /gst/equalizer/gstiirequalizer.c
parent556fdc15f4cad344aa75cdbada6a55e2d839db32 (diff)
downloadgst-plugins-bad-3b838968c2a34e1031b8b67ae7b9dc784ec6d209.tar.gz
gst-plugins-bad-3b838968c2a34e1031b8b67ae7b9dc784ec6d209.tar.bz2
gst-plugins-bad-3b838968c2a34e1031b8b67ae7b9dc784ec6d209.zip
gst/equalizer/gstiirequalizer.c: Replace filters with a bit better filters for which we can actually find documentati...
Original commit message from CVS: * gst/equalizer/gstiirequalizer.c: (gst_iir_equalizer_band_set_property), (gst_iir_equalizer_band_get_property), (gst_iir_equalizer_band_class_init), (arg_to_scale), (setup_filter), (gst_iir_equalizer_compute_frequencies): Replace filters with a bit better filters for which we can actually find documentation, which don't change anything on zero gain, etc. Make the frequency property of the bands writable, rename the band-width property to bandwidth and change the meaning to the frequency difference between bandedges, change the meaning of the gain property to dB instead of a weird scale between -1 and 1 that has no real meaning.
Diffstat (limited to 'gst/equalizer/gstiirequalizer.c')
-rw-r--r--gst/equalizer/gstiirequalizer.c118
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); \