1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004-2012 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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>
36 #include <vlc_charset.h>
39 #include <vlc_filter.h>
41 #include "equalizer_presets.h"
44 * - optimize a bit (you can hardly do slower ;)
45 * - add tables for more bands (15 and 32 would be cool), maybe with auto coeffs
46 * computation (not too hard once the Q is found).
47 * - support for external preset
48 * - callback to handle preset changes on the fly
52 /*****************************************************************************
54 *****************************************************************************/
55 static int Open ( vlc_object_t
* );
56 static void Close( vlc_object_t
* );
58 #define PRESET_TEXT N_( "Equalizer preset" )
59 #define PRESET_LONGTEXT N_("Preset to use for the equalizer." )
61 #define BANDS_TEXT N_( "Bands gain")
62 #define BANDS_LONGTEXT N_( \
63 "Don't use presets, but manually specified bands. You need to " \
64 "provide 10 values between -20dB and 20dB, separated by spaces, " \
65 "e.g. \"0 2 4 2 0 -2 -4 -2 0 2\"." )
67 #define VLC_BANDS_TEXT N_( "Use VLC frequency bands" )
68 #define VLC_BANDS_LONGTEXT N_( \
69 "Use the VLC frequency bands. Otherwise, use the ISO Standard " \
72 #define TWOPASS_TEXT N_( "Two pass" )
73 #define TWOPASS_LONGTEXT N_( "Filter the audio twice. This provides a more " \
76 #define PREAMP_TEXT N_("Global gain" )
77 #define PREAMP_LONGTEXT N_("Set the global gain in dB (-20 ... 20)." )
80 set_description( N_("Equalizer with 10 bands") )
81 set_shortname( N_("Equalizer" ) )
82 set_capability( "audio filter", 0 )
83 set_category( CAT_AUDIO
)
84 set_subcategory( SUBCAT_AUDIO_AFILTER
)
86 add_string( "equalizer-preset", "flat", PRESET_TEXT
,
87 PRESET_LONGTEXT
, false )
88 change_string_list( preset_list
, preset_list_text
)
89 add_string( "equalizer-bands", NULL
, BANDS_TEXT
,
90 BANDS_LONGTEXT
, true )
91 add_bool( "equalizer-2pass", false, TWOPASS_TEXT
,
92 TWOPASS_LONGTEXT
, true )
93 add_bool( "equalizer-vlcfreqs", true, VLC_BANDS_TEXT
,
94 VLC_BANDS_LONGTEXT
, true )
95 add_float( "equalizer-preamp", 12.0f
, PREAMP_TEXT
,
96 PREAMP_LONGTEXT
, true )
97 set_callbacks( Open
, Close
)
98 add_shortcut( "equalizer" )
101 /*****************************************************************************
103 *****************************************************************************/
106 /* Filter static config */
112 /* Filter dyn config */
113 float *f_amp
; /* Per band amp */
114 float f_gamp
; /* Global preamp */
121 /* Second filter state */
123 float y2
[32][128][2];
128 static block_t
*DoWork( filter_t
*, block_t
* );
130 #define EQZ_IN_FACTOR (0.25f)
131 static int EqzInit( filter_t
*, int );
132 static void EqzFilter( filter_t
*, float *, float *, int, int );
133 static void EqzClean( filter_t
* );
135 static int PresetCallback ( vlc_object_t
*, char const *, vlc_value_t
,
136 vlc_value_t
, void * );
137 static int PreampCallback ( vlc_object_t
*, char const *, vlc_value_t
,
138 vlc_value_t
, void * );
139 static int BandsCallback ( vlc_object_t
*, char const *, vlc_value_t
,
140 vlc_value_t
, void * );
141 static int TwoPassCallback( vlc_object_t
*, char const *, vlc_value_t
,
142 vlc_value_t
, void * );
146 /*****************************************************************************
148 *****************************************************************************/
149 static int Open( vlc_object_t
*p_this
)
151 filter_t
*p_filter
= (filter_t
*)p_this
;
153 /* Allocate structure */
154 filter_sys_t
*p_sys
= p_filter
->p_sys
= malloc( sizeof( *p_sys
) );
158 vlc_mutex_init( &p_sys
->lock
);
159 if( EqzInit( p_filter
, p_filter
->fmt_in
.audio
.i_rate
) != VLC_SUCCESS
)
161 vlc_mutex_destroy( &p_sys
->lock
);
166 p_filter
->fmt_in
.audio
.i_format
= VLC_CODEC_FL32
;
167 aout_FormatPrepare(&p_filter
->fmt_in
.audio
);
168 p_filter
->fmt_out
.audio
= p_filter
->fmt_in
.audio
;
169 p_filter
->pf_audio_filter
= DoWork
;
174 /*****************************************************************************
175 * Close: close the plugin
176 *****************************************************************************/
177 static void Close( vlc_object_t
*p_this
)
179 filter_t
*p_filter
= (filter_t
*)p_this
;
180 filter_sys_t
*p_sys
= p_filter
->p_sys
;
182 EqzClean( p_filter
);
183 vlc_mutex_destroy( &p_sys
->lock
);
187 /*****************************************************************************
188 * DoWork: process samples buffer
189 *****************************************************************************
191 *****************************************************************************/
192 static block_t
* DoWork( filter_t
* p_filter
, block_t
* p_in_buf
)
194 EqzFilter( p_filter
, (float*)p_in_buf
->p_buffer
,
195 (float*)p_in_buf
->p_buffer
, p_in_buf
->i_nb_samples
,
196 aout_FormatNbChannels( &p_filter
->fmt_in
.audio
) );
200 /*****************************************************************************
202 *****************************************************************************/
213 } band
[EQZ_BANDS_MAX
];
217 /* Equalizer coefficient calculation function based on equ-xmms */
218 static void EqzCoeffs( int i_rate
, float f_octave_percent
,
219 bool b_use_vlc_freqs
,
220 eqz_config_t
*p_eqz_config
)
222 const float *f_freq_table_10b
= b_use_vlc_freqs
223 ? f_vlc_frequency_table_10b
224 : f_iso_frequency_table_10b
;
225 float f_rate
= (float) i_rate
;
226 float f_nyquist_freq
= 0.5f
* f_rate
;
227 float f_octave_factor
= powf( 2.0f
, 0.5f
* f_octave_percent
);
228 float f_octave_factor_1
= 0.5f
* ( f_octave_factor
+ 1.0f
);
229 float f_octave_factor_2
= 0.5f
* ( f_octave_factor
- 1.0f
);
231 p_eqz_config
->i_band
= EQZ_BANDS_MAX
;
233 for( int i
= 0; i
< EQZ_BANDS_MAX
; i
++ )
235 float f_freq
= f_freq_table_10b
[i
];
237 p_eqz_config
->band
[i
].f_frequency
= f_freq
;
239 if( f_freq
<= f_nyquist_freq
)
241 float f_theta_1
= ( 2.0f
* (float) M_PI
* f_freq
) / f_rate
;
242 float f_theta_2
= f_theta_1
/ f_octave_factor
;
243 float f_sin
= sinf( f_theta_2
);
244 float f_sin_prd
= sinf( f_theta_2
* f_octave_factor_1
)
245 * sinf( f_theta_2
* f_octave_factor_2
);
246 float f_sin_hlf
= f_sin
* 0.5f
;
247 float f_den
= f_sin_hlf
+ f_sin_prd
;
249 p_eqz_config
->band
[i
].f_alpha
= f_sin_prd
/ f_den
;
250 p_eqz_config
->band
[i
].f_beta
= ( f_sin_hlf
- f_sin_prd
) / f_den
;
251 p_eqz_config
->band
[i
].f_gamma
= f_sin
* cosf( f_theta_1
) / f_den
;
255 /* Any frequency beyond the Nyquist frequency is no good... */
256 p_eqz_config
->band
[i
].f_alpha
=
257 p_eqz_config
->band
[i
].f_beta
=
258 p_eqz_config
->band
[i
].f_gamma
= 0.0f
;
263 static inline float EqzConvertdB( float db
)
266 * (we do as if the input of iir is /EQZ_IN_FACTOR, but in fact it's the non iir data that is *EQZ_IN_FACTOR)
267 * db = 20*log( out / in ) with out = in + amp*iir(i/EQZ_IN_FACTOR)
268 * or iir(i) == i for the center freq so
269 * db = 20*log( 1 + amp/EQZ_IN_FACTOR )
270 * -> amp = EQZ_IN_FACTOR*(10^(db/20) - 1)
275 else if( db
> 20.0f
)
277 return EQZ_IN_FACTOR
* ( powf( 10.0f
, db
/ 20.0f
) - 1.0f
);
280 static int EqzInit( filter_t
*p_filter
, int i_rate
)
282 filter_sys_t
*p_sys
= p_filter
->p_sys
;
285 vlc_value_t val1
, val2
, val3
;
286 vlc_object_t
*p_aout
= p_filter
->obj
.parent
;
287 int i_ret
= VLC_ENOMEM
;
289 bool b_vlcFreqs
= var_InheritBool( p_aout
, "equalizer-vlcfreqs" );
290 EqzCoeffs( i_rate
, 1.0f
, b_vlcFreqs
, &cfg
);
292 /* Create the static filter config */
293 p_sys
->i_band
= cfg
.i_band
;
294 p_sys
->f_alpha
= vlc_alloc( p_sys
->i_band
, sizeof(float) );
295 p_sys
->f_beta
= vlc_alloc( p_sys
->i_band
, sizeof(float) );
296 p_sys
->f_gamma
= vlc_alloc( p_sys
->i_band
, sizeof(float) );
297 if( !p_sys
->f_alpha
|| !p_sys
->f_beta
|| !p_sys
->f_gamma
)
300 for( i
= 0; i
< p_sys
->i_band
; i
++ )
302 p_sys
->f_alpha
[i
] = cfg
.band
[i
].f_alpha
;
303 p_sys
->f_beta
[i
] = cfg
.band
[i
].f_beta
;
304 p_sys
->f_gamma
[i
] = cfg
.band
[i
].f_gamma
;
307 /* Filter dyn config */
308 p_sys
->b_2eqz
= false;
309 p_sys
->f_gamp
= 1.0f
;
310 p_sys
->f_amp
= vlc_alloc( p_sys
->i_band
, sizeof(float) );
314 for( i
= 0; i
< p_sys
->i_band
; i
++ )
316 p_sys
->f_amp
[i
] = 0.0f
;
320 for( ch
= 0; ch
< 32; ch
++ )
325 p_sys
->x2
[ch
][1] = 0.0f
;
327 for( i
= 0; i
< p_sys
->i_band
; i
++ )
331 p_sys
->y2
[ch
][i
][0] =
332 p_sys
->y2
[ch
][i
][1] = 0.0f
;
336 var_Create( p_aout
, "equalizer-bands", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
337 var_Create( p_aout
, "equalizer-preset", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
339 p_sys
->b_2eqz
= var_CreateGetBool( p_aout
, "equalizer-2pass" );
341 var_Create( p_aout
, "equalizer-preamp", VLC_VAR_FLOAT
| VLC_VAR_DOINHERIT
);
343 /* Get initial values */
344 var_Get( p_aout
, "equalizer-preset", &val1
);
345 var_Get( p_aout
, "equalizer-bands", &val2
);
346 var_Get( p_aout
, "equalizer-preamp", &val3
);
348 /* Load the preset only if equalizer-bands is not set. */
349 if ( val2
.psz_string
== NULL
|| *val2
.psz_string
== '\0' )
350 PresetCallback( VLC_OBJECT( p_aout
), NULL
, val1
, val1
, p_sys
);
351 free( val1
.psz_string
);
352 BandsCallback( VLC_OBJECT( p_aout
), NULL
, val2
, val2
, p_sys
);
353 PreampCallback( VLC_OBJECT( p_aout
), NULL
, val3
, val3
, p_sys
);
355 /* Exit if we have no preset and no bands value */
356 if (!val2
.psz_string
|| !*val2
.psz_string
)
358 msg_Err(p_filter
, "No preset selected");
359 free( val2
.psz_string
);
360 free( p_sys
->f_amp
);
361 i_ret
= VLC_EGENERIC
;
364 free( val2
.psz_string
);
366 /* Add our own callbacks */
367 var_AddCallback( p_aout
, "equalizer-preset", PresetCallback
, p_sys
);
368 var_AddCallback( p_aout
, "equalizer-bands", BandsCallback
, p_sys
);
369 var_AddCallback( p_aout
, "equalizer-preamp", PreampCallback
, p_sys
);
370 var_AddCallback( p_aout
, "equalizer-2pass", TwoPassCallback
, p_sys
);
372 msg_Dbg( p_filter
, "equalizer loaded for %d Hz with %d bands %d pass",
373 i_rate
, p_sys
->i_band
, p_sys
->b_2eqz
? 2 : 1 );
374 for( i
= 0; i
< p_sys
->i_band
; i
++ )
376 msg_Dbg( p_filter
, " %.2f Hz -> factor:%f alpha:%f beta:%f gamma:%f",
377 cfg
.band
[i
].f_frequency
, p_sys
->f_amp
[i
],
378 p_sys
->f_alpha
[i
], p_sys
->f_beta
[i
], p_sys
->f_gamma
[i
]);
383 free( p_sys
->f_alpha
);
384 free( p_sys
->f_beta
);
385 free( p_sys
->f_gamma
);
389 static void EqzFilter( filter_t
*p_filter
, float *out
, float *in
,
390 int i_samples
, int i_channels
)
392 filter_sys_t
*p_sys
= p_filter
->p_sys
;
395 vlc_mutex_lock( &p_sys
->lock
);
396 for( i
= 0; i
< i_samples
; i
++ )
398 for( ch
= 0; ch
< i_channels
; ch
++ )
400 const float x
= in
[ch
];
403 for( j
= 0; j
< p_sys
->i_band
; j
++ )
405 float y
= p_sys
->f_alpha
[j
] * ( x
- p_sys
->x
[ch
][1] ) +
406 p_sys
->f_gamma
[j
] * p_sys
->y
[ch
][j
][0] -
407 p_sys
->f_beta
[j
] * p_sys
->y
[ch
][j
][1];
409 p_sys
->y
[ch
][j
][1] = p_sys
->y
[ch
][j
][0];
410 p_sys
->y
[ch
][j
][0] = y
;
412 o
+= y
* p_sys
->f_amp
[j
];
414 p_sys
->x
[ch
][1] = p_sys
->x
[ch
][0];
420 const float x2
= EQZ_IN_FACTOR
* x
+ o
;
422 for( j
= 0; j
< p_sys
->i_band
; j
++ )
424 float y
= p_sys
->f_alpha
[j
] * ( x2
- p_sys
->x2
[ch
][1] ) +
425 p_sys
->f_gamma
[j
] * p_sys
->y2
[ch
][j
][0] -
426 p_sys
->f_beta
[j
] * p_sys
->y2
[ch
][j
][1];
428 p_sys
->y2
[ch
][j
][1] = p_sys
->y2
[ch
][j
][0];
429 p_sys
->y2
[ch
][j
][0] = y
;
431 o
+= y
* p_sys
->f_amp
[j
];
433 p_sys
->x2
[ch
][1] = p_sys
->x2
[ch
][0];
434 p_sys
->x2
[ch
][0] = x2
;
436 /* We add source PCM + filtered PCM */
437 out
[ch
] = p_sys
->f_gamp
* p_sys
->f_gamp
*( EQZ_IN_FACTOR
* x2
+ o
);
441 /* We add source PCM + filtered PCM */
442 out
[ch
] = p_sys
->f_gamp
*( EQZ_IN_FACTOR
* x
+ o
);
449 vlc_mutex_unlock( &p_sys
->lock
);
452 static void EqzClean( filter_t
*p_filter
)
454 filter_sys_t
*p_sys
= p_filter
->p_sys
;
455 vlc_object_t
*p_aout
= p_filter
->obj
.parent
;
457 var_DelCallback( p_aout
, "equalizer-bands", BandsCallback
, p_sys
);
458 var_DelCallback( p_aout
, "equalizer-preset", PresetCallback
, p_sys
);
459 var_DelCallback( p_aout
, "equalizer-preamp", PreampCallback
, p_sys
);
460 var_DelCallback( p_aout
, "equalizer-2pass", TwoPassCallback
, p_sys
);
462 free( p_sys
->f_alpha
);
463 free( p_sys
->f_beta
);
464 free( p_sys
->f_gamma
);
466 free( p_sys
->f_amp
);
470 static int PresetCallback( vlc_object_t
*p_aout
, char const *psz_cmd
,
471 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
473 const eqz_preset_t
*preset
= NULL
;
474 const char *psz_preset
= newval
.psz_string
;
476 for( unsigned i
= 0; i
< NB_PRESETS
; i
++ )
477 if( !strcasecmp( eqz_preset_10b
[i
].psz_name
, psz_preset
) )
479 preset
= eqz_preset_10b
+ i
;
485 msg_Err( p_aout
, "equalizer preset '%s' not found", psz_preset
);
486 msg_Info( p_aout
, "full list:" );
487 for( unsigned i
= 0; i
< NB_PRESETS
; i
++ )
488 msg_Info( p_aout
, " - '%s'", eqz_preset_10b
[i
].psz_name
);
494 for( unsigned i
= 0; i
< EQZ_BANDS_MAX
; i
++ )
498 lldiv_t d
= lldiv( lroundf(preset
->f_amp
[i
] * 10000000.f
), 10000000 );
500 if( asprintf( &psz
, "%s %lld.%07llu", i
? bands
: "",
501 d
.quot
, d
.rem
) == -1 )
505 if( unlikely(psz
== NULL
) )
510 var_SetFloat( p_aout
, "equalizer-preamp", preset
->f_preamp
);
511 var_SetString( p_aout
, "equalizer-bands", bands
);
513 (void) psz_cmd
; (void) oldval
; (void) p_data
;
517 static int PreampCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
518 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
520 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
521 filter_sys_t
*p_sys
= p_data
;
524 if( newval
.f_float
< -20.f
)
526 else if( newval
.f_float
< 20.f
)
527 preamp
= powf( 10.f
, newval
.f_float
/ 20.f
);
531 vlc_mutex_lock( &p_sys
->lock
);
532 p_sys
->f_gamp
= preamp
;
533 vlc_mutex_unlock( &p_sys
->lock
);
537 static int BandsCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
538 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
540 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
541 filter_sys_t
*p_sys
= p_data
;
542 const char *p
= newval
.psz_string
;
545 /* Same thing for bands */
546 vlc_mutex_lock( &p_sys
->lock
);
547 while( i
< p_sys
->i_band
)
551 float f
= us_strtof( p
, &next
);
552 if( next
== p
|| isnan( f
) )
553 break; /* no conversion */
555 p_sys
->f_amp
[i
++] = EqzConvertdB( f
);
558 break; /* end of line */
561 while( i
< p_sys
->i_band
)
562 p_sys
->f_amp
[i
++] = EqzConvertdB( 0.f
);
563 vlc_mutex_unlock( &p_sys
->lock
);
566 static int TwoPassCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
567 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
569 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
570 filter_sys_t
*p_sys
= p_data
;
572 vlc_mutex_lock( &p_sys
->lock
);
573 p_sys
->b_2eqz
= newval
.b_bool
;
574 vlc_mutex_unlock( &p_sys
->lock
);