equalizer.c 20.4 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
dionoea's avatar
dionoea 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 )
zorglub's avatar
zorglub 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

ivoire's avatar
ivoire committed
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 ) );
ivoire's avatar
ivoire committed
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 )
ivoire's avatar
ivoire committed
164
    {
165
        vlc_mutex_destroy( &p_sys->lock );
ivoire's avatar
ivoire committed
166
        free( p_sys );
167
        return VLC_EGENERIC;
ivoire's avatar
ivoire committed
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
223
224
225
226
227
228
229
230
/* 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,
};

231
232
233
234
/* 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 )
235
{
236
237
238
239
240
241
242
243
244
245
246
247
    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++ )
248
    {
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
        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;
        }
279
    }
280
}
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298

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 );
}

299
static int EqzInit( filter_t *p_filter, int i_rate )
300
{
301
    filter_sys_t *p_sys = p_filter->p_sys;
302
    eqz_config_t cfg;
303
    int i, ch;
304
    vlc_value_t val1, val2, val3;
305
    vlc_object_t *p_aout = p_filter->p_parent;
ivoire's avatar
ivoire committed
306
    int i_ret = VLC_ENOMEM;
307

308
309
    bool b_vlcFreqs = var_InheritBool( p_aout, "equalizer-vlcfreqs" );
    EqzCoeffs( i_rate, 1.0, b_vlcFreqs, &cfg );
310
311

    /* Create the static filter config */
312
    p_sys->i_band = cfg.i_band;
313
314
315
    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) );
ivoire's avatar
ivoire committed
316
    if( !p_sys->f_alpha || !p_sys->f_beta || !p_sys->f_gamma )
ivoire's avatar
ivoire committed
317
        goto error;
ivoire's avatar
ivoire committed
318

319
320
    for( i = 0; i < p_sys->i_band; i++ )
    {
321
322
323
        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;
324
325
326
    }

    /* Filter dyn config */
327
    p_sys->b_2eqz = false;
328
    p_sys->f_gamp = 1.0;
ivoire's avatar
ivoire committed
329
330
    p_sys->f_amp  = malloc( p_sys->i_band * sizeof(float) );
    if( !p_sys->f_amp )
ivoire's avatar
ivoire committed
331
332
        goto error;

333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
    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;
        }
    }

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

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

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

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

367
    p_sys->b_first = true;
368
369
370
    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 );
371
    p_sys->b_first = false;
372

ivoire's avatar
ivoire committed
373
374
    free( val1.psz_string );

375
376
377
    /* 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 */
378
379
380
    if (p_sys->psz_newbands == NULL)
    {
        msg_Err(p_filter, "No preset selected");
ivoire's avatar
ivoire committed
381
        free( val2.psz_string );
ivoire's avatar
ivoire committed
382
        free( p_sys->f_amp );
ivoire's avatar
ivoire committed
383
384
        i_ret = VLC_EGENERIC;
        goto error;
385
    }
386
387
388
389
    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 );
390
391
        if( p_sys->f_newpreamp == p_sys->f_gamp )
            var_SetFloat( p_aout, "equalizer-preamp", p_sys->f_newpreamp );
392
    }
ivoire's avatar
ivoire committed
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
405
    for( i = 0; i < p_sys->i_band; i++ )
    {
        msg_Dbg( p_filter, "   %d Hz -> factor:%f alpha:%f beta:%f gamma:%f",
406
                 (int)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;
ivoire's avatar
ivoire committed
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
430
431
432
433
434
435
436
437
438
439
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
    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;
    }
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

ivoire's avatar
ivoire committed
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 );
ivoire's avatar
ivoire committed
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

ivoire's avatar
ivoire committed
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 *= pow( 10, eqz_preset_10b[i].f_preamp / 20.0 );
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
            }
ivoire's avatar
ivoire 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
        }
    }
ivoire's avatar
ivoire 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.0 )
        newval.f_float = -20.0;
    else if( newval.f_float > 20.0 )
        newval.f_float = 20.0;
575
576

    vlc_mutex_lock( &p_sys->lock );
577
    p_sys->f_gamp = pow( 10, newval.f_float /20.0);
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;
ivoire's avatar
ivoire committed
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 );
ivoire's avatar
ivoire committed
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