equalizer.c 21 KB
Newer Older
1 2 3
/*****************************************************************************
 * equalizer.c:
 *****************************************************************************
4
 * Copyright (C) 2004-2012 the VideoLAN team
5
 * $Id$
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
21
 * 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.0, 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.25)
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 156
    filter_t     *p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys;
157

158 159
    if( p_filter->fmt_in.audio.i_format != VLC_CODEC_FL32 ||
        p_filter->fmt_out.audio.i_format != VLC_CODEC_FL32 )
160
    {
161 162
        p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
        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 171 172 173
        msg_Warn( p_filter, "input and output formats are not similar" );
        return VLC_EGENERIC;
    }

174
    p_filter->pf_audio_filter = DoWork;
175 176

    /* Allocate structure */
177
    p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
178 179
    if( !p_sys )
        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 190 191 192 193 194 195 196

    return VLC_SUCCESS;
}

/*****************************************************************************
 * Close: close the plugin
 *****************************************************************************/
static void Close( vlc_object_t *p_this )
{
197 198
    filter_t     *p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys = p_filter->p_sys;
199 200

    EqzClean( p_filter );
201
    vlc_mutex_destroy( &p_sys->lock );
202 203 204 205 206 207 208 209
    free( p_sys );
}

/*****************************************************************************
 * DoWork: process samples buffer
 *****************************************************************************
 *
 *****************************************************************************/
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 220 221 222 223 224 225 226 227 228 229 230
}

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

    struct
    {
        float f_frequency;
        float f_alpha;
        float f_beta;
        float f_gamma;
231
    } band[EQZ_BANDS_MAX];
232

233 234
} eqz_config_t;

235 236 237 238 239 240 241 242 243 244 245
/* The frequency tables */
static const float f_vlc_frequency_table_10b[EQZ_BANDS_MAX] =
{
    60, 170, 310, 600, 1000, 3000, 6000, 12000, 14000, 16000,
};

static const float f_iso_frequency_table_10b[EQZ_BANDS_MAX] =
{
    31.25, 62.5, 125, 250, 500, 1000, 2000, 4000, 8000, 16000,
};

246 247 248 249
/* 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 )
250
{
251 252 253 254 255 256 257 258 259 260 261 262
    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;
    float f_nyquist_freq = 0.5 * f_rate;
    float f_octave_factor = pow( 2.0, 0.5 * f_octave_percent );
    float f_octave_factor_1 = 0.5 * ( f_octave_factor + 1.0 );
    float f_octave_factor_2 = 0.5 * ( f_octave_factor - 1.0 );

    p_eqz_config->i_band = EQZ_BANDS_MAX;

    for( int i = 0; i < EQZ_BANDS_MAX; i++ )
263
    {
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293
        float f_freq = f_freq_table_10b[i];

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

        if( f_freq <= f_nyquist_freq )
        {
            float f_theta_1 = ( 2.0 * M_PI * f_freq ) / f_rate;
            float f_theta_2 = f_theta_1 / f_octave_factor;
            float f_sin     = sin( f_theta_2 ) * 0.5;
            float f_sin_prd = sin( f_theta_2 * f_octave_factor_1 )
                            * sin( f_theta_2 * f_octave_factor_2 );
            /* The equation from equ-xmms simplifies to something similar to
             * this when you restrict the domain to all valid frequencies at or
             * below the Nyquist frequency (the interval 0 <= f_theta_1 <= Pi).
             * (This result for the root is twice that returned by equ-xmms,
             * but the more efficient calculations for alpha, beta, and gamma
             * below compensate for this.) */
            float f_root    = ( f_sin - f_sin_prd ) / ( f_sin + f_sin_prd );

            p_eqz_config->band[i].f_alpha = ( 1.0 - f_root ) * 0.5;
            p_eqz_config->band[i].f_beta  = f_root;
            p_eqz_config->band[i].f_gamma = ( 1.0 + f_root ) * cos( f_theta_1 );
        }
        else
        {
            /* Any frequency beyond the Nyquist frequency is no good... */
            p_eqz_config->band[i].f_alpha =
            p_eqz_config->band[i].f_beta  =
            p_eqz_config->band[i].f_gamma = 0.0;
        }
294
    }
295
}
296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

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)
     **/

    if( db < -20.0 )
        db = -20.0;
    else if(  db > 20.0 )
        db = 20.0;
    return EQZ_IN_FACTOR * ( pow( 10, db / 20.0 ) - 1.0 );
}

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 324
    bool b_vlcFreqs = var_InheritBool( p_aout, "equalizer-vlcfreqs" );
    EqzCoeffs( i_rate, 1.0, b_vlcFreqs, &cfg );
325 326

    /* Create the static filter config */
327
    p_sys->i_band = cfg.i_band;
328 329 330
    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
331
    if( !p_sys->f_alpha || !p_sys->f_beta || !p_sys->f_gamma )
332
        goto error;
Rémi Duraffort's avatar
Rémi Duraffort committed
333

334 335
    for( i = 0; i < p_sys->i_band; i++ )
    {
336 337 338
        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;
339 340 341
    }

    /* Filter dyn config */
342
    p_sys->b_2eqz = false;
343
    p_sys->f_gamp = 1.0;
Rémi Duraffort's avatar
Rémi Duraffort committed
344 345
    p_sys->f_amp  = malloc( p_sys->i_band * sizeof(float) );
    if( !p_sys->f_amp )
346 347
        goto error;

