equalizer.c 20.3 KB
Newer Older
1 2 3
/*****************************************************************************
 * equalizer.c:
 *****************************************************************************
4
 * Copyright (C) 2004-2012 VLC authors and VideoLAN
5
 * $Id$
6 7 8
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
9 10 11
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
12 13 14 15
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
18
 *
19 20 21
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26 27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

28 29 30 31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32 33
#include <math.h>

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

Jérome Decoodt's avatar
Jérome Decoodt committed
41
#include "equalizer_presets.h"
42

43 44 45
/* TODO:
 *  - optimize a bit (you can hardly do slower ;)
 *  - 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 48 49 50 51 52 53 54 55 56 57 58
 *  - support for external preset
 *  - callback to handle preset changes on the fly
 *  - ...
 */

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

#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 64
         "Don't use presets, but manually specified bands. You need to " \
         "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 68 69 70 71
#define VLC_BANDS_TEXT N_( "Use VLC frequency bands" )
#define VLC_BANDS_LONGTEXT N_( \
         "Use the VLC frequency bands. Otherwise, use the ISO Standard " \
         "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.")
75 76

#define PREAMP_TEXT N_("Global gain" )
77
#define PREAMP_LONGTEXT N_("Set the global gain in dB (-20 ... 20)." )
78

79 80 81
vlc_module_begin ()
    set_description( N_("Equalizer with 10 bands") )
    set_shortname( N_("Equalizer" ) )
82
    set_capability( "audio filter", 0 )
83 84
    set_category( CAT_AUDIO )
    set_subcategory( SUBCAT_AUDIO_AFILTER )
Clément Stenac's avatar
Clément Stenac committed
85

86
    add_string( "equalizer-preset", "flat", PRESET_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
87
                PRESET_LONGTEXT, false )
88
        change_string_list( preset_list, preset_list_text )
89
    add_string( "equalizer-bands", NULL, BANDS_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
90
                BANDS_LONGTEXT, true )
91
    add_bool( "equalizer-2pass", false, TWOPASS_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
92
              TWOPASS_LONGTEXT, true )
93 94
    add_bool( "equalizer-vlcfreqs", true, VLC_BANDS_TEXT,
              VLC_BANDS_LONGTEXT, true )
95
    add_float( "equalizer-preamp", 12.0f, PREAMP_TEXT,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
96
               PREAMP_LONGTEXT, true )
97 98 99
    set_callbacks( Open, Close )
    add_shortcut( "equalizer" )
vlc_module_end ()
100 101 102 103

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
104
struct filter_sys_t
105 106 107 108 109 110 111
{
    /* Filter static config */
    int i_band;
    float *f_alpha;
    float *f_beta;
    float *f_gamma;

112 113
    float f_newpreamp;
    char *psz_newbands;
114
    bool b_first;
115

116 117 118
    /* Filter dyn config */
    float *f_amp;   /* Per band amp */
    float f_gamp;   /* Global preamp */
119
    bool b_2eqz;
120 121 122 123 124 125 126 127 128

    /* Filter state */
    float x[32][2];
    float y[32][128][2];

    /* Second filter state */
    float x2[32][2];
    float y2[32][128][2];

129
    vlc_mutex_t lock;
130
};
131

132
static block_t *DoWork( filter_t *, block_t * );
133

134
#define EQZ_IN_FACTOR (0.25f)
135 136 137
static int  EqzInit( filter_t *, int );
static void EqzFilter( filter_t *, float *, float *, int, int );
static void EqzClean( filter_t * );
138

139 140 141 142 143 144 145 146
static int PresetCallback ( vlc_object_t *, char const *, vlc_value_t,
                            vlc_value_t, void * );
static int PreampCallback ( vlc_object_t *, char const *, vlc_value_t,
                            vlc_value_t, void * );
static int BandsCallback  ( vlc_object_t *, char const *, vlc_value_t,
                            vlc_value_t, void * );
