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