348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369
    for( i = 0; i < p_sys->i_band; i++ )
    {
        p_sys->f_amp[i] = 0.0;
    }

    /* Filter state */
    for( ch = 0; ch < 32; ch++ )
    {
        p_sys->x[ch][0]  =
        p_sys->x[ch][1]  =
        p_sys->x2[ch][0] =
        p_sys->x2[ch][1] = 0.0;

        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] =
            p_sys->y2[ch][i][1] = 0.0;
        }
    }

370 371
    var_Create( p_aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    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 378 379 380
    /* Get initial values */
    var_Get( p_aout, "equalizer-preset", &val1 );
    var_Get( p_aout, "equalizer-bands", &val2 );
    var_Get( p_aout, "equalizer-preamp", &val3 );
381

382
    p_sys->b_first = true;
383 384 385
    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 );
386
    p_sys->b_first = false;
387

388 389
    free( val1.psz_string );

390 391 392
    /* 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 */
393 394 395
    if (p_sys->psz_newbands == NULL)
    {
        msg_Err(p_filter, "No preset selected");
396
        free( val2.psz_string );
Rémi Duraffort's avatar
Rémi Duraffort committed
397
        free( p_sys->f_amp );
398 399
        i_ret = VLC_EGENERIC;
        goto error;
400
    }
401 402 403 404
    if( ( *(val2.psz_string) &&
        strstr( p_sys->psz_newbands, val2.psz_string ) ) || !*val2.psz_string )
    {
        var_SetString( p_aout, "equalizer-bands", p_sys->psz_newbands );
405 406
        if( p_sys->f_newpreamp == p_sys->f_gamp )
            var_SetFloat( p_aout, "equalizer-preamp", p_sys->f_newpreamp );
407
    }
408
    free( val2.psz_string );
409 410 411 412 413

    /* 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 );
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 419 420
    for( i = 0; i < p_sys->i_band; i++ )
    {
        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 423 424
                 p_sys->f_alpha[i], p_sys->f_beta[i], p_sys->f_gamma[i]);
    }
    return VLC_SUCCESS;
425 426 427 428 429 430

error:
    free( p_sys->f_alpha );
    free( p_sys->f_beta );
    free( p_sys->f_gamma );
    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 438
    int i, ch, j;

439
    vlc_mutex_lock( &p_sys->lock );
440 441 442 443 444 445 446 447 448 449 450 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 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492
    for( i = 0; i < i_samples; i++ )
    {
        for( ch = 0; ch < i_channels; ch++ )
        {
            const float x = in[ch];
            float o = 0.0;

            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;
                o = 0.0;
                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;
    }
493
    vlc_mutex_unlock( &p_sys->lock );
494 495
}

496
static void EqzClean( filter_t *p_filter )
497
{
498 499
    filter_sys_t *p_sys = p_filter->p_sys;
    vlc_object_t *p_aout = p_filter->p_parent;
500

501 502 503 504
    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 );
505

506 507 508 509 510
    free( p_sys->f_alpha );
    free( p_sys->f_beta );
    free( p_sys->f_gamma );

    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
{
Rafaël Carré's avatar
Rafaël Carré committed
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 535
            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++ )
538
            {
539 540 541
                lldiv_t d;
                char *psz;

542 543
                p_sys->f_amp[j] = EqzConvertdB( eqz_preset_10b[i].f_amp[j] );
                d = lldiv( eqz_preset_10b[i].f_amp[j] * 10000000, 10000000 );
544 545 546
                if( asprintf( &psz, "%s %lld.%07llu",
                              psz_newbands ? psz_newbands : "",
                              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
            }
Rémi Duraffort's avatar
Rémi Duraffort committed
555
            if( !p_sys->b_first )
556
            {
557
                vlc_mutex_unlock( &p_sys->lock );
558 559
                var_SetString( p_aout, "equalizer-bands", psz_newbands );
                var_SetFloat( p_aout, "equalizer-preamp",
560
                              eqz_preset_10b[i].f_preamp );
561 562 563 564 565
                free( psz_newbands );
            }
            else
            {
                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
        }
    }
Rémi Duraffort's avatar
Rémi Duraffort committed
572
    vlc_mutex_unlock( &p_sys->lock );
573 574
    msg_Err( p_aout, "equalizer preset '%s' not found", psz_preset );
    msg_Info( p_aout, "full list:" );
575 576
    for( unsigned i = 0; i < NB_PRESETS; i++ )
         msg_Info( p_aout, "  - '%s'", eqz_preset_10b[i].psz_name );
577 578 579 580
    return VLC_SUCCESS;
}

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
{
Rafaël Carré's avatar
Rafaël Carré committed
583
    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
584
    filter_sys_t *p_sys = p_data;
585 586 587 588 589

    if( newval.f_float < -20.0 )
        newval.f_float = -20.0;
    else if( newval.f_float > 20.0 )
        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 596 597 598

    return VLC_SUCCESS;
}

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
{
Rafaël Carré's avatar
Rafaël Carré committed
601
    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
602
    filter_sys_t *p_sys = p_data;
603 604
    const char *psz_bands = newval.psz_string;
    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 614 615 616
        if( *psz_bands == '\0' )
            break;

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

619 620
        if( psz_next == p )
            break; /* no conversion */
621

622
        p_sys->f_amp[i] = EqzConvertdB( f );
623

624 625 626
        if( *psz_next == '\0' )
            break; /* end of line */
        p = &psz_next[1];
627
    }
628
    vlc_mutex_unlock( &p_sys->lock );
629
    return VLC_SUCCESS;
630
}
631 632 633 634
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);
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