static int TwoPassCallback( vlc_object_t *, char const *, vlc_value_t,
                            vlc_value_t, void * );
147 148 149



150 151 152 153 154
/*****************************************************************************
 * Open:
 *****************************************************************************/
static int Open( vlc_object_t *p_this )
{
155
    filter_t     *p_filter = (filter_t *)p_this;
156 157

    /* Allocate structure */
158
    filter_sys_t *p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
159 160
    if( !p_sys )
        return VLC_ENOMEM;
161

162
    vlc_mutex_init( &p_sys->lock );
163
    if( EqzInit( p_filter, p_filter->fmt_in.audio.i_rate ) != VLC_SUCCESS )
164
    {
165
        vlc_mutex_destroy( &p_sys->lock );
166
        free( p_sys );
167
        return VLC_EGENERIC;
168
    }
169

170 171 172 173
    p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
    p_filter->fmt_out.audio = p_filter->fmt_in.audio;
    p_filter->pf_audio_filter = DoWork;

174 175 176 177 178 179 180 181
    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close: close the plugin
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
182 183
    filter_t     *p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys = p_filter->p_sys;
184 185

    EqzClean( p_filter );
186
    vlc_mutex_destroy( &p_sys->lock );
187 188 189 190 191 192 193 194
    free( p_sys );
}

/*****************************************************************************
 * DoWork: process samples buffer
 *****************************************************************************
 *
 *****************************************************************************/
195
static block_t * DoWork( filter_t * p_filter, block_t * p_in_buf )
196
{
197
    EqzFilter( p_filter, (float*)p_in_buf->p_buffer,
198
               (float*)p_in_buf->p_buffer, p_in_buf->i_nb_samples,
199
               aout_FormatNbChannels( &p_filter->fmt_in.audio ) );
200
    return p_in_buf;
201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
}

/*****************************************************************************
 * Equalizer stuff
 *****************************************************************************/
typedef struct
{
    int   i_band;

    struct
    {
        float f_frequency;
        float f_alpha;
        float f_beta;
        float f_gamma;
216
    } band[EQZ_BANDS_MAX];
217

218 219
} eqz_config_t;

220 221 222
/* The frequency tables */
static const float f_vlc_frequency_table_10b[EQZ_BANDS_MAX] =
{
223 224
    60.0f, 170.0f, 310.0f, 600.0f, 1000.0f, 3000.0f, 6000.0f, 12000.0f,
    14000.0f, 16000.0f,
225 226 227 228
};

static const float f_iso_frequency_table_10b[EQZ_BANDS_MAX] =
{
229 230
    31.25f, 62.5f, 125.0f, 250.0f, 500.0f, 1000.0f, 2000.0f, 4000.0f,
    8000.0f, 16000.0f,
231 232
};

233 234 235 236
/* Equalizer coefficient calculation function based on equ-xmms */
static void EqzCoeffs( int i_rate, float f_octave_percent,
                       bool b_use_vlc_freqs,
                       eqz_config_t *p_eqz_config )
