mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-31 03:29:50 +00:00
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.
This commit is contained in:
parent
556fdc15f4
commit
3b838968c2
2 changed files with 86 additions and 48 deletions
16
ChangeLog
16
ChangeLog
|
@ -1,3 +1,19 @@
|
||||||
|
2007-10-30 Sebastian Dröge <slomo@circular-chaos.org>
|
||||||
|
|
||||||
|
* 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.
|
||||||
|
|
||||||
2007-10-30 Stefan Kost <ensonic@users.sf.net>
|
2007-10-30 Stefan Kost <ensonic@users.sf.net>
|
||||||
|
|
||||||
* sys/dvb/dvbbasebin.c:
|
* sys/dvb/dvbbasebin.c:
|
||||||
|
|
|
@ -83,7 +83,7 @@ enum
|
||||||
{
|
{
|
||||||
ARG_GAIN = 1,
|
ARG_GAIN = 1,
|
||||||
ARG_FREQ,
|
ARG_FREQ,
|
||||||
ARG_BAND_WIDTH
|
ARG_BANDWIDTH
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct _GstIirEqualizerBandClass GstIirEqualizerBandClass;
|
typedef struct _GstIirEqualizerBandClass GstIirEqualizerBandClass;
|
||||||
|
@ -110,9 +110,8 @@ struct _GstIirEqualizerBand
|
||||||
gdouble width;
|
gdouble width;
|
||||||
|
|
||||||
/* second order iir filter */
|
/* second order iir filter */
|
||||||
gdouble alpha; /* IIR coefficients for outputs */
|
gdouble b1, b2; /* IIR coefficients for outputs */
|
||||||
gdouble beta; /* IIR coefficients for inputs */
|
gdouble a0, a1, a2; /* IIR coefficients for inputs */
|
||||||
gdouble gamma; /* IIR coefficients for inputs */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstIirEqualizerBandClass
|
struct _GstIirEqualizerBandClass
|
||||||
|
@ -148,7 +147,25 @@ gst_iir_equalizer_band_set_property (GObject * object, guint prop_id,
|
||||||
}
|
}
|
||||||
break;
|
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;
|
gdouble width;
|
||||||
|
|
||||||
width = g_value_get_double (value);
|
width = g_value_get_double (value);
|
||||||
|
@ -185,7 +202,7 @@ gst_iir_equalizer_band_get_property (GObject * object, guint prop_id,
|
||||||
case ARG_FREQ:
|
case ARG_FREQ:
|
||||||
g_value_set_double (value, band->freq);
|
g_value_set_double (value, band->freq);
|
||||||
break;
|
break;
|
||||||
case ARG_BAND_WIDTH:
|
case ARG_BANDWIDTH:
|
||||||
g_value_set_double (value, band->width);
|
g_value_set_double (value, band->width);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -204,18 +221,18 @@ gst_iir_equalizer_band_class_init (GstIirEqualizerBandClass * klass)
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, ARG_GAIN,
|
g_object_class_install_property (gobject_class, ARG_GAIN,
|
||||||
g_param_spec_double ("gain", "gain",
|
g_param_spec_double ("gain", "gain",
|
||||||
"gain for the frequency band ranging from -1.0 to +1.0",
|
"gain for the frequency band ranging from -24.0 dB to +12.0 dB",
|
||||||
-1.0, 1.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
|
-24.0, 12.0, 0.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
|
||||||
|
|
||||||
g_object_class_install_property (gobject_class, ARG_FREQ,
|
g_object_class_install_property (gobject_class, ARG_FREQ,
|
||||||
g_param_spec_double ("freq", "freq",
|
g_param_spec_double ("freq", "freq",
|
||||||
"center frequency of the band",
|
"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_object_class_install_property (gobject_class, ARG_BANDWIDTH,
|
||||||
g_param_spec_double ("band-width", "band-width",
|
g_param_spec_double ("bandwidth", "bandwidth",
|
||||||
"band width calculated as distance between bands * this value", 0.1,
|
"difference between bandedges in Hz",
|
||||||
10.0, 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
|
1.0, 100000.0, 1.0, G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -330,53 +347,57 @@ gst_iir_equalizer_finalize (GObject * object)
|
||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static inline gdouble
|
||||||
* 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
|
|
||||||
arg_to_scale (gdouble arg)
|
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
|
static void
|
||||||
setup_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
|
setup_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate);
|
g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
|
||||||
/* FIXME: we need better filters
|
/* FIXME: we need better filters
|
||||||
* - the band-width control is not good
|
|
||||||
* - we need shelf-filter for 1st and last band
|
* - we need shelf-filter for 1st and last band
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
gdouble gain = arg_to_scale (band->gain);
|
gdouble gain = arg_to_scale (band->gain);
|
||||||
gdouble frequency = band->freq / GST_AUDIO_FILTER (equ)->format.rate;
|
gdouble frequency = band->freq / GST_AUDIO_FILTER (equ)->format.rate;
|
||||||
gdouble q = pow (HIGHEST_FREQ / LOWEST_FREQ,
|
gdouble omega = 2.0 * M_PI * frequency;
|
||||||
1.0 / (equ->freq_band_count - 1)) * band->width;
|
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);
|
gdouble alpha = gamma * edge_gain;
|
||||||
band->gamma = (0.5 + band->beta) * cos (theta);
|
gdouble beta = gamma / edge_gain;
|
||||||
band->alpha = (0.5 - band->beta) / 2;
|
|
||||||
|
|
||||||
band->beta *= 2.0;
|
band->a0 = (1.0 + alpha) / (1.0 + beta);
|
||||||
band->alpha *= 2.0 * gain;
|
band->a1 = (-2.0 * cos (omega)) / (1.0 + beta);
|
||||||
band->gamma *= 2.0;
|
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
|
GST_INFO
|
||||||
("gain = %7.5g, frequency = %7.5g, alpha = %7.5g, beta = %7.5g, gamma=%7.5g",
|
("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, frequency, band->alpha, band->beta, band->gamma);
|
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 :(
|
* FIXME: arg! we can't change the name of parented objects :(
|
||||||
* application should read band->freq to get the name
|
* application should read band->freq to get the name
|
||||||
*/
|
*/
|
||||||
|
|
||||||
step = pow (HIGHEST_FREQ / LOWEST_FREQ, 1.0 / new_count);
|
step = pow (HIGHEST_FREQ / LOWEST_FREQ, 1.0 / new_count);
|
||||||
freq0 = LOWEST_FREQ;
|
freq0 = LOWEST_FREQ;
|
||||||
for (i = 0; i < new_count; i++) {
|
for (i = 0; i < new_count; i++) {
|
||||||
freq1 = freq0 * step;
|
freq1 = freq0 * step;
|
||||||
equ->bands[i]->freq = freq0 + ((freq1 - freq0) / 2.0);
|
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);
|
GST_DEBUG ("band[%2d] = '%lf'", i, equ->bands[i]->freq);
|
||||||
/*
|
/*
|
||||||
if(equ->bands[i]->freq<10000.0)
|
if(equ->bands[i]->freq<10000.0)
|
||||||
|
@ -442,6 +465,7 @@ gst_iir_equalizer_compute_frequencies (GstIirEqualizer * equ, guint new_count)
|
||||||
freq0 = freq1;
|
freq0 = freq1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (GST_AUDIO_FILTER (equ)->format.rate) {
|
if (GST_AUDIO_FILTER (equ)->format.rate) {
|
||||||
for (i = 0; i < new_count; i++) {
|
for (i = 0; i < new_count; i++) {
|
||||||
setup_filter (equ, equ->bands[i]);
|
setup_filter (equ, equ->bands[i]);
|
||||||
|
@ -462,16 +486,16 @@ one_step_ ## TYPE (GstIirEqualizerBand *filter, \
|
||||||
SecondOrderHistory ## TYPE *history, TYPE input) \
|
SecondOrderHistory ## TYPE *history, TYPE input) \
|
||||||
{ \
|
{ \
|
||||||
/* calculate output */ \
|
/* calculate output */ \
|
||||||
TYPE output = filter->alpha * (input - history->x2) + \
|
TYPE output = filter->a0 * input + filter->a1 * history->x1 + \
|
||||||
filter->gamma * history->y1 - filter->beta * history->y2; \
|
filter->a2 * history->x2 + filter->b1 * history->y1 + \
|
||||||
|
filter->b2 * history->y2; \
|
||||||
/* update history */ \
|
/* update history */ \
|
||||||
history->y2 = history->y1; \
|
history->y2 = history->y1; \
|
||||||
history->y1 = output; \
|
history->y1 = output; \
|
||||||
history->x2 = history->x1; \
|
history->x2 = history->x1; \
|
||||||
history->x1 = input; \
|
history->x1 = input; \
|
||||||
\
|
\
|
||||||
/* for negative gains we subtract */ \
|
return output; \
|
||||||
return (filter->gain>0.0) ? output : -output; \
|
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
static const guint \
|
static const guint \
|
||||||
|
@ -484,17 +508,15 @@ guint size, guint channels) \
|
||||||
guint frames = size / channels / sizeof (TYPE); \
|
guint frames = size / channels / sizeof (TYPE); \
|
||||||
guint i, c, f; \
|
guint i, c, f; \
|
||||||
BIG_TYPE cur; \
|
BIG_TYPE cur; \
|
||||||
TYPE val; \
|
|
||||||
\
|
\
|
||||||
for (i = 0; i < frames; i++) { \
|
for (i = 0; i < frames; i++) { \
|
||||||
for (c = 0; c < channels; c++) { \
|
for (c = 0; c < channels; c++) { \
|
||||||
SecondOrderHistory ## TYPE *history = equ->history; \
|
SecondOrderHistory ## TYPE *history = equ->history; \
|
||||||
val = *((TYPE *) data); \
|
cur = *((TYPE *) data); \
|
||||||
cur = 0.25 * val; /* FIXME: should be without factor*/ \
|
|
||||||
for (f = 0; f < equ->freq_band_count; f++) { \
|
for (f = 0; f < equ->freq_band_count; f++) { \
|
||||||
GstIirEqualizerBand *filter = equ->bands[f]; \
|
GstIirEqualizerBand *filter = equ->bands[f]; \
|
||||||
\
|
\
|
||||||
cur += one_step_ ## TYPE (filter, history, val); \
|
cur = one_step_ ## TYPE (filter, history, cur); \
|
||||||
history++; \
|
history++; \
|
||||||
} \
|
} \
|
||||||
cur = CLAMP (cur, MIN_VAL, MAX_VAL); \
|
cur = CLAMP (cur, MIN_VAL, MAX_VAL); \
|
||||||
|
|
Loading…
Reference in a new issue