1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 2004-2012 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, 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.0, PREAMP_TEXT,
96 PREAMP_LONGTEXT, true )
97 set_callbacks( Open, Close )
98 add_shortcut( "equalizer" )
101 /*****************************************************************************
103 *****************************************************************************/
106 /* Filter static config */
116 /* Filter dyn config */
117 float *f_amp; /* Per band amp */
118 float f_gamp; /* Global preamp */
125 /* Second filter state */
127 float y2[32][128][2];
132 static block_t *DoWork( filter_t *, block_t * );
134 #define EQZ_IN_FACTOR (0.25)
135 static int EqzInit( filter_t *, int );
136 static void EqzFilter( filter_t *, float *, float *, int, int );
137 static void EqzClean( filter_t * );
139 static int PresetCallback ( vlc_object_t *, char const *, vlc_value_t,
140 vlc_value_t, void * );
141 static int PreampCallback ( vlc_object_t *, char const *, vlc_value_t,
142 vlc_value_t, void * );
143 static int BandsCallback ( vlc_object_t *, char const *, vlc_value_t,
144 vlc_value_t, void * );
145 static int TwoPassCallback( vlc_object_t *, char const *, vlc_value_t,
146 vlc_value_t, void * );
150 /*****************************************************************************
152 *****************************************************************************/
153 static int Open( vlc_object_t *p_this )
155 filter_t *p_filter = (filter_t *)p_this;
158 if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
159 p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
161 p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
162 p_filter->fmt_out.audio.i_format = VLC_CODEC_FL32;
163 msg_Warn( p_filter, "bad input or output format" );
166 if ( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) )
168 memcpy( &p_filter->fmt_out.audio, &p_filter->fmt_in.audio,
169 sizeof(audio_sample_format_t) );
170 msg_Warn( p_filter, "input and output formats are not similar" );
174 p_filter->pf_audio_filter = DoWork;
176 /* Allocate structure */
177 p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
181 vlc_mutex_init( &p_sys->lock );
182 if( EqzInit( p_filter, p_filter->fmt_in.audio.i_rate ) != VLC_SUCCESS )
184 vlc_mutex_destroy( &p_sys->lock );
192 /*****************************************************************************
193 * Close: close the plugin
194 *****************************************************************************/
195 static void Close( vlc_object_t *p_this )
197 filter_t *p_filter = (filter_t *)p_this;
198 filter_sys_t *p_sys = p_filter->p_sys;
200 EqzClean( p_filter );
201 vlc_mutex_destroy( &p_sys->lock );
205 /*****************************************************************************
206 * DoWork: process samples buffer
207 *****************************************************************************
209 *****************************************************************************/
210 static block_t * DoWork( filter_t * p_filter, block_t * p_in_buf )
212 EqzFilter( p_filter, (float*)p_in_buf->p_buffer,
213 (float*)p_in_buf->p_buffer, p_in_buf->i_nb_samples,
214 aout_FormatNbChannels( &p_filter->fmt_in.audio ) );
218 /*****************************************************************************
220 *****************************************************************************/
231 } band[EQZ_BANDS_MAX];
235 /* The frequency tables */
236 static const float f_vlc_frequency_table_10b[EQZ_BANDS_MAX] =
238 60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000,
241 static const float f_iso_frequency_table_10b[EQZ_BANDS_MAX] =
243 31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, 16000,
246 /* Equalizer coefficient calculation function based on equ-xmms */
247 static void EqzCoeffs( int i_rate, float f_octave_percent,
248 bool b_use_vlc_freqs,
249 eqz_config_t *p_eqz_config )
251 const float *f_freq_table_10b = b_use_vlc_freqs
252 ? f_vlc_frequency_table_10b
253 : f_iso_frequency_table_10b;
254 float f_rate = (float) i_rate;
255 float f_nyquist_freq = 0.5 * f_rate;
256 float f_octave_factor = pow( 2.0, 0.5 * f_octave_percent );
257 float f_octave_factor_1 = 0.5 * ( f_octave_factor + 1.0 );
258 float f_octave_factor_2 = 0.5 * ( f_octave_factor - 1.0 );
260 p_eqz_config->i_band = EQZ_BANDS_MAX;
262 for( int i = 0; i < EQZ_BANDS_MAX; i++ )
264 float f_freq = f_freq_table_10b[i];
266 p_eqz_config->band[i].f_frequency = f_freq;
268 if( f_freq <= f_nyquist_freq )
270 float f_theta_1 = ( 2.0 * M_PI * f_freq ) / f_rate;
271 float f_theta_2 = f_theta_1 / f_octave_factor;
272 float f_sin = sin( f_theta_2 ) * 0.5;
273 float f_sin_prd = sin( f_theta_2 * f_octave_factor_1 )
274 * sin( f_theta_2 * f_octave_factor_2 );
275 /* The equation from equ-xmms simplifies to something similar to
276 * this when you restrict the domain to all valid frequencies at or
277 * below the Nyquist frequency (the interval 0 <= f_theta_1 <= Pi).
278 * (This result for the root is twice that returned by equ-xmms,
279 * but the more efficient calculations for alpha, beta, and gamma
280 * below compensate for this.) */
281 float f_root = ( f_sin - f_sin_prd ) / ( f_sin + f_sin_prd );
283 p_eqz_config->band[i].f_alpha = ( 1.0 - f_root ) * 0.5;
284 p_eqz_config->band[i].f_beta = f_root;
285 p_eqz_config->band[i].f_gamma = ( 1.0 + f_root ) * cos( f_theta_1 );
289 /* Any frequency beyond the Nyquist frequency is no good... */
290 p_eqz_config->band[i].f_alpha =
291 p_eqz_config->band[i].f_beta =
292 p_eqz_config->band[i].f_gamma = 0.0;
297 static inline float EqzConvertdB( float db )
300 * (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)
301 * db = 20*log( out / in ) with out = in + amp*iir(i/EQZ_IN_FACTOR)
302 * or iir(i) == i for the center freq so
303 * db = 20*log( 1 + amp/EQZ_IN_FACTOR )
304 * -> amp = EQZ_IN_FACTOR*(10^(db/20) - 1)
311 return EQZ_IN_FACTOR * ( pow( 10, db / 20.0 ) - 1.0 );
314 static int EqzInit( filter_t *p_filter, int i_rate )
316 filter_sys_t *p_sys = p_filter->p_sys;
319 vlc_value_t val1, val2, val3;
320 vlc_object_t *p_aout = p_filter->p_parent;
321 int i_ret = VLC_ENOMEM;
323 bool b_vlcFreqs = var_InheritBool( p_aout, "equalizer-vlcfreqs" );
324 EqzCoeffs( i_rate, 1.0, b_vlcFreqs, &cfg );
326 /* Create the static filter config */
327 p_sys->i_band = cfg.i_band;
328 p_sys->f_alpha = malloc( p_sys->i_band * sizeof(float) );
329 p_sys->f_beta = malloc( p_sys->i_band * sizeof(float) );
330 p_sys->f_gamma = malloc( p_sys->i_band * sizeof(float) );
331 if( !p_sys->f_alpha || !p_sys->f_beta || !p_sys->f_gamma )
334 for( i = 0; i < p_sys->i_band; i++ )
336 p_sys->f_alpha[i] = cfg.band[i].f_alpha;
337 p_sys->f_beta[i] = cfg.band[i].f_beta;
338 p_sys->f_gamma[i] = cfg.band[i].f_gamma;
341 /* Filter dyn config */
342 p_sys->b_2eqz = false;
344 p_sys->f_amp = malloc( p_sys->i_band * sizeof(float) );
348 for( i = 0; i < p_sys->i_band; i++ )
350 p_sys->f_amp[i] = 0.0;
354 for( ch = 0; ch < 32; ch++ )
359 p_sys->x2[ch][1] = 0.0;
361 for( i = 0; i < p_sys->i_band; i++ )
365 p_sys->y2[ch][i][0] =
366 p_sys->y2[ch][i][1] = 0.0;
370 var_Create( p_aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
371 var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
373 p_sys->b_2eqz = var_CreateGetBool( p_aout, "equalizer-2pass" );
375 var_Create( p_aout, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
377 /* Get initial values */
378 var_Get( p_aout, "equalizer-preset", &val1 );
379 var_Get( p_aout, "equalizer-bands", &val2 );
380 var_Get( p_aout, "equalizer-preamp", &val3 );
382 p_sys->b_first = true;
383 PresetCallback( VLC_OBJECT( p_aout ), NULL, val1, val1, p_sys );
384 BandsCallback( VLC_OBJECT( p_aout ), NULL, val2, val2, p_sys );
385 PreampCallback( VLC_OBJECT( p_aout ), NULL, val3, val3, p_sys );
386 p_sys->b_first = false;
388 free( val1.psz_string );
390 /* Register preset bands (for intf) if : */
391 /* We have no bands info --> the preset info must be given to the intf */
392 /* or The bands info matches the preset */
393 if (p_sys->psz_newbands == NULL)
395 msg_Err(p_filter, "No preset selected");
396 free( val2.psz_string );
397 free( p_sys->f_amp );
398 i_ret = VLC_EGENERIC;
401 if( ( *(val2.psz_string) &&
402 strstr( p_sys->psz_newbands, val2.psz_string ) ) || !*val2.psz_string )
404 var_SetString( p_aout, "equalizer-bands", p_sys->psz_newbands );
405 if( p_sys->f_newpreamp == p_sys->f_gamp )
406 var_SetFloat( p_aout, "equalizer-preamp", p_sys->f_newpreamp );
408 free( val2.psz_string );
410 /* Add our own callbacks */
411 var_AddCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
412 var_AddCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
413 var_AddCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
414 var_AddCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
416 msg_Dbg( p_filter, "equalizer loaded for %d Hz with %d bands %d pass",
417 i_rate, p_sys->i_band, p_sys->b_2eqz ? 2 : 1 );
418 for( i = 0; i < p_sys->i_band; i++ )
420 msg_Dbg( p_filter, " %d Hz -> factor:%f alpha:%f beta:%f gamma:%f",
421 (int)cfg.band[i].f_frequency, p_sys->f_amp[i],
422 p_sys->f_alpha[i], p_sys->f_beta[i], p_sys->f_gamma[i]);
427 free( p_sys->f_alpha );
428 free( p_sys->f_beta );
429 free( p_sys->f_gamma );
433 static void EqzFilter( filter_t *p_filter, float *out, float *in,
434 int i_samples, int i_channels )
436 filter_sys_t *p_sys = p_filter->p_sys;
439 vlc_mutex_lock( &p_sys->lock );
440 for( i = 0; i < i_samples; i++ )
442 for( ch = 0; ch < i_channels; ch++ )
444 const float x = in[ch];
447 for( j = 0; j < p_sys->i_band; j++ )
449 float y = p_sys->f_alpha[j] * ( x - p_sys->x[ch][1] ) +
450 p_sys->f_gamma[j] * p_sys->y[ch][j][0] -
451 p_sys->f_beta[j] * p_sys->y[ch][j][1];
453 p_sys->y[ch][j][1] = p_sys->y[ch][j][0];
454 p_sys->y[ch][j][0] = y;
456 o += y * p_sys->f_amp[j];
458 p_sys->x[ch][1] = p_sys->x[ch][0];
464 const float x2 = EQZ_IN_FACTOR * x + o;
466 for( j = 0; j < p_sys->i_band; j++ )
468 float y = p_sys->f_alpha[j] * ( x2 - p_sys->x2[ch][1] ) +
469 p_sys->f_gamma[j] * p_sys->y2[ch][j][0] -
470 p_sys->f_beta[j] * p_sys->y2[ch][j][1];
472 p_sys->y2[ch][j][1] = p_sys->y2[ch][j][0];
473 p_sys->y2[ch][j][0] = y;
475 o += y * p_sys->f_amp[j];
477 p_sys->x2[ch][1] = p_sys->x2[ch][0];
478 p_sys->x2[ch][0] = x2;
480 /* We add source PCM + filtered PCM */
481 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x2 + o );
485 /* We add source PCM + filtered PCM */
486 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o );
493 vlc_mutex_unlock( &p_sys->lock );
496 static void EqzClean( filter_t *p_filter )
498 filter_sys_t *p_sys = p_filter->p_sys;
499 vlc_object_t *p_aout = p_filter->p_parent;
501 var_DelCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
502 var_DelCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
503 var_DelCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
504 var_DelCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
506 free( p_sys->f_alpha );
507 free( p_sys->f_beta );
508 free( p_sys->f_gamma );
510 free( p_sys->f_amp );
511 free( p_sys->psz_newbands );
515 static int PresetCallback( vlc_object_t *p_aout, char const *psz_cmd,
516 vlc_value_t oldval, vlc_value_t newval, void *p_data )
518 VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
519 filter_sys_t *p_sys = p_data;
521 const char *psz_preset = newval.psz_string;
523 vlc_mutex_lock( &p_sys->lock );
524 if( !*psz_preset || p_sys->i_band != 10 )
526 vlc_mutex_unlock( &p_sys->lock );
530 for( unsigned i = 0; i < NB_PRESETS; i++ )
532 if( !strcasecmp( eqz_preset_10b[i].psz_name, psz_preset ) )
534 char *psz_newbands = NULL;
536 p_sys->f_gamp *= pow( 10, eqz_preset_10b[i].f_preamp / 20.0 );
537 for( int j = 0; j < p_sys->i_band; j++ )
542 p_sys->f_amp[j] = EqzConvertdB( eqz_preset_10b[i].f_amp[j] );
543 d = lldiv( eqz_preset_10b[i].f_amp[j] * 10000000, 10000000 );
544 if( asprintf( &psz, "%s %lld.%07llu",
545 psz_newbands ? psz_newbands : "",
546 d.quot, d.rem ) == -1 )
548 free( psz_newbands );
549 vlc_mutex_unlock( &p_sys->lock );
552 free( psz_newbands );
555 if( !p_sys->b_first )
557 vlc_mutex_unlock( &p_sys->lock );
558 var_SetString( p_aout, "equalizer-bands", psz_newbands );
559 var_SetFloat( p_aout, "equalizer-preamp",
560 eqz_preset_10b[i].f_preamp );
561 free( psz_newbands );
565 p_sys->psz_newbands = psz_newbands;
566 p_sys->f_newpreamp = eqz_preset_10b[i].f_preamp;
567 vlc_mutex_unlock( &p_sys->lock );
572 vlc_mutex_unlock( &p_sys->lock );
573 msg_Err( p_aout, "equalizer preset '%s' not found", psz_preset );
574 msg_Info( p_aout, "full list:" );
575 for( unsigned i = 0; i < NB_PRESETS; i++ )
576 msg_Info( p_aout, " - '%s'", eqz_preset_10b[i].psz_name );
580 static int PreampCallback( vlc_object_t *p_this, char const *psz_cmd,
581 vlc_value_t oldval, vlc_value_t newval, void *p_data )
583 VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
584 filter_sys_t *p_sys = p_data;
586 if( newval.f_float < -20.0 )
587 newval.f_float = -20.0;
588 else if( newval.f_float > 20.0 )
589 newval.f_float = 20.0;
591 vlc_mutex_lock( &p_sys->lock );
592 p_sys->f_gamp = pow( 10, newval.f_float /20.0);
593 vlc_mutex_unlock( &p_sys->lock );
598 static int BandsCallback( vlc_object_t *p_this, char const *psz_cmd,
599 vlc_value_t oldval, vlc_value_t newval, void *p_data )
601 VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
602 filter_sys_t *p_sys = p_data;
603 const char *psz_bands = newval.psz_string;
604 const char *p = psz_bands;
607 /* Same thing for bands */
608 vlc_mutex_lock( &p_sys->lock );
609 for( int i = 0; i < p_sys->i_band; i++ )
613 if( *psz_bands == '\0' )
617 f = us_strtof( p, &psz_next );
620 break; /* no conversion */
622 p_sys->f_amp[i] = EqzConvertdB( f );
624 if( *psz_next == '\0' )
625 break; /* end of line */
628 vlc_mutex_unlock( &p_sys->lock );
631 static int TwoPassCallback( vlc_object_t *p_this, char const *psz_cmd,
632 vlc_value_t oldval, vlc_value_t newval, void *p_data )
634 VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
635 filter_sys_t *p_sys = p_data;
637 vlc_mutex_lock( &p_sys->lock );
638 p_sys->b_2eqz = newval.b_bool;
639 vlc_mutex_unlock( &p_sys->lock );