237
{
238 239 240 241
    const float *f_freq_table_10b = b_use_vlc_freqs
                                  ? f_vlc_frequency_table_10b
                                  : f_iso_frequency_table_10b;
    float f_rate = (float) i_rate;
242 243 244 245
    float f_nyquist_freq = 0.5f * f_rate;
    float f_octave_factor = powf( 2.0f, 0.5f * f_octave_percent );
    float f_octave_factor_1 = 0.5f * ( f_octave_factor + 1.0f );
    float f_octave_factor_2 = 0.5f * ( f_octave_factor - 1.0f );
246 247 248 249

    p_eqz_config->i_band = EQZ_BANDS_MAX;

    for( int i = 0; i < EQZ_BANDS_MAX; i++ )
250
    {
251 252 253 254 255 256
        float f_freq = f_freq_table_10b[i];

        p_eqz_config->band[i].f_frequency = f_freq;

        if( f_freq <= f_nyquist_freq )
        {
257
            float f_theta_1 = ( 2.0f * M_PI * f_freq ) / f_rate;
258
            float f_theta_2 = f_theta_1 / f_octave_factor;
259 260 261 262
            float f_sin     = sinf( f_theta_2 );
            float f_sin_prd = sinf( f_theta_2 * f_octave_factor_1 )
                            * sinf( f_theta_2 * f_octave_factor_2 );
            float f_sin_hlf = f_sin * 0.5f;
263 264 265 266
            float f_den     = f_sin_hlf + f_sin_prd;

            p_eqz_config->band[i].f_alpha = f_sin_prd / f_den;
            p_eqz_config->band[i].f_beta  = ( f_sin_hlf - f_sin_prd ) / f_den;
267
            p_eqz_config->band[i].f_gamma = f_sin * cosf( f_theta_1 ) / f_den;
268 269 270 271 272 273
        }
        else
        {
            /* Any frequency beyond the Nyquist frequency is no good... */
            p_eqz_config->band[i].f_alpha =
            p_eqz_config->band[i].f_beta  =
274
            p_eqz_config->band[i].f_gamma = 0.0f;
275
        }
276
    }
277
}
278 279 280 281 282 283 284 285 286 287 288

static inline float EqzConvertdB( float db )
{
    /* Map it to gain,
     * (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)
     * db = 20*log( out / in ) with out = in + amp*iir(i/EQZ_IN_FACTOR)
     * or iir(i) == i for the center freq so
     * db = 20*log( 1 + amp/EQZ_IN_FACTOR )
     * -> amp = EQZ_IN_FACTOR*(10^(db/20) - 1)
     **/

289 290 291 292 293
    if( db < -20.0f )
        db = -20.0f;
    else if(  db > 20.0f )
        db = 20.0f;
    return EQZ_IN_FACTOR * ( powf( 10.0f, db / 20.0f ) - 1.0f );
294 295
}

