equalizer: use shelfing filters for first and last band
Refactor the filter setup. Add two new filters with shelf characteristics for first and last band. Change gain calculation as recommended in the quoted document (no qrt needed). Rename variables to match the formulas in the document.
This commit is contained in:
parent
15c6175044
commit
27ea0b076a
@ -121,10 +121,6 @@ struct _GstIirEqualizerBandClass
|
|||||||
|
|
||||||
static GType gst_iir_equalizer_band_get_type (void);
|
static GType gst_iir_equalizer_band_get_type (void);
|
||||||
|
|
||||||
static void setup_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band);
|
|
||||||
|
|
||||||
static void set_passthrough (GstIirEqualizer * equ);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_iir_equalizer_band_set_property (GObject * object, guint prop_id,
|
gst_iir_equalizer_band_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * pspec)
|
const GValue * value, GParamSpec * pspec)
|
||||||
@ -357,12 +353,6 @@ gst_iir_equalizer_finalize (GObject * object)
|
|||||||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline gdouble
|
|
||||||
arg_to_scale (gdouble arg)
|
|
||||||
{
|
|
||||||
return (pow (10.0, arg / 20.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Filter taken from
|
/* Filter taken from
|
||||||
*
|
*
|
||||||
* The Equivalence of Various Methods of Computing
|
* The Equivalence of Various Methods of Computing
|
||||||
@ -372,34 +362,39 @@ arg_to_scale (gdouble arg)
|
|||||||
*
|
*
|
||||||
* http://www.aes.org/e-lib/browse.cfm?elib=6326
|
* http://www.aes.org/e-lib/browse.cfm?elib=6326
|
||||||
* http://www.musicdsp.org/files/EQ-Coefficients.pdf
|
* http://www.musicdsp.org/files/EQ-Coefficients.pdf
|
||||||
|
* http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
|
||||||
*
|
*
|
||||||
* The bandwidth method that we use here is the preferred
|
* The bandwidth method that we use here is the preferred
|
||||||
* one from this article transformed from octaves to frequency
|
* one from this article transformed from octaves to frequency
|
||||||
* in Hz.
|
* in Hz.
|
||||||
*/
|
*/
|
||||||
static void
|
static inline gdouble
|
||||||
setup_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
|
arg_to_scale (gdouble arg)
|
||||||
{
|
{
|
||||||
g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate);
|
return (pow (10.0, arg / 40.0));
|
||||||
|
}
|
||||||
|
|
||||||
/* FIXME: we need better filters
|
static gdouble
|
||||||
* - we need shelf-filter for 1st and last band
|
calculate_omega (gdouble freq, gint rate)
|
||||||
*/
|
{
|
||||||
{
|
gdouble omega;
|
||||||
gdouble gain, omega, bw;
|
|
||||||
gdouble edge_gain, gamma;
|
|
||||||
gdouble alpha, beta;
|
|
||||||
|
|
||||||
gain = arg_to_scale (band->gain);
|
if (freq / rate >= 0.5)
|
||||||
|
|
||||||
if (band->freq / GST_AUDIO_FILTER (equ)->format.rate >= 0.5)
|
|
||||||
omega = M_PI;
|
omega = M_PI;
|
||||||
else if (band->freq <= 0.0)
|
else if (freq <= 0.0)
|
||||||
omega = 0.0;
|
omega = 0.0;
|
||||||
else
|
else
|
||||||
omega = 2.0 * M_PI * (band->freq / GST_AUDIO_FILTER (equ)->format.rate);
|
omega = 2.0 * M_PI * (freq / rate);
|
||||||
|
|
||||||
if (band->width / GST_AUDIO_FILTER (equ)->format.rate >= 0.5) {
|
return omega;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gdouble
|
||||||
|
calculate_bw (GstIirEqualizerBand * band, gint rate)
|
||||||
|
{
|
||||||
|
gdouble bw = 0.0;
|
||||||
|
|
||||||
|
if (band->width / rate >= 0.5) {
|
||||||
/* If bandwidth == 0.5 the calculation below fails as tan(M_PI/2)
|
/* If bandwidth == 0.5 the calculation below fails as tan(M_PI/2)
|
||||||
* is undefined. So set the bandwidth to a slightly smaller value.
|
* is undefined. So set the bandwidth to a slightly smaller value.
|
||||||
*/
|
*/
|
||||||
@ -415,23 +410,115 @@ setup_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
|
|||||||
band->a2 = 0.0;
|
band->a2 = 0.0;
|
||||||
band->b1 = 0.0;
|
band->b1 = 0.0;
|
||||||
band->b2 = 0.0;
|
band->b2 = 0.0;
|
||||||
gain = 1.0;
|
|
||||||
goto out;
|
|
||||||
} else {
|
} else {
|
||||||
bw = 2.0 * M_PI * (band->width / GST_AUDIO_FILTER (equ)->format.rate);
|
bw = 2.0 * M_PI * (band->width / rate);
|
||||||
}
|
}
|
||||||
|
return bw;
|
||||||
|
}
|
||||||
|
|
||||||
edge_gain = sqrt (gain);
|
static void
|
||||||
gamma = tan (bw / 2.0);
|
setup_peak_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
|
||||||
alpha = gamma * edge_gain;
|
{
|
||||||
beta = gamma / edge_gain;
|
gdouble gain, omega, bw;
|
||||||
|
gdouble alpha, alpha1, alpha2, b0;
|
||||||
|
|
||||||
|
gain = arg_to_scale (band->gain);
|
||||||
|
omega = calculate_omega (band->freq, GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
bw = calculate_bw (band, GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
if (bw == 0.0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
alpha = tan (bw / 2.0);
|
||||||
|
|
||||||
|
alpha1 = alpha * gain;
|
||||||
|
alpha2 = alpha / gain;
|
||||||
|
|
||||||
|
b0 = (1.0 + alpha2);
|
||||||
|
|
||||||
|
band->a0 = (1.0 + alpha1) / b0;
|
||||||
|
band->a1 = (-2.0 * cos (omega)) / b0;
|
||||||
|
band->a2 = (1.0 - alpha1) / b0;
|
||||||
|
band->b1 = (2.0 * cos (omega)) / b0;
|
||||||
|
band->b2 = -(1.0 - alpha2) / b0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
GST_INFO
|
||||||
|
("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
|
||||||
|
band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
|
||||||
|
band->b1, band->b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_low_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
|
||||||
|
{
|
||||||
|
gdouble gain, omega, bw;
|
||||||
|
gdouble alpha, delta, b0;
|
||||||
|
gdouble egp, egm;
|
||||||
|
|
||||||
|
gain = arg_to_scale (band->gain);
|
||||||
|
omega = calculate_omega (band->freq, GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
bw = calculate_bw (band, GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
if (bw == 0.0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
egm = gain - 1.0;
|
||||||
|
egp = gain + 1.0;
|
||||||
|
alpha = tan (bw / 2.0);
|
||||||
|
|
||||||
|
delta = 2.0 * sqrt (gain) * alpha;
|
||||||
|
b0 = egp + egm * cos (omega) + delta;
|
||||||
|
|
||||||
|
band->a0 = ((egp - egm * cos (omega) + delta) * gain) / b0;
|
||||||
|
band->a1 = ((egm - egp * cos (omega)) * 2.0 * gain) / b0;
|
||||||
|
band->a2 = ((egp - egm * cos (omega) - delta) * gain) / b0;
|
||||||
|
band->b1 = ((egm + egp * cos (omega)) * 2.0) / b0;
|
||||||
|
band->b2 = -((egp + egm * cos (omega) - delta)) / b0;
|
||||||
|
|
||||||
|
|
||||||
|
out:
|
||||||
|
GST_INFO
|
||||||
|
("gain = %5.1f, width= %7.2f, freq = %7.2f, a0 = %7.5g, a1 = %7.5g, a2=%7.5g b1 = %7.5g, b2 = %7.5g",
|
||||||
|
band->gain, band->width, band->freq, band->a0, band->a1, band->a2,
|
||||||
|
band->b1, band->b2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
setup_high_shelf_filter (GstIirEqualizer * equ, GstIirEqualizerBand * band)
|
||||||
|
{
|
||||||
|
g_return_if_fail (GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
|
||||||
|
{
|
||||||
|
gdouble gain, omega, bw;
|
||||||
|
gdouble alpha, delta, b0;
|
||||||
|
gdouble egp, egm;
|
||||||
|
|
||||||
|
gain = arg_to_scale (band->gain);
|
||||||
|
omega = calculate_omega (band->freq, GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
bw = calculate_bw (band, GST_AUDIO_FILTER (equ)->format.rate);
|
||||||
|
if (bw == 0.0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
egm = gain - 1.0;
|
||||||
|
egp = gain + 1.0;
|
||||||
|
alpha = tan (bw / 2.0);
|
||||||
|
|
||||||
|
delta = 2.0 * sqrt (gain) * alpha;
|
||||||
|
b0 = egp - egm * cos (omega) + delta;
|
||||||
|
|
||||||
|
band->a0 = ((egp + egm * cos (omega) + delta) * gain) / b0;
|
||||||
|
band->a1 = ((egm + egp * cos (omega)) * -2.0 * gain) / b0;
|
||||||
|
band->a2 = ((egp + egm * cos (omega) - delta) * gain) / b0;
|
||||||
|
band->b1 = ((egm - egp * cos (omega)) * -2.0) / b0;
|
||||||
|
band->b2 = -((egp - egm * cos (omega) - delta)) / b0;
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
GST_INFO
|
GST_INFO
|
||||||
@ -459,11 +546,14 @@ set_passthrough (GstIirEqualizer * equ)
|
|||||||
static void
|
static void
|
||||||
update_coefficients (GstIirEqualizer * equ)
|
update_coefficients (GstIirEqualizer * equ)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i, n = equ->freq_band_count;
|
||||||
|
|
||||||
for (i = 0; i < equ->freq_band_count; i++) {
|
setup_low_shelf_filter (equ, equ->bands[0]);
|
||||||
setup_filter (equ, equ->bands[i]);
|
for (i = 1; i < n - 1; i++) {
|
||||||
|
setup_peak_filter (equ, equ->bands[i]);
|
||||||
}
|
}
|
||||||
|
setup_high_shelf_filter (equ, equ->bands[n - 1]);
|
||||||
|
|
||||||
equ->need_new_coefficients = FALSE;
|
equ->need_new_coefficients = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user