equalizer: load the equalizer-preset only if equalizer-bands is not set
[vlc.git] / modules / audio_filter / equalizer.c
blobf8ca033520668e5bee6fb1f47b75b66d5cfb2201
1 /*****************************************************************************
2 * equalizer.c:
3 *****************************************************************************
4 * Copyright (C) 2004-2012 VLC authors and VideoLAN
5 * $Id$
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 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <math.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_charset.h>
38 #include <vlc_aout.h>
39 #include <vlc_filter.h>
41 #include "equalizer_presets.h"
43 /* TODO:
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
49 * - ...
52 /*****************************************************************************
53 * Module descriptor
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 " \
70 "frequency bands." )
72 #define TWOPASS_TEXT N_( "Two pass" )
73 #define TWOPASS_LONGTEXT N_( "Filter the audio twice. This provides a more " \
74 "intense effect.")
76 #define PREAMP_TEXT N_("Global gain" )
77 #define PREAMP_LONGTEXT N_("Set the global gain in dB (-20 ... 20)." )
79 vlc_module_begin ()
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" )
99 vlc_module_end ()
101 /*****************************************************************************
102 * Local prototypes
103 *****************************************************************************/
104 struct filter_sys_t
106 /* Filter static config */
107 int i_band;
108 float *f_alpha;
109 float *f_beta;
110 float *f_gamma;
112 /* Filter dyn config */
113 float *f_amp; /* Per band amp */
114 float f_gamp; /* Global preamp */
115 bool b_2eqz;
117 /* Filter state */
118 float x[32][2];
119 float y[32][128][2];
121 /* Second filter state */
122 float x2[32][2];
123 float y2[32][128][2];
125 vlc_mutex_t lock;
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 /*****************************************************************************
147 * Open:
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 ) );
155 if( !p_sys )
156 return VLC_ENOMEM;
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 );
162 free( p_sys );
163 return VLC_EGENERIC;
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;
170 return VLC_SUCCESS;
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 );
183 free( p_sys );
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 ) );
196 return p_in_buf;
199 /*****************************************************************************
200 * Equalizer stuff
201 *****************************************************************************/
202 typedef struct
204 int i_band;
206 struct
208 float f_frequency;
209 float f_alpha;
210 float f_beta;
211 float f_gamma;
212 } band[EQZ_BANDS_MAX];
214 } eqz_config_t;
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;
252 else
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 )
264 /* Map it to gain,
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)
272 if( db < -20.0f )
273 db = -20.0f;
274 else if( db > 20.0f )
275 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;
282 eqz_config_t cfg;
283 int i, ch;
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 )
297 goto error;
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) );
310 if( !p_sys->f_amp )
311 goto error;
313 for( i = 0; i < p_sys->i_band; i++ )
315 p_sys->f_amp[i] = 0.0f;
318 /* Filter state */
319 for( ch = 0; ch < 32; ch++ )
321 p_sys->x[ch][0] =
322 p_sys->x[ch][1] =
323 p_sys->x2[ch][0] =
324 p_sys->x2[ch][1] = 0.0f;
326 for( i = 0; i < p_sys->i_band; i++ )
328 p_sys->y[ch][i][0] =
329 p_sys->y[ch][i][1] =
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;
361 goto error;
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]);
379 return VLC_SUCCESS;
381 error:
382 free( p_sys->f_alpha );
383 free( p_sys->f_beta );
384 free( p_sys->f_gamma );
385 return i_ret;
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;
392 int i, ch, j;
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];
400 float o = 0.0f;
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];
414 p_sys->x[ch][0] = x;
416 /* Second filter */
417 if( p_sys->b_2eqz )
419 const float x2 = EQZ_IN_FACTOR * x + o;
420 o = 0.0f;
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 );
438 else
440 /* We add source PCM + filtered PCM */
441 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o );
445 in += i_channels;
446 out += i_channels;
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;
479 break;
482 if( preset == NULL )
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 );
488 return VLC_EGENERIC;
491 char *bands = NULL;
493 for( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
495 char *psz;
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 )
501 psz = NULL;
503 free( bands );
504 if( unlikely(psz == NULL) )
505 return VLC_ENOMEM;
506 bands = psz;
509 var_SetFloat( p_aout, "equalizer-preamp", preset->f_preamp );
510 var_SetString( p_aout, "equalizer-bands", bands );
511 free( bands );
512 (void) psz_cmd; (void) oldval; (void) p_data;
513 return VLC_SUCCESS;
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;
521 float preamp;
523 if( newval.f_float < -20.f )
524 preamp = .1f;
525 else if( newval.f_float < 20.f )
526 preamp = powf( 10.f, newval.f_float / 20.f );
527 else
528 preamp = 10.f;
530 vlc_mutex_lock( &p_sys->lock );
531 p_sys->f_gamp = preamp;
532 vlc_mutex_unlock( &p_sys->lock );
533 return VLC_SUCCESS;
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;
542 int i = 0;
544 /* Same thing for bands */
545 vlc_mutex_lock( &p_sys->lock );
546 while( i < p_sys->i_band )
548 char *next;
549 /* Read dB -20/20 */
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 );
556 if( *next == '\0' )
557 break; /* end of line */
558 p = &next[1];
560 while( i < p_sys->i_band )
561 p_sys->f_amp[i++] = EqzConvertdB( 0.f );
562 vlc_mutex_unlock( &p_sys->lock );
563 return VLC_SUCCESS;
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 );
574 return VLC_SUCCESS;