296
static int EqzInit( filter_t *p_filter, int i_rate )
297
{
298
    filter_sys_t *p_sys = p_filter->p_sys;
299
    eqz_config_t cfg;
300
    int i, ch;
301
    vlc_value_t val1, val2, val3;
302
    vlc_object_t *p_aout = p_filter->p_parent;
303
    int i_ret = VLC_ENOMEM;
304

305
    bool b_vlcFreqs = var_InheritBool( p_aout, "equalizer-vlcfreqs" );
306
    EqzCoeffs( i_rate, 1.0f, b_vlcFreqs, &cfg );
307 308

    /* Create the static filter config */
309
    p_sys->i_band = cfg.i_band;
310 311 312
    p_sys->f_alpha = malloc( p_sys->i_band * sizeof(float) );
    p_sys->f_beta  = malloc( p_sys->i_band * sizeof(float) );
    p_sys->f_gamma = malloc( p_sys->i_band * sizeof(float) );
Rémi Duraffort's avatar
Rémi Duraffort committed
313
    if( !p_sys->f_alpha || !p_sys->f_beta || !p_sys->f_gamma )
314
        goto error;
Rémi Duraffort's avatar
Rémi Duraffort committed
315

316 317
    for( i = 0; i < p_sys->i_band; i++ )
    {
318 319 320
        p_sys->f_alpha[i] = cfg.band[i].f_alpha;
        p_sys->f_beta[i]  = cfg.band[i].f_beta;
        p_sys->f_gamma[i] = cfg.band[i].f_gamma;
321 322 323
    }

    /* Filter dyn config */
324
    p_sys->b_2eqz = false;
325
    p_sys->f_gamp = 1.0f;
Rémi Duraffort's avatar
Rémi Duraffort committed
326 327
    p_sys->f_amp  = malloc( p_sys->i_band * sizeof(float) );
    if( !p_sys->f_amp )
328 329
        goto error;

330 331
    for( i = 0; i < p_sys->i_band; i++ )
    {
332
        p_sys->f_amp[i] = 0.0f;
333 334 335 336 337 338 339 340
    }

    /* Filter state */
    for( ch = 0; ch < 32; ch++ )
    {
        p_sys->x[ch][0]  =
        p_sys->x[ch][1]  =
        p_sys->x2[ch][0] =
341
        p_sys->x2[ch][1] = 0.0f;
342 343 344 345 346 347

        for( i = 0; i < p_sys->i_band; i++ )
        {
            p_sys->y[ch][i][0]  =
            p_sys->y[ch][i][1]  =
            p_sys->y2[ch][i][0] =
348
            p_sys->y2[ch][i][1] = 0.0f;
349 350 351
        }
    }

352 353
    p_sys->psz_newbands = NULL;

354 355
    var_Create( p_aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
356

357
    p_sys->b_2eqz = var_CreateGetBool( p_aout, "equalizer-2pass" );
358

359
    var_Create( p_aout, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
360

361 362 363 364
    /* Get initial values */
    var_Get( p_aout, "equalizer-preset", &val1 );
    var_Get( p_aout, "equalizer-bands", &val2 );
    var_Get( p_aout, "equalizer-preamp", &val3 );
365

366
    p_sys->b_first = true;
367 368 369
    PresetCallback( VLC_OBJECT( p_aout ), NULL, val1, val1, p_sys );
    BandsCallback(  VLC_OBJECT( p_aout ), NULL, val2, val2, p_sys );
    PreampCallback( VLC_OBJECT( p_aout ), NULL, val3, val3, p_sys );
370
    p_sys->b_first = false;
371

372 373
    free( val1.psz_string );

374 375
    /* Exit if we have no preset and no bands value */
    if (p_sys->psz_newbands == NULL && (!val2.psz_string || !*val2.psz_string))
376 377
    {
        msg_Err(p_filter, "No preset selected");
378
        free( val2.psz_string );
Rémi Duraffort's avatar
Rémi Duraffort committed
379
        free( p_sys->f_amp );
380 381
        i_ret = VLC_EGENERIC;
        goto error;
382
    }
383 384 385 386 387
    /* Register preset bands (for intf) if : */
    /* We have no bands info --> the preset info must be given to the intf */
    /* or The bands info matches the preset */
    if( ( p_sys->psz_newbands && *(val2.psz_string) &&
         strstr( p_sys->psz_newbands, val2.psz_string ) ) || !*val2.psz_string )
388 389
    {
        var_SetString( p_aout, "equalizer-bands", p_sys->psz_newbands );
390 391
        if( p_sys->f_newpreamp == p_sys->f_gamp )
            var_SetFloat( p_aout, "equalizer-preamp", p_sys->f_newpreamp );
392
    }
393
    free( val2.psz_string );
394 395 396 397 398

    /* Add our own callbacks */
    var_AddCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
    var_AddCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
    var_AddCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
399
    var_AddCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
400 401

    msg_Dbg( p_filter, "equalizer loaded for %d Hz with %d bands %d pass",
402
                        i_rate, p_sys->i_band, p_sys->b_2eqz ? 2 : 1 );
403 404
    for( i = 0; i < p_sys->i_band; i++ )
    {
405 406
        msg_Dbg( p_filter, "   %.2f Hz -> factor:%f alpha:%f beta:%f gamma:%f",
                 cfg.band[i].f_frequency, p_sys->f_amp[i],
407 408 409
                 p_sys->f_alpha[i], p_sys->f_beta[i], p_sys->f_gamma[i]);
    }
    return VLC_SUCCESS;
410 411 412 413 414 415

error:
    free( p_sys->f_alpha );
    free( p_sys->f_beta );
    free( p_sys->f_gamma );
    return i_ret;
416 417
}

418
static void EqzFilter( filter_t *p_filter, float *out, float *in,
419
                       int i_samples, int i_channels )
420
{
421
    filter_sys_t *p_sys = p_filter->p_sys;
422 423
    int i, ch, j;

424
    vlc_mutex_lock( &p_sys->lock );
425 426 427 428 429
    for( i = 0; i < i_samples; i++ )
    {
        for( ch = 0; ch < i_channels; ch++ )
        {
            const float x = in[ch];
430
            float o = 0.0f;
431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449

            for( j = 0; j < p_sys->i_band; j++ )
            {
                float y = p_sys->f_alpha[j] * ( x - p_sys->x[ch][1] ) +
                          p_sys->f_gamma[j] * p_sys->y[ch][j][0] -
                          p_sys->f_beta[j]  * p_sys->y[ch][j][1];

                p_sys->y[ch][j][1] = p_sys->y[ch][j][0];
                p_sys->y[ch][j][0] = y;

                o += y * p_sys->f_amp[j];
            }
            p_sys->x[ch][1] = p_sys->x[ch][0];
            p_sys->x[ch][0] = x;

            /* Second filter */
            if( p_sys->b_2eqz )
            {
                const float x2 = EQZ_IN_FACTOR * x + o;
450
                o = 0.0f;
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
                for( j = 0; j < p_sys->i_band; j++ )
                {
                    float y = p_sys->f_alpha[j] * ( x2 - p_sys->x2[ch][1] ) +
                              p_sys->f_gamma[j] * p_sys->y2[ch][j][0] -
                              p_sys->f_beta[j]  * p_sys->y2[ch][j][1];

                    p_sys->y2[ch][j][1] = p_sys->y2[ch][j][0];
                    p_sys->y2[ch][j][0] = y;

                    o += y * p_sys->f_amp[j];
                }
                p_sys->x2[ch][1] = p_sys->x2[ch][0];
                p_sys->x2[ch][0] = x2;

                /* We add source PCM + filtered PCM */
                out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x2 + o );
            }
            else
            {
                /* We add source PCM + filtered PCM */
                out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o );
            }
        }

        in  += i_channels;
        out += i_channels;
    }
478
    vlc_mutex_unlock( &p_sys->lock );
479 480
}

