00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdlib.h>
00028 #include <math.h>
00029
00030 #include <vlc/vlc.h>
00031
00032 #include <vlc/aout.h>
00033 #include "aout_internal.h"
00034
00035 #include "equalizer_presets.h"
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 static int Open ( vlc_object_t * );
00050 static void Close( vlc_object_t * );
00051
00052 #define PRESET_TEXT N_( "Equalizer preset" )
00053 #define PRESET_LONGTEXT PRESET_TEXT
00054
00055 #define BANDS_TEXT N_( "Bands gain")
00056 #define BANDS_LONGTEXT N_( "Override preset bands gain in dB (-20 ... 20)" )
00057
00058 #define TWOPASS_TEXT N_( "Two pass" )
00059 #define TWOPASS_LONGTEXT N_( "Filter twice the audio" )
00060
00061 #define PREAMP_TEXT N_("Global gain" )
00062 #define PREAMP_LONGTEXT N_("Set the global gain in dB (-20 ... 20)" )
00063
00064 vlc_module_begin();
00065 set_description( _("Equalizer 10 bands") );
00066 set_shortname( N_("Equalizer" ) );
00067 set_capability( "audio filter", 0 );
00068 set_category( CAT_AUDIO );
00069 set_subcategory( SUBCAT_AUDIO_AFILTER );
00070
00071 add_string( "equalizer-preset", "flat", NULL, PRESET_TEXT,
00072 PRESET_LONGTEXT, VLC_FALSE );
00073 change_string_list( preset_list, preset_list_text, 0 );
00074 add_string( "equalizer-bands", NULL, NULL, BANDS_TEXT,
00075 BANDS_LONGTEXT, VLC_TRUE );
00076 add_bool( "equalizer-2pass", 0, NULL, TWOPASS_TEXT,
00077 TWOPASS_LONGTEXT, VLC_TRUE );
00078 add_float( "equalizer-preamp", 12.0, NULL, PREAMP_TEXT,
00079 PREAMP_LONGTEXT, VLC_TRUE );
00080 set_callbacks( Open, Close );
00081 add_shortcut( "equalizer" );
00082 vlc_module_end();
00083
00084
00085
00086
00087 typedef struct aout_filter_sys_t
00088 {
00089
00090 int i_band;
00091 float *f_alpha;
00092 float *f_beta;
00093 float *f_gamma;
00094
00095 float f_newpreamp;
00096 char *psz_newbands;
00097 vlc_bool_t b_first;
00098
00099
00100 float *f_amp;
00101 float f_gamp;
00102 vlc_bool_t b_2eqz;
00103
00104
00105 float x[32][2];
00106 float y[32][128][2];
00107
00108
00109 float x2[32][2];
00110 float y2[32][128][2];
00111
00112 } aout_filter_sys_t;
00113
00114 static void DoWork( aout_instance_t *, aout_filter_t *,
00115 aout_buffer_t *, aout_buffer_t * );
00116
00117 #define EQZ_IN_FACTOR (0.25)
00118 static int EqzInit( aout_filter_t *, int );
00119 static void EqzFilter( aout_instance_t *,aout_filter_t *, float *, float *,
00120 int, int );
00121 static void EqzClean( aout_filter_t * );
00122
00123 static int PresetCallback( vlc_object_t *, char const *,
00124 vlc_value_t, vlc_value_t, void * );
00125 static int PreampCallback( vlc_object_t *, char const *,
00126 vlc_value_t, vlc_value_t, void * );
00127 static int BandsCallback ( vlc_object_t *, char const *,
00128 vlc_value_t, vlc_value_t, void * );
00129
00130
00131
00132
00133
00134
00135 static int Open( vlc_object_t *p_this )
00136 {
00137 aout_filter_t *p_filter = (aout_filter_t *)p_this;
00138 aout_filter_sys_t *p_sys;
00139 vlc_bool_t b_fit = VLC_TRUE;
00140
00141 if( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' ) ||
00142 p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
00143 {
00144 b_fit = VLC_FALSE;
00145 p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
00146 p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
00147 msg_Warn( p_filter, "Bad input or output format" );
00148 }
00149 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
00150 {
00151 b_fit = VLC_FALSE;
00152 memcpy( &p_filter->output, &p_filter->input,
00153 sizeof(audio_sample_format_t) );
00154 msg_Warn( p_filter, "input and output formats are not similar" );
00155 }
00156
00157 if ( ! b_fit )
00158 {
00159 return VLC_EGENERIC;
00160 }
00161
00162 p_filter->pf_do_work = DoWork;
00163 p_filter->b_in_place = VLC_TRUE;
00164
00165
00166 p_sys = p_filter->p_sys = malloc( sizeof( aout_filter_sys_t ) );
00167
00168 if( EqzInit( p_filter, p_filter->input.i_rate ) )
00169 return VLC_EGENERIC;
00170
00171 return VLC_SUCCESS;
00172 }
00173
00174
00175
00176
00177 static void Close( vlc_object_t *p_this )
00178 {
00179 aout_filter_t *p_filter = (aout_filter_t *)p_this;
00180 aout_filter_sys_t *p_sys = p_filter->p_sys;
00181
00182 EqzClean( p_filter );
00183 free( p_sys );
00184 }
00185
00186
00187
00188
00189
00190
00191 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
00192 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
00193 {
00194 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
00195 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
00196
00197 EqzFilter( p_aout, p_filter, (float*)p_out_buf->p_buffer,
00198 (float*)p_in_buf->p_buffer, p_in_buf->i_nb_samples,
00199 aout_FormatNbChannels( &p_filter->input ) );
00200 }
00201
00202
00203
00204
00205 typedef struct
00206 {
00207 int i_band;
00208
00209 struct
00210 {
00211 float f_frequency;
00212 float f_alpha;
00213 float f_beta;
00214 float f_gamma;
00215 } band[EQZ_BANDS_MAX];
00216
00217 } eqz_config_t;
00218
00219
00220 static const eqz_config_t eqz_config_44100_10b =
00221 {
00222 10,
00223 {
00224 { 60, 0.003013, 0.993973, 1.993901 },
00225 { 170, 0.008490, 0.983019, 1.982437 },
00226 { 310, 0.015374, 0.969252, 1.967331 },
00227 { 600, 0.029328, 0.941343, 1.934254 },
00228 { 1000, 0.047918, 0.904163, 1.884869 },
00229 { 3000, 0.130408, 0.739184, 1.582718 },
00230 { 6000, 0.226555, 0.546889, 1.015267 },
00231 { 12000, 0.344937, 0.310127, -0.181410 },
00232 { 14000, 0.366438, 0.267123, -0.521151 },
00233 { 16000, 0.379009, 0.241981, -0.808451 },
00234 }
00235 };
00236 static const eqz_config_t eqz_config_48000_10b =
00237 {
00238 10,
00239 {
00240 { 60, 0.002769, 0.994462, 1.994400 },
00241 { 170, 0.007806, 0.984388, 1.983897 },
00242 { 310, 0.014143, 0.971714, 1.970091 },
00243 { 600, 0.027011, 0.945978, 1.939979 },
00244 { 1000, 0.044203, 0.911595, 1.895241 },
00245 { 3000, 0.121223, 0.757553, 1.623767 },
00246 { 6000, 0.212888, 0.574224, 1.113145 },
00247 { 12000, 0.331347, 0.337307, 0.000000 },
00248 { 14000, 0.355263, 0.289473, -0.333740 },
00249 { 16000, 0.371900, 0.256201, -0.628100 }
00250 }
00251 };
00252
00253 static inline float EqzConvertdB( float db )
00254 {
00255
00256
00257
00258
00259
00260
00261
00262
00263 if( db < -20.0 )
00264 db = -20.0;
00265 else if( db > 20.0 )
00266 db = 20.0;
00267 return EQZ_IN_FACTOR * ( pow( 10, db / 20.0 ) - 1.0 );
00268 }
00269
00270 static int EqzInit( aout_filter_t *p_filter, int i_rate )
00271 {
00272 aout_filter_sys_t *p_sys = p_filter->p_sys;
00273 const eqz_config_t *p_cfg;
00274 int i, ch;
00275 vlc_value_t val1, val2, val3;
00276 aout_instance_t *p_aout = (aout_instance_t *)p_filter->p_parent;
00277
00278
00279 if( i_rate == 48000 )
00280 {
00281 p_cfg = &eqz_config_48000_10b;
00282 }
00283 else if( i_rate == 44100 )
00284 {
00285 p_cfg = &eqz_config_44100_10b;
00286 }
00287 else
00288 {
00289
00290 msg_Err( p_filter, "unsupported rate" );
00291 return VLC_EGENERIC;
00292 }
00293
00294
00295 p_sys->i_band = p_cfg->i_band;
00296 p_sys->f_alpha = malloc( p_sys->i_band * sizeof(float) );
00297 p_sys->f_beta = malloc( p_sys->i_band * sizeof(float) );
00298 p_sys->f_gamma = malloc( p_sys->i_band * sizeof(float) );
00299 for( i = 0; i < p_sys->i_band; i++ )
00300 {
00301 p_sys->f_alpha[i] = p_cfg->band[i].f_alpha;
00302 p_sys->f_beta[i] = p_cfg->band[i].f_beta;
00303 p_sys->f_gamma[i] = p_cfg->band[i].f_gamma;
00304 }
00305
00306
00307 p_sys->b_2eqz = VLC_FALSE;
00308 p_sys->f_gamp = 1.0;
00309 p_sys->f_amp = malloc( p_sys->i_band * sizeof(float) );
00310 for( i = 0; i < p_sys->i_band; i++ )
00311 {
00312 p_sys->f_amp[i] = 0.0;
00313 }
00314
00315
00316 for( ch = 0; ch < 32; ch++ )
00317 {
00318 p_sys->x[ch][0] =
00319 p_sys->x[ch][1] =
00320 p_sys->x2[ch][0] =
00321 p_sys->x2[ch][1] = 0.0;
00322
00323 for( i = 0; i < p_sys->i_band; i++ )
00324 {
00325 p_sys->y[ch][i][0] =
00326 p_sys->y[ch][i][1] =
00327 p_sys->y2[ch][i][0] =
00328 p_sys->y2[ch][i][1] = 0.0;
00329 }
00330 }
00331
00332 var_CreateGetString( p_aout,"equalizer-bands" );
00333 var_CreateGetString( p_aout, "equalizer-preset" );
00334
00335 p_sys->b_2eqz = var_CreateGetBool( p_aout, "equalizer-2pass" );
00336
00337 var_CreateGetFloat( p_aout, "equalizer-preamp" );
00338
00339
00340 var_Get( p_aout, "equalizer-preset", &val1 );
00341 var_Get( p_aout, "equalizer-bands", &val2 );
00342 var_Get( p_aout, "equalizer-preamp", &val3 );
00343
00344 p_sys->b_first = VLC_TRUE;
00345 PresetCallback( VLC_OBJECT( p_aout ), NULL, val1, val1, p_sys );
00346 BandsCallback( VLC_OBJECT( p_aout ), NULL, val2, val2, p_sys );
00347 PreampCallback( VLC_OBJECT( p_aout ), NULL, val3, val3, p_sys );
00348 p_sys->b_first = VLC_FALSE;
00349
00350
00351
00352
00353 if (p_sys->psz_newbands == NULL)
00354 {
00355 msg_Err(p_filter, "No preset selected");
00356 return (VLC_EGENERIC);
00357 }
00358 if( ( *(val2.psz_string) &&
00359 strstr( p_sys->psz_newbands, val2.psz_string ) ) || !*val2.psz_string )
00360 {
00361 var_SetString( p_aout, "equalizer-bands", p_sys->psz_newbands );
00362 if( p_sys->f_newpreamp == p_sys->f_gamp )
00363 var_SetFloat( p_aout, "equalizer-preamp", p_sys->f_newpreamp );
00364 }
00365
00366
00367 var_AddCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
00368 var_AddCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
00369 var_AddCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
00370
00371 msg_Dbg( p_filter, "equalizer loaded for %d Hz with %d bands %d pass",
00372 i_rate, p_sys->i_band, p_sys->b_2eqz ? 2 : 1 );
00373 for( i = 0; i < p_sys->i_band; i++ )
00374 {
00375 msg_Dbg( p_filter, " %d Hz -> factor:%f alpha:%f beta:%f gamma:%f",
00376 (int)p_cfg->band[i].f_frequency, p_sys->f_amp[i],
00377 p_sys->f_alpha[i], p_sys->f_beta[i], p_sys->f_gamma[i]);
00378 }
00379 return VLC_SUCCESS;
00380 }
00381
00382 static void EqzFilter( aout_instance_t *p_aout,
00383 aout_filter_t *p_filter, float *out, float *in,
00384 int i_samples, int i_channels )
00385 {
00386 aout_filter_sys_t *p_sys = p_filter->p_sys;
00387 int i, ch, j;
00388
00389 for( i = 0; i < i_samples; i++ )
00390 {
00391 for( ch = 0; ch < i_channels; ch++ )
00392 {
00393 const float x = in[ch];
00394 float o = 0.0;
00395
00396 for( j = 0; j < p_sys->i_band; j++ )
00397 {
00398 float y = p_sys->f_alpha[j] * ( x - p_sys->x[ch][1] ) +
00399 p_sys->f_gamma[j] * p_sys->y[ch][j][0] -
00400 p_sys->f_beta[j] * p_sys->y[ch][j][1];
00401
00402 p_sys->y[ch][j][1] = p_sys->y[ch][j][0];
00403 p_sys->y[ch][j][0] = y;
00404
00405 o += y * p_sys->f_amp[j];
00406 }
00407 p_sys->x[ch][1] = p_sys->x[ch][0];
00408 p_sys->x[ch][0] = x;
00409
00410
00411 if( p_sys->b_2eqz )
00412 {
00413 const float x2 = EQZ_IN_FACTOR * x + o;
00414 o = 0.0;
00415 for( j = 0; j < p_sys->i_band; j++ )
00416 {
00417 float y = p_sys->f_alpha[j] * ( x2 - p_sys->x2[ch][1] ) +
00418 p_sys->f_gamma[j] * p_sys->y2[ch][j][0] -
00419 p_sys->f_beta[j] * p_sys->y2[ch][j][1];
00420
00421 p_sys->y2[ch][j][1] = p_sys->y2[ch][j][0];
00422 p_sys->y2[ch][j][0] = y;
00423
00424 o += y * p_sys->f_amp[j];
00425 }
00426 p_sys->x2[ch][1] = p_sys->x2[ch][0];
00427 p_sys->x2[ch][0] = x2;
00428
00429
00430 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x2 + o );
00431 }
00432 else
00433 {
00434
00435 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o );
00436 }
00437 }
00438
00439 in += i_channels;
00440 out += i_channels;
00441 }
00442 }
00443
00444 static void EqzClean( aout_filter_t *p_filter )
00445 {
00446 aout_filter_sys_t *p_sys = p_filter->p_sys;
00447
00448 var_DelCallback( (aout_instance_t *)p_filter->p_parent,
00449 "equalizer-bands", BandsCallback, p_sys );
00450 var_DelCallback( (aout_instance_t *)p_filter->p_parent,
00451 "equalizer-preset", PresetCallback, p_sys );
00452 var_DelCallback( (aout_instance_t *)p_filter->p_parent,
00453 "equalizer-preamp", PreampCallback, p_sys );
00454
00455 free( p_sys->f_alpha );
00456 free( p_sys->f_beta );
00457 free( p_sys->f_gamma );
00458
00459 free( p_sys->f_amp );
00460 }
00461
00462
00463 static int PresetCallback( vlc_object_t *p_this, char const *psz_cmd,
00464 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00465 {
00466 aout_filter_sys_t *p_sys = (aout_filter_sys_t *)p_data;
00467 aout_instance_t *p_aout = (aout_instance_t *)p_this;
00468
00469 char *psz_preset = newval.psz_string;
00470 char psz_newbands[120];
00471
00472 memset( psz_newbands, 0, 120 );
00473
00474 if( *psz_preset && p_sys->i_band == 10 )
00475 {
00476 int i;
00477
00478 for( i = 0; eqz_preset_10b[i] != NULL; i++ )
00479 {
00480 if( !strcasecmp( eqz_preset_10b[i]->psz_name, psz_preset ) )
00481 {
00482 int j;
00483 p_sys->f_gamp *= pow( 10, eqz_preset_10b[i]->f_preamp / 20.0 );
00484 for( j = 0; j < p_sys->i_band; j++ )
00485 {
00486 p_sys->f_amp[j] = EqzConvertdB(
00487 eqz_preset_10b[i]->f_amp[j] );
00488 sprintf( psz_newbands, "%s %f", psz_newbands,
00489 eqz_preset_10b[i]->f_amp[j] );
00490 }
00491 if( p_sys->b_first == VLC_FALSE )
00492 {
00493 var_SetString( p_aout, "equalizer-bands", psz_newbands );
00494 var_SetFloat( p_aout, "equalizer-preamp",
00495 eqz_preset_10b[i]->f_preamp );
00496 }
00497 else
00498 {
00499 p_sys->psz_newbands = strdup( psz_newbands );
00500 p_sys->f_newpreamp = eqz_preset_10b[i]->f_preamp;
00501 }
00502 break;
00503 }
00504 }
00505 if( eqz_preset_10b[i] == NULL )
00506 {
00507 msg_Err( p_aout, "equalizer preset '%s' not found", psz_preset );
00508 msg_Dbg( p_aout, "full list:" );
00509 for( i = 0; eqz_preset_10b[i] != NULL; i++ )
00510 msg_Dbg( p_aout, " - '%s'", eqz_preset_10b[i]->psz_name );
00511 }
00512 }
00513 return VLC_SUCCESS;
00514 }
00515
00516 static int PreampCallback( vlc_object_t *p_this, char const *psz_cmd,
00517 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00518 {
00519 aout_filter_sys_t *p_sys = (aout_filter_sys_t *)p_data;
00520
00521 if( newval.f_float < -20.0 )
00522 newval.f_float = -20.0;
00523 else if( newval.f_float > 20.0 )
00524 newval.f_float = 20.0;
00525 p_sys->f_gamp = pow( 10, newval.f_float /20.0);
00526
00527 return VLC_SUCCESS;
00528 }
00529
00530 static int BandsCallback( vlc_object_t *p_this, char const *psz_cmd,
00531 vlc_value_t oldval, vlc_value_t newval, void *p_data )
00532 {
00533 aout_filter_sys_t *p_sys = (aout_filter_sys_t *)p_data;
00534 char *psz_bands = newval.psz_string;
00535
00536
00537 if( *psz_bands )
00538 {
00539 char *p = psz_bands, *p_next;
00540 int i;
00541
00542 for( i = 0; i < p_sys->i_band; i++ )
00543 {
00544
00545 #ifdef HAVE_STRTOF
00546 float f = strtof( p, &p_next );
00547 #else
00548 float f = (float) strtod( p, &p_next );
00549 #endif
00550 if( !p_next || p_next == p ) break;
00551
00552 p_sys->f_amp[i] = EqzConvertdB( f );
00553
00554 if( !*p ) break;
00555 p=p_next+1;
00556 }
00557 }
00558
00559 return VLC_SUCCESS;
00560 }