1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright © 2006 VLC authors and VideoLAN
6 * Authors: Antti Huovilainen
7 * Sigmund A. Helberg <dnumgis@videolan.org>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
37 #include <vlc_filter.h>
39 /*****************************************************************************
41 *****************************************************************************/
42 static int Open ( vlc_object_t
* );
43 static void Close( vlc_object_t
* );
44 static void CalcPeakEQCoeffs( float, float, float, float, float * );
45 static void CalcShelfEQCoeffs( float, float, float, int, float, float * );
46 static void ProcessEQ( const float *, float *, float *, unsigned, unsigned,
47 const float *, unsigned );
48 static block_t
*DoWork( filter_t
*, block_t
* );
51 set_description( N_("Parametric Equalizer") )
52 set_shortname( N_("Parametric Equalizer" ) )
53 set_capability( "audio filter", 0 )
54 set_category( CAT_AUDIO
)
55 set_subcategory( SUBCAT_AUDIO_AFILTER
)
57 add_float( "param-eq-lowf", 100, N_("Low freq (Hz)"),NULL
, false )
58 add_float_with_range( "param-eq-lowgain", 0, -20.0, 20.0,
59 N_("Low freq gain (dB)"), NULL
,false )
60 add_float( "param-eq-highf", 10000, N_("High freq (Hz)"),NULL
, false )
61 add_float_with_range( "param-eq-highgain", 0, -20.0, 20.0,
62 N_("High freq gain (dB)"),NULL
,false )
63 add_float( "param-eq-f1", 300, N_("Freq 1 (Hz)"),NULL
, false )
64 add_float_with_range( "param-eq-gain1", 0, -20.0, 20.0,
65 N_("Freq 1 gain (dB)"), NULL
,false )
66 add_float_with_range( "param-eq-q1", 3, 0.1, 100.0,
67 N_("Freq 1 Q"), NULL
,false )
68 add_float( "param-eq-f2", 1000, N_("Freq 2 (Hz)"),NULL
, false )
69 add_float_with_range( "param-eq-gain2", 0, -20.0, 20.0,
70 N_("Freq 2 gain (dB)"),NULL
,false )
71 add_float_with_range( "param-eq-q2", 3, 0.1, 100.0,
72 N_("Freq 2 Q"),NULL
,false )
73 add_float( "param-eq-f3", 3000, N_("Freq 3 (Hz)"),NULL
, false )
74 add_float_with_range( "param-eq-gain3", 0, -20.0, 20.0,
75 N_("Freq 3 gain (dB)"),NULL
,false )
76 add_float_with_range( "param-eq-q3", 3, 0.1, 100.0,
77 N_("Freq 3 Q"),NULL
,false )
79 set_callbacks( Open
, Close
)
82 /*****************************************************************************
84 *****************************************************************************/
87 /* Filter static config */
88 float f_lowf
, f_lowgain
;
89 float f_f1
, f_Q1
, f_gain1
;
90 float f_f2
, f_Q2
, f_gain2
;
91 float f_f3
, f_Q3
, f_gain3
;
92 float f_highf
, f_highgain
;
93 /* Filter computed coeffs */
102 /*****************************************************************************
104 *****************************************************************************/
105 static int Open( vlc_object_t
*p_this
)
107 filter_t
*p_filter
= (filter_t
*)p_this
;
108 unsigned i_samplerate
;
110 /* Allocate structure */
111 filter_sys_t
*p_sys
= p_filter
->p_sys
= malloc( sizeof( *p_sys
) );
115 p_filter
->fmt_in
.audio
.i_format
= VLC_CODEC_FL32
;
116 p_filter
->fmt_out
.audio
= p_filter
->fmt_in
.audio
;
117 p_filter
->pf_audio_filter
= DoWork
;
119 p_sys
->f_lowf
= var_InheritFloat( p_this
, "param-eq-lowf");
120 p_sys
->f_lowgain
= var_InheritFloat( p_this
, "param-eq-lowgain");
121 p_sys
->f_highf
= var_InheritFloat( p_this
, "param-eq-highf");
122 p_sys
->f_highgain
= var_InheritFloat( p_this
, "param-eq-highgain");
124 p_sys
->f_f1
= var_InheritFloat( p_this
, "param-eq-f1");
125 p_sys
->f_Q1
= var_InheritFloat( p_this
, "param-eq-q1");
126 p_sys
->f_gain1
= var_InheritFloat( p_this
, "param-eq-gain1");
128 p_sys
->f_f2
= var_InheritFloat( p_this
, "param-eq-f2");
129 p_sys
->f_Q2
= var_InheritFloat( p_this
, "param-eq-q2");
130 p_sys
->f_gain2
= var_InheritFloat( p_this
, "param-eq-gain2");
132 p_sys
->f_f3
= var_InheritFloat( p_this
, "param-eq-f3");
133 p_sys
->f_Q3
= var_InheritFloat( p_this
, "param-eq-q3");
134 p_sys
->f_gain3
= var_InheritFloat( p_this
, "param-eq-gain3");
137 i_samplerate
= p_filter
->fmt_in
.audio
.i_rate
;
138 CalcPeakEQCoeffs(p_sys
->f_f1
, p_sys
->f_Q1
, p_sys
->f_gain1
,
139 i_samplerate
, p_sys
->coeffs
+0*5);
140 CalcPeakEQCoeffs(p_sys
->f_f2
, p_sys
->f_Q2
, p_sys
->f_gain2
,
141 i_samplerate
, p_sys
->coeffs
+1*5);
142 CalcPeakEQCoeffs(p_sys
->f_f3
, p_sys
->f_Q3
, p_sys
->f_gain3
,
143 i_samplerate
, p_sys
->coeffs
+2*5);
144 CalcShelfEQCoeffs(p_sys
->f_lowf
, 1, p_sys
->f_lowgain
, 0,
145 i_samplerate
, p_sys
->coeffs
+3*5);
146 CalcShelfEQCoeffs(p_sys
->f_highf
, 1, p_sys
->f_highgain
, 0,
147 i_samplerate
, p_sys
->coeffs
+4*5);
148 p_sys
->p_state
= (float*)calloc( p_filter
->fmt_in
.audio
.i_channels
*5*4,
154 static void Close( vlc_object_t
*p_this
)
156 filter_t
*p_filter
= (filter_t
*)p_this
;
157 filter_sys_t
*p_sys
= p_filter
->p_sys
;
158 free( p_sys
->p_state
);
162 /*****************************************************************************
163 * DoWork: process samples buffer
164 *****************************************************************************
166 *****************************************************************************/
167 static block_t
*DoWork( filter_t
* p_filter
, block_t
* p_in_buf
)
169 filter_sys_t
*p_sys
= p_filter
->p_sys
;
170 ProcessEQ( (float*)p_in_buf
->p_buffer
, (float*)p_in_buf
->p_buffer
,
172 p_filter
->fmt_in
.audio
.i_channels
, p_in_buf
->i_nb_samples
,
178 * Calculate direct form IIR coefficients for peaking EQ
185 * Equations taken from RBJ audio EQ cookbook
186 * (http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt)
188 static void CalcPeakEQCoeffs( float f0
, float Q
, float gainDB
, float Fs
,
197 // Provide sane limits to avoid overflow
198 if (Q
< 0.1f
) Q
= 0.1f
;
199 if (Q
> 100) Q
= 100;
200 if (f0
> Fs
/2*0.95f
) f0
= Fs
/2*0.95f
;
201 if (gainDB
< -40) gainDB
= -40;
202 if (gainDB
> 40) gainDB
= 40;
204 A
= powf(10, gainDB
/40);
205 w0
= 2*((float)M_PI
)*f0
/Fs
;
206 alpha
= sinf(w0
)/(2*Q
);
215 // Store values to coeffs and normalize by 1/a0
224 * Calculate direct form IIR coefficients for low/high shelf EQ
231 * Equations taken from RBJ audio EQ cookbook
232 * (http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt)
234 static void CalcShelfEQCoeffs( float f0
, float slope
, float gainDB
, int high
,
235 float Fs
, float *coeffs
)
243 // Provide sane limits to avoid overflow
244 if (f0
> Fs
/2*0.95f
) f0
= Fs
/2*0.95f
;
245 if (gainDB
< -40) gainDB
= -40;
246 if (gainDB
> 40) gainDB
= 40;
248 A
= powf(10, gainDB
/40);
249 w0
= 2*3.141593f
*f0
/Fs
;
250 alpha
= sinf(w0
)/2 * sqrtf( (A
+ 1/A
)*(1/slope
- 1) + 2 );
254 b0
= A
*( (A
+1) + (A
-1)*cosf(w0
) + 2*sqrtf(A
)*alpha
);
255 b1
= -2*A
*( (A
-1) + (A
+1)*cosf(w0
) );
256 b2
= A
*( (A
+1) + (A
-1)*cosf(w0
) - 2*sqrtf(A
)*alpha
);
257 a0
= (A
+1) - (A
-1)*cosf(w0
) + 2*sqrtf(A
)*alpha
;
258 a1
= 2*( (A
-1) - (A
+1)*cosf(w0
) );
259 a2
= (A
+1) - (A
-1)*cosf(w0
) - 2*sqrtf(A
)*alpha
;
263 b0
= A
*( (A
+1) - (A
-1)*cosf(w0
) + 2*sqrtf(A
)*alpha
);
264 b1
= 2*A
*( (A
-1) - (A
+1)*cosf(w0
));
265 b2
= A
*( (A
+1) - (A
-1)*cosf(w0
) - 2*sqrtf(A
)*alpha
);
266 a0
= (A
+1) + (A
-1)*cosf(w0
) + 2*sqrtf(A
)*alpha
;
267 a1
= -2*( (A
-1) + (A
+1)*cosf(w0
));
268 a2
= (A
+1) + (A
-1)*cosf(w0
) - 2*sqrtf(A
)*alpha
;
270 // Store values to coeffs and normalize by 1/a0
279 src is assumed to be interleaved
280 dest is assumed to be interleaved
281 size of state is 4*channels*eqCount
282 samples is not premultiplied by channels
283 size of coeffs is 5*eqCount
285 void ProcessEQ( const float *src
, float *dest
, float *state
,
286 unsigned channels
, unsigned samples
, const float *coeffs
,
290 float b0
, b1
, b2
, a1
, a2
;
292 const float *src1
= src
;
295 for (i
= 0; i
< samples
; i
++)
297 float *state1
= state
;
298 for (chn
= 0; chn
< channels
; chn
++)
300 const float *coeffs1
= coeffs
;
302 /* Direct form 1 IIRs */
303 for (eq
= 0; eq
< eqCount
; eq
++)
311 y
= x
*b0
+ state1
[0]*b1
+ state1
[1]*b2
- state1
[2]*a1
- state1
[3]*a2
;
312 state1
[1] = state1
[0];
314 state1
[3] = state1
[2];