481
static void EqzClean( filter_t *p_filter )
482
{
483 484
    filter_sys_t *p_sys = p_filter->p_sys;
    vlc_object_t *p_aout = p_filter->p_parent;
485

486 487 488 489
    var_DelCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
    var_DelCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
    var_DelCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
    var_DelCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
490

491 492 493 494 495
    free( p_sys->f_alpha );
    free( p_sys->f_beta );
    free( p_sys->f_gamma );

    free( p_sys->f_amp );
496
    free( p_sys->psz_newbands );
497 498 499
}


500
static int PresetCallback( vlc_object_t *p_aout, char const *psz_cmd,
501
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
502
{
Rafaël Carré's avatar
Rafaël Carré committed
503
    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
504
    filter_sys_t *p_sys = p_data;
505

506
    const char *psz_preset = newval.psz_string;
507

508
    vlc_mutex_lock( &p_sys->lock );
509
    if( !*psz_preset || p_sys->i_band != 10 )
510 511
    {
        vlc_mutex_unlock( &p_sys->lock );
512
        return VLC_SUCCESS;
513
    }
514

515
    for( unsigned i = 0; i < NB_PRESETS; i++ )
516
    {
517
        if( !strcasecmp( eqz_preset_10b[i].psz_name, psz_preset ) )
518
        {
519 520
            char *psz_newbands = NULL;

521
            p_sys->f_gamp *= powf( 10.0f, eqz_preset_10b[i].f_preamp / 20.0f );
522
            for( int j = 0; j < p_sys->i_band; j++ )
523
            {
524 525 526
                lldiv_t d;
                char *psz;

527 528
                p_sys->f_amp[j] = EqzConvertdB( eqz_preset_10b[i].f_amp[j] );
                d = lldiv( eqz_preset_10b[i].f_amp[j] * 10000000, 10000000 );
529 530 531
                if( asprintf( &psz, "%s %lld.%07llu",
                              psz_newbands ? psz_newbands : "",
                              d.quot, d.rem ) == -1 )
532
                {
533
                    free( psz_newbands );
534
                    vlc_mutex_unlock( &p_sys->lock );
535
                    return VLC_ENOMEM;
536
                }
537
                free( psz_newbands );
538
                psz_newbands = psz;
539
            }
Rémi Duraffort's avatar
Rémi Duraffort committed
540
            if( !p_sys->b_first )
541
            {
542
                vlc_mutex_unlock( &p_sys->lock );
543 544
                var_SetString( p_aout, "equalizer-bands", psz_newbands );
                var_SetFloat( p_aout, "equalizer-preamp",
545
                              eqz_preset_10b[i].f_preamp );
546 547 548 549 550
                free( psz_newbands );
            }
            else
            {
                p_sys->psz_newbands = psz_newbands;
551
                p_sys->f_newpreamp = eqz_preset_10b[i].f_preamp;
552
                vlc_mutex_unlock( &p_sys->lock );
553 554
            }
            return VLC_SUCCESS;
555 556
        }
    }
Rémi Duraffort's avatar
Rémi Duraffort committed
557
    vlc_mutex_unlock( &p_sys->lock );
558 559
    msg_Err( p_aout, "equalizer preset '%s' not found", psz_preset );
    msg_Info( p_aout, "full list:" );
560 561
    for( unsigned i = 0; i < NB_PRESETS; i++ )
         msg_Info( p_aout, "  - '%s'", eqz_preset_10b[i].psz_name );
562 563 564 565
    return VLC_SUCCESS;
}

static int PreampCallback( vlc_object_t *p_this, char const *psz_cmd,
566
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
567
{
Rafaël Carré's avatar
Rafaël Carré committed
568
    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
569
    filter_sys_t *p_sys = p_data;
570

571 572 573 574
    if( newval.f_float < -20.0f )
        newval.f_float = -20.0f;
    else if( newval.f_float > 20.0f )
        newval.f_float = 20.0f;
575 576

    vlc_mutex_lock( &p_sys->lock );
577
    p_sys->f_gamp = powf( 10.0f, newval.f_float / 20.0f );
578
    vlc_mutex_unlock( &p_sys->lock );
579 580 581 582 583

    return VLC_SUCCESS;
}

static int BandsCallback( vlc_object_t *p_this, char const *psz_cmd,
584
                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
585
{
Rafaël Carré's avatar
Rafaël Carré committed
586
    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
587
    filter_sys_t *p_sys = p_data;
588 589
    const char *psz_bands = newval.psz_string;
    const char *p = psz_bands;
590
    char *psz_next;
591 592

    /* Same thing for bands */
593
    vlc_mutex_lock( &p_sys->lock );
594
    for( int i = 0; i < p_sys->i_band; i++ )
595
    {
596
        float f;
597

598 599 600 601
        if( *psz_bands == '\0' )
            break;

        /* Read dB -20/20 */
602 603
        f = us_strtof( p, &psz_next );

604 605
        if( psz_next == p )
            break; /* no conversion */
606

607
        p_sys->f_amp[i] = EqzConvertdB( f );
608

609 610 611
        if( *psz_next == '\0' )
            break; /* end of line */
        p = &psz_next[1];
612
    }
613
    vlc_mutex_unlock( &p_sys->lock );
614
    return VLC_SUCCESS;
615
}
616 617 618 619
static int TwoPassCallback( vlc_object_t *p_this, char const *psz_cmd,
                            vlc_value_t oldval, vlc_value_t newval, void *p_data )
{
    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
620
    filter_sys_t *p_sys = p_data;
621

622
    vlc_mutex_lock( &p_sys->lock );
623
    p_sys->b_2eqz = newval.b_bool;
624
    vlc_mutex_unlock( &p_sys->lock );
625
    return VLC_SUCCESS;
626
}
627