]> git.sesse.net Git - vlc/blob - modules/audio_filter/equalizer.c
ftp: rename function for consistency and avoid forward declaration
[vlc] / modules / audio_filter / equalizer.c
1 /*****************************************************************************
2  * equalizer.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2012 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
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.
13  *
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.
18  *
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  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
31
32 #include <math.h>
33
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_charset.h>
37
38 #include <vlc_aout.h>
39 #include <vlc_filter.h>
40
41 #include "equalizer_presets.h"
42
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  *  - ...
50  */
51
52 /*****************************************************************************
53  * Module descriptor
54  *****************************************************************************/
55 static int  Open ( vlc_object_t * );
56 static void Close( vlc_object_t * );
57
58 #define PRESET_TEXT N_( "Equalizer preset" )
59 #define PRESET_LONGTEXT N_("Preset to use for the equalizer." )
60
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\"." )
66
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." )
71
72 #define TWOPASS_TEXT N_( "Two pass" )
73 #define TWOPASS_LONGTEXT N_( "Filter the audio twice. This provides a more "  \
74          "intense effect.")
75
76 #define PREAMP_TEXT N_("Global gain" )
77 #define PREAMP_LONGTEXT N_("Set the global gain in dB (-20 ... 20)." )
78
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 )
85
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" )
99 vlc_module_end ()
100
101 /*****************************************************************************
102  * Local prototypes
103  *****************************************************************************/
104 struct filter_sys_t
105 {
106     /* Filter static config */
107     int i_band;
108     float *f_alpha;
109     float *f_beta;
110     float *f_gamma;
111
112     float f_newpreamp;
113     char *psz_newbands;
114     bool b_first;
115
116     /* Filter dyn config */
117     float *f_amp;   /* Per band amp */
118     float f_gamp;   /* Global preamp */
119     bool b_2eqz;
120
121     /* Filter state */
122     float x[32][2];
123     float y[32][128][2];
124
125     /* Second filter state */
126     float x2[32][2];
127     float y2[32][128][2];
128
129     vlc_mutex_t lock;
130 };
131
132 static block_t *DoWork( filter_t *, block_t * );
133
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 * );
138
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 * );
147
148
149
150 /*****************************************************************************
151  * Open:
152  *****************************************************************************/
153 static int Open( vlc_object_t *p_this )
154 {
155     filter_t     *p_filter = (filter_t *)p_this;
156     filter_sys_t *p_sys;
157
158     if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
159         p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
160     {
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" );
164         return VLC_EGENERIC;
165     }
166     if ( !AOUT_FMTS_SIMILAR( &p_filter->fmt_in.audio, &p_filter->fmt_out.audio ) )
167     {
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" );
171         return VLC_EGENERIC;
172     }
173
174     p_filter->pf_audio_filter = DoWork;
175
176     /* Allocate structure */
177     p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
178     if( !p_sys )
179         return VLC_ENOMEM;
180
181     vlc_mutex_init( &p_sys->lock );
182     if( EqzInit( p_filter, p_filter->fmt_in.audio.i_rate ) != VLC_SUCCESS )
183     {
184         vlc_mutex_destroy( &p_sys->lock );
185         free( p_sys );
186         return VLC_EGENERIC;
187     }
188
189     return VLC_SUCCESS;
190 }
191
192 /*****************************************************************************
193  * Close: close the plugin
194  *****************************************************************************/
195 static void Close( vlc_object_t *p_this )
196 {
197     filter_t     *p_filter = (filter_t *)p_this;
198     filter_sys_t *p_sys = p_filter->p_sys;
199
200     EqzClean( p_filter );
201     vlc_mutex_destroy( &p_sys->lock );
202     free( p_sys );
203 }
204
205 /*****************************************************************************
206  * DoWork: process samples buffer
207  *****************************************************************************
208  *
209  *****************************************************************************/
210 static block_t * DoWork( filter_t * p_filter, block_t * p_in_buf )
211 {
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 ) );
215     return p_in_buf;
216 }
217
218 /*****************************************************************************
219  * Equalizer stuff
220  *****************************************************************************/
221 typedef struct
222 {
223     int   i_band;
224
225     struct
226     {
227         float f_frequency;
228         float f_alpha;
229         float f_beta;
230         float f_gamma;
231     } band[EQZ_BANDS_MAX];
232
233 } eqz_config_t;
234
235 /* The frequency tables */
236 static const float f_vlc_frequency_table_10b[EQZ_BANDS_MAX] =
237 {
238     60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000,
239 };
240
241 static const float f_iso_frequency_table_10b[EQZ_BANDS_MAX] =
242 {
243     31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, 16000,
244 };
245
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 )
250 {
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 );
259
260     p_eqz_config->i_band = EQZ_BANDS_MAX;
261
262     for( int i = 0; i < EQZ_BANDS_MAX; i++ )
263     {
264         float f_freq = f_freq_table_10b[i];
265
266         p_eqz_config->band[i].f_frequency = f_freq;
267
268         if( f_freq <= f_nyquist_freq )
269         {
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 );
282
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 );
286         }
287         else
288         {
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;
293         }
294     }
295 }
296
297 static inline float EqzConvertdB( float db )
298 {
299     /* Map it to gain,
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)
305      **/
306
307     if( db < -20.0 )
308         db = -20.0;
309     else if(  db > 20.0 )
310         db = 20.0;
311     return EQZ_IN_FACTOR * ( pow( 10, db / 20.0 ) - 1.0 );
312 }
313
314 static int EqzInit( filter_t *p_filter, int i_rate )
315 {
316     filter_sys_t *p_sys = p_filter->p_sys;
317     eqz_config_t cfg;
318     int i, ch;
319     vlc_value_t val1, val2, val3;
320     vlc_object_t *p_aout = p_filter->p_parent;
321     int i_ret = VLC_ENOMEM;
322
323     bool b_vlcFreqs = var_InheritBool( p_aout, "equalizer-vlcfreqs" );
324     EqzCoeffs( i_rate, 1.0, b_vlcFreqs, &cfg );
325
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 )
332         goto error;
333
334     for( i = 0; i < p_sys->i_band; i++ )
335     {
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;
339     }
340
341     /* Filter dyn config */
342     p_sys->b_2eqz = false;
343     p_sys->f_gamp = 1.0;
344     p_sys->f_amp  = malloc( p_sys->i_band * sizeof(float) );
345     if( !p_sys->f_amp )
346         goto error;
347
348     for( i = 0; i < p_sys->i_band; i++ )
349     {
350         p_sys->f_amp[i] = 0.0;
351     }
352
353     /* Filter state */
354     for( ch = 0; ch < 32; ch++ )
355     {
356         p_sys->x[ch][0]  =
357         p_sys->x[ch][1]  =
358         p_sys->x2[ch][0] =
359         p_sys->x2[ch][1] = 0.0;
360
361         for( i = 0; i < p_sys->i_band; i++ )
362         {
363             p_sys->y[ch][i][0]  =
364             p_sys->y[ch][i][1]  =
365             p_sys->y2[ch][i][0] =
366             p_sys->y2[ch][i][1] = 0.0;
367         }
368     }
369
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 );
372
373     p_sys->b_2eqz = var_CreateGetBool( p_aout, "equalizer-2pass" );
374
375     var_Create( p_aout, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
376
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 );
381
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;
387
388     free( val1.psz_string );
389
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)
394     {
395         msg_Err(p_filter, "No preset selected");
396         free( val2.psz_string );
397         free( p_sys->f_amp );
398         i_ret = VLC_EGENERIC;
399         goto error;
400     }
401     if( ( *(val2.psz_string) &&
402         strstr( p_sys->psz_newbands, val2.psz_string ) ) || !*val2.psz_string )
403     {
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 );
407     }
408     free( val2.psz_string );
409
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 );
415
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++ )
419     {
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]);
423     }
424     return VLC_SUCCESS;
425
426 error:
427     free( p_sys->f_alpha );
428     free( p_sys->f_beta );
429     free( p_sys->f_gamma );
430     return i_ret;
431 }
432
433 static void EqzFilter( filter_t *p_filter, float *out, float *in,
434                        int i_samples, int i_channels )
435 {
436     filter_sys_t *p_sys = p_filter->p_sys;
437     int i, ch, j;
438
439     vlc_mutex_lock( &p_sys->lock );
440     for( i = 0; i < i_samples; i++ )
441     {
442         for( ch = 0; ch < i_channels; ch++ )
443         {
444             const float x = in[ch];
445             float o = 0.0;
446
447             for( j = 0; j < p_sys->i_band; j++ )
448             {
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];
452
453                 p_sys->y[ch][j][1] = p_sys->y[ch][j][0];
454                 p_sys->y[ch][j][0] = y;
455
456                 o += y * p_sys->f_amp[j];
457             }
458             p_sys->x[ch][1] = p_sys->x[ch][0];
459             p_sys->x[ch][0] = x;
460
461             /* Second filter */
462             if( p_sys->b_2eqz )
463             {
464                 const float x2 = EQZ_IN_FACTOR * x + o;
465                 o = 0.0;
466                 for( j = 0; j < p_sys->i_band; j++ )
467                 {
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];
471
472                     p_sys->y2[ch][j][1] = p_sys->y2[ch][j][0];
473                     p_sys->y2[ch][j][0] = y;
474
475                     o += y * p_sys->f_amp[j];
476                 }
477                 p_sys->x2[ch][1] = p_sys->x2[ch][0];
478                 p_sys->x2[ch][0] = x2;
479
480                 /* We add source PCM + filtered PCM */
481                 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x2 + o );
482             }
483             else
484             {
485                 /* We add source PCM + filtered PCM */
486                 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o );
487             }
488         }
489
490         in  += i_channels;
491         out += i_channels;
492     }
493     vlc_mutex_unlock( &p_sys->lock );
494 }
495
496 static void EqzClean( filter_t *p_filter )
497 {
498     filter_sys_t *p_sys = p_filter->p_sys;
499     vlc_object_t *p_aout = p_filter->p_parent;
500
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 );
505
506     free( p_sys->f_alpha );
507     free( p_sys->f_beta );
508     free( p_sys->f_gamma );
509
510     free( p_sys->f_amp );
511     free( p_sys->psz_newbands );
512 }
513
514
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 )
517 {
518     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
519     filter_sys_t *p_sys = p_data;
520
521     const char *psz_preset = newval.psz_string;
522
523     vlc_mutex_lock( &p_sys->lock );
524     if( !*psz_preset || p_sys->i_band != 10 )
525     {
526         vlc_mutex_unlock( &p_sys->lock );
527         return VLC_SUCCESS;
528     }
529
530     for( unsigned i = 0; i < NB_PRESETS; i++ )
531     {
532         if( !strcasecmp( eqz_preset_10b[i].psz_name, psz_preset ) )
533         {
534             char *psz_newbands = NULL;
535
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++ )
538             {
539                 lldiv_t d;
540                 char *psz;
541
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 )
547                 {
548                     free( psz_newbands );
549                     vlc_mutex_unlock( &p_sys->lock );
550                     return VLC_ENOMEM;
551                 }
552                 free( psz_newbands );
553                 psz_newbands = psz;
554             }
555             if( !p_sys->b_first )
556             {
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 );
562             }
563             else
564             {
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 );
568             }
569             return VLC_SUCCESS;
570         }
571     }
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 );
577     return VLC_SUCCESS;
578 }
579
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 )
582 {
583     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
584     filter_sys_t *p_sys = p_data;
585
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;
590
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 );
594
595     return VLC_SUCCESS;
596 }
597
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 )
600 {
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;
605     char *psz_next;
606
607     /* Same thing for bands */
608     vlc_mutex_lock( &p_sys->lock );
609     for( int i = 0; i < p_sys->i_band; i++ )
610     {
611         float f;
612
613         if( *psz_bands == '\0' )
614             break;
615
616         /* Read dB -20/20 */
617         f = us_strtof( p, &psz_next );
618
619         if( psz_next == p )
620             break; /* no conversion */
621
622         p_sys->f_amp[i] = EqzConvertdB( f );
623
624         if( *psz_next == '\0' )
625             break; /* end of line */
626         p = &psz_next[1];
627     }
628     vlc_mutex_unlock( &p_sys->lock );
629     return VLC_SUCCESS;
630 }
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 )
633 {
634     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
635     filter_sys_t *p_sys = p_data;
636
637     vlc_mutex_lock( &p_sys->lock );
638     p_sys->b_2eqz = newval.b_bool;
639     vlc_mutex_unlock( &p_sys->lock );
640     return VLC_SUCCESS;
641 }
642