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 p_filter
->fmt_out
.audio
= p_filter
->fmt_in
.audio
;
168 p_filter
->pf_audio_filter
= DoWork
;
173 /*****************************************************************************
174 * Close: close the plugin
175 *****************************************************************************/
176 static void Close( vlc_object_t
*p_this
)
178 filter_t
*p_filter
= (filter_t
*)p_this
;
179 filter_sys_t
*p_sys
= p_filter
->p_sys
;
181 EqzClean( p_filter
);
182 vlc_mutex_destroy( &p_sys
->lock
);
186 /*****************************************************************************
187 * DoWork: process samples buffer
188 *****************************************************************************
190 *****************************************************************************/
191 static block_t
* DoWork( filter_t
* p_filter
, block_t
* p_in_buf
)
193 EqzFilter( p_filter
, (float*)p_in_buf
->p_buffer
,
194 (float*)p_in_buf
->p_buffer
, p_in_buf
->i_nb_samples
,
195 aout_FormatNbChannels( &p_filter
->fmt_in
.audio
) );
199 /*****************************************************************************
201 *****************************************************************************/
212 } band
[EQZ_BANDS_MAX
];
216 /* Equalizer coefficient calculation function based on equ-xmms */
217 static void EqzCoeffs( int i_rate
, float f_octave_percent
,
218 bool b_use_vlc_freqs
,
219 eqz_config_t
*p_eqz_config
)
221 const float *f_freq_table_10b
= b_use_vlc_freqs
222 ? f_vlc_frequency_table_10b
223 : f_iso_frequency_table_10b
;
224 float f_rate
= (float) i_rate
;
225 float f_nyquist_freq
= 0.5f
* f_rate
;
226 float f_octave_factor
= powf( 2.0f
, 0.5f
* f_octave_percent
);
227 float f_octave_factor_1
= 0.5f
* ( f_octave_factor
+ 1.0f
);
228 float f_octave_factor_2
= 0.5f
* ( f_octave_factor
- 1.0f
);
230 p_eqz_config
->i_band
= EQZ_BANDS_MAX
;
232 for( int i
= 0; i
< EQZ_BANDS_MAX
; i
++ )
234 float f_freq
= f_freq_table_10b
[i
];
236 p_eqz_config
->band
[i
].f_frequency
= f_freq
;
238 if( f_freq
<= f_nyquist_freq
)
240 float f_theta_1
= ( 2.0f
* (float) M_PI
* f_freq
) / f_rate
;
241 float f_theta_2
= f_theta_1
/ f_octave_factor
;
242 float f_sin
= sinf( f_theta_2
);
243 float f_sin_prd
= sinf( f_theta_2
* f_octave_factor_1
)
244 * sinf( f_theta_2
* f_octave_factor_2
);
245 float f_sin_hlf
= f_sin
* 0.5f
;
246 float f_den
= f_sin_hlf
+ f_sin_prd
;
248 p_eqz_config
->band
[i
].f_alpha
= f_sin_prd
/ f_den
;
249 p_eqz_config
->band
[i
].f_beta
= ( f_sin_hlf
- f_sin_prd
) / f_den
;
250 p_eqz_config
->band
[i
].f_gamma
= f_sin
* cosf( f_theta_1
) / f_den
;
254 /* Any frequency beyond the Nyquist frequency is no good... */
255 p_eqz_config
->band
[i
].f_alpha
=
256 p_eqz_config
->band
[i
].f_beta
=
257 p_eqz_config
->band
[i
].f_gamma
= 0.0f
;
262 static inline float EqzConvertdB( float db
)
265 * (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)
266 * db = 20*log( out / in ) with out = in + amp*iir(i/EQZ_IN_FACTOR)
267 * or iir(i) == i for the center freq so
268 * db = 20*log( 1 + amp/EQZ_IN_FACTOR )
269 * -> amp = EQZ_IN_FACTOR*(10^(db/20) - 1)
274 else if( db
> 20.0f
)
276 return EQZ_IN_FACTOR
* ( powf( 10.0f
, db
/ 20.0f
) - 1.0f
);
279 static int EqzInit( filter_t
*p_filter
, int i_rate
)
281 filter_sys_t
*p_sys
= p_filter
->p_sys
;
284 vlc_value_t val1
, val2
, val3
;
285 vlc_object_t
*p_aout
= p_filter
->p_parent
;
286 int i_ret
= VLC_ENOMEM
;
288 bool b_vlcFreqs
= var_InheritBool( p_aout
, "equalizer-vlcfreqs" );
289 EqzCoeffs( i_rate
, 1.0f
, b_vlcFreqs
, &cfg
);
291 /* Create the static filter config */
292 p_sys
->i_band
= cfg
.i_band
;
293 p_sys
->f_alpha
= malloc( p_sys
->i_band
* sizeof(float) );
294 p_sys
->f_beta
= malloc( p_sys
->i_band
* sizeof(float) );
295 p_sys
->f_gamma
= malloc( p_sys
->i_band
* sizeof(float) );
296 if( !p_sys
->f_alpha
|| !p_sys
->f_beta
|| !p_sys
->f_gamma
)
299 for( i
= 0; i
< p_sys
->i_band
; i
++ )
301 p_sys
->f_alpha
[i
] = cfg
.band
[i
].f_alpha
;
302 p_sys
->f_beta
[i
] = cfg
.band
[i
].f_beta
;
303 p_sys
->f_gamma
[i
] = cfg
.band
[i
].f_gamma
;
306 /* Filter dyn config */
307 p_sys
->b_2eqz
= false;
308 p_sys
->f_gamp
= 1.0f
;
309 p_sys
->f_amp
= malloc( p_sys
->i_band
* sizeof(float) );
313 for( i
= 0; i
< p_sys
->i_band
; i
++ )
315 p_sys
->f_amp
[i
] = 0.0f
;
319 for( ch
= 0; ch
< 32; ch
++ )
324 p_sys
->x2
[ch
][1] = 0.0f
;
326 for( i
= 0; i
< p_sys
->i_band
; i
++ )
330 p_sys
->y2
[ch
][i
][0] =
331 p_sys
->y2
[ch
][i
][1] = 0.0f
;
335 var_Create( p_aout
, "equalizer-bands", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
336 var_Create( p_aout
, "equalizer-preset", VLC_VAR_STRING
| VLC_VAR_DOINHERIT
);
338 p_sys
->b_2eqz
= var_CreateGetBool( p_aout
, "equalizer-2pass" );
340 var_Create( p_aout
, "equalizer-preamp", VLC_VAR_FLOAT
| VLC_VAR_DOINHERIT
);
342 /* Get initial values */
343 var_Get( p_aout
, "equalizer-preset", &val1
);
344 var_Get( p_aout
, "equalizer-bands", &val2
);
345 var_Get( p_aout
, "equalizer-preamp", &val3
);
347 /* Load the preset only if equalizer-bands is not set. */
348 if (val2
.psz_string
!= NULL
&& *val2
.psz_string
!= "\0")
349 PresetCallback( VLC_OBJECT( p_aout
), NULL
, val1
, val1
, p_sys
);
350 free( val1
.psz_string
);
351 BandsCallback( VLC_OBJECT( p_aout
), NULL
, val2
, val2
, p_sys
);
352 PreampCallback( VLC_OBJECT( p_aout
), NULL
, val3
, val3
, p_sys
);
354 /* Exit if we have no preset and no bands value */
355 if (!val2
.psz_string
|| !*val2
.psz_string
)
357 msg_Err(p_filter
, "No preset selected");
358 free( val2
.psz_string
);
359 free( p_sys
->f_amp
);
360 i_ret
= VLC_EGENERIC
;
363 free( val2
.psz_string
);
365 /* Add our own callbacks */
366 var_AddCallback( p_aout
, "equalizer-preset", PresetCallback
, p_sys
);
367 var_AddCallback( p_aout
, "equalizer-bands", BandsCallback
, p_sys
);
368 var_AddCallback( p_aout
, "equalizer-preamp", PreampCallback
, p_sys
);
369 var_AddCallback( p_aout
, "equalizer-2pass", TwoPassCallback
, p_sys
);
371 msg_Dbg( p_filter
, "equalizer loaded for %d Hz with %d bands %d pass",
372 i_rate
, p_sys
->i_band
, p_sys
->b_2eqz
? 2 : 1 );
373 for( i
= 0; i
< p_sys
->i_band
; i
++ )
375 msg_Dbg( p_filter
, " %.2f Hz -> factor:%f alpha:%f beta:%f gamma:%f",
376 cfg
.band
[i
].f_frequency
, p_sys
->f_amp
[i
],
377 p_sys
->f_alpha
[i
], p_sys
->f_beta
[i
], p_sys
->f_gamma
[i
]);
382 free( p_sys
->f_alpha
);
383 free( p_sys
->f_beta
);
384 free( p_sys
->f_gamma
);
388 static void EqzFilter( filter_t
*p_filter
, float *out
, float *in
,
389 int i_samples
, int i_channels
)
391 filter_sys_t
*p_sys
= p_filter
->p_sys
;
394 vlc_mutex_lock( &p_sys
->lock
);
395 for( i
= 0; i
< i_samples
; i
++ )
397 for( ch
= 0; ch
< i_channels
; ch
++ )
399 const float x
= in
[ch
];
402 for( j
= 0; j
< p_sys
->i_band
; j
++ )
404 float y
= p_sys
->f_alpha
[j
] * ( x
- p_sys
->x
[ch
][1] ) +
405 p_sys
->f_gamma
[j
] * p_sys
->y
[ch
][j
][0] -
406 p_sys
->f_beta
[j
] * p_sys
->y
[ch
][j
][1];
408 p_sys
->y
[ch
][j
][1] = p_sys
->y
[ch
][j
][0];
409 p_sys
->y
[ch
][j
][0] = y
;
411 o
+= y
* p_sys
->f_amp
[j
];
413 p_sys
->x
[ch
][1] = p_sys
->x
[ch
][0];
419 const float x2
= EQZ_IN_FACTOR
* x
+ o
;
421 for( j
= 0; j
< p_sys
->i_band
; j
++ )
423 float y
= p_sys
->f_alpha
[j
] * ( x2
- p_sys
->x2
[ch
][1] ) +
424 p_sys
->f_gamma
[j
] * p_sys
->y2
[ch
][j
][0] -
425 p_sys
->f_beta
[j
] * p_sys
->y2
[ch
][j
][1];
427 p_sys
->y2
[ch
][j
][1] = p_sys
->y2
[ch
][j
][0];
428 p_sys
->y2
[ch
][j
][0] = y
;
430 o
+= y
* p_sys
->f_amp
[j
];
432 p_sys
->x2
[ch
][1] = p_sys
->x2
[ch
][0];
433 p_sys
->x2
[ch
][0] = x2
;
435 /* We add source PCM + filtered PCM */
436 out
[ch
] = p_sys
->f_gamp
* p_sys
->f_gamp
*( EQZ_IN_FACTOR
* x2
+ o
);
440 /* We add source PCM + filtered PCM */
441 out
[ch
] = p_sys
->f_gamp
*( EQZ_IN_FACTOR
* x
+ o
);
448 vlc_mutex_unlock( &p_sys
->lock
);
451 static void EqzClean( filter_t
*p_filter
)
453 filter_sys_t
*p_sys
= p_filter
->p_sys
;
454 vlc_object_t
*p_aout
= p_filter
->p_parent
;
456 var_DelCallback( p_aout
, "equalizer-bands", BandsCallback
, p_sys
);
457 var_DelCallback( p_aout
, "equalizer-preset", PresetCallback
, p_sys
);
458 var_DelCallback( p_aout
, "equalizer-preamp", PreampCallback
, p_sys
);
459 var_DelCallback( p_aout
, "equalizer-2pass", TwoPassCallback
, p_sys
);
461 free( p_sys
->f_alpha
);
462 free( p_sys
->f_beta
);
463 free( p_sys
->f_gamma
);
465 free( p_sys
->f_amp
);
469 static int PresetCallback( vlc_object_t
*p_aout
, char const *psz_cmd
,
470 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
472 const eqz_preset_t
*preset
= NULL
;
473 const char *psz_preset
= newval
.psz_string
;
475 for( unsigned i
= 0; i
< NB_PRESETS
; i
++ )
476 if( !strcasecmp( eqz_preset_10b
[i
].psz_name
, psz_preset
) )
478 preset
= eqz_preset_10b
+ i
;
484 msg_Err( p_aout
, "equalizer preset '%s' not found", psz_preset
);
485 msg_Info( p_aout
, "full list:" );
486 for( unsigned i
= 0; i
< NB_PRESETS
; i
++ )
487 msg_Info( p_aout
, " - '%s'", eqz_preset_10b
[i
].psz_name
);
493 for( unsigned i
= 0; i
< EQZ_BANDS_MAX
; i
++ )
497 lldiv_t d
= lldiv( lroundf(preset
->f_amp
[i
] * 10000000.f
), 10000000 );
499 if( asprintf( &psz
, "%s %lld.%07llu", i
? bands
: "",
500 d
.quot
, d
.rem
) == -1 )
504 if( unlikely(psz
== NULL
) )
509 var_SetFloat( p_aout
, "equalizer-preamp", preset
->f_preamp
);
510 var_SetString( p_aout
, "equalizer-bands", bands
);
512 (void) psz_cmd
; (void) oldval
; (void) p_data
;
516 static int PreampCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
517 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
519 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
520 filter_sys_t
*p_sys
= p_data
;
523 if( newval
.f_float
< -20.f
)
525 else if( newval
.f_float
< 20.f
)
526 preamp
= powf( 10.f
, newval
.f_float
/ 20.f
);
530 vlc_mutex_lock( &p_sys
->lock
);
531 p_sys
->f_gamp
= preamp
;
532 vlc_mutex_unlock( &p_sys
->lock
);
536 static int BandsCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
537 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
539 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
540 filter_sys_t
*p_sys
= p_data
;
541 const char *p
= newval
.psz_string
;
544 /* Same thing for bands */
545 vlc_mutex_lock( &p_sys
->lock
);
546 while( i
< p_sys
->i_band
)
550 float f
= us_strtof( p
, &next
);
551 if( next
== p
|| isnan( f
) )
552 break; /* no conversion */
554 p_sys
->f_amp
[i
++] = EqzConvertdB( f
);
557 break; /* end of line */
560 while( i
< p_sys
->i_band
)
561 p_sys
->f_amp
[i
++] = EqzConvertdB( 0.f
);
562 vlc_mutex_unlock( &p_sys
->lock
);
565 static int TwoPassCallback( vlc_object_t
*p_this
, char const *psz_cmd
,
566 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
568 VLC_UNUSED(p_this
); VLC_UNUSED(psz_cmd
); VLC_UNUSED(oldval
);
569 filter_sys_t
*p_sys
= p_data
;
571 vlc_mutex_lock( &p_sys
->lock
);
572 p_sys
->b_2eqz
= newval
.b_bool
;
573 vlc_mutex_unlock( &p_sys
->lock
);