]> git.sesse.net Git - vlc/blob - modules/audio_filter/equalizer.c
mediacodec: handle error_state in one place
[vlc] / modules / audio_filter / equalizer.c
1 /*****************************************************************************
2  * equalizer.c:
3  *****************************************************************************
4  * Copyright (C) 2004-2012 VLC authors and VideoLAN
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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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.0f, 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     /* Filter dyn config */
113     float *f_amp;   /* Per band amp */
114     float f_gamp;   /* Global preamp */
115     bool b_2eqz;
116
117     /* Filter state */
118     float x[32][2];
119     float y[32][128][2];
120
121     /* Second filter state */
122     float x2[32][2];
123     float y2[32][128][2];
124
125     vlc_mutex_t lock;
126 };
127
128 static block_t *DoWork( filter_t *, block_t * );
129
130 #define EQZ_IN_FACTOR (0.25f)
131 static int  EqzInit( filter_t *, int );
132 static void EqzFilter( filter_t *, float *, float *, int, int );
133 static void EqzClean( filter_t * );
134
135 static int PresetCallback ( vlc_object_t *, char const *, vlc_value_t,
136                             vlc_value_t, void * );
137 static int PreampCallback ( vlc_object_t *, char const *, vlc_value_t,
138                             vlc_value_t, void * );
139 static int BandsCallback  ( vlc_object_t *, char const *, vlc_value_t,
140                             vlc_value_t, void * );
141 static int TwoPassCallback( vlc_object_t *, char const *, vlc_value_t,
142                             vlc_value_t, void * );
143
144
145
146 /*****************************************************************************
147  * Open:
148  *****************************************************************************/
149 static int Open( vlc_object_t *p_this )
150 {
151     filter_t     *p_filter = (filter_t *)p_this;
152
153     /* Allocate structure */
154     filter_sys_t *p_sys = p_filter->p_sys = malloc( sizeof( *p_sys ) );
155     if( !p_sys )
156         return VLC_ENOMEM;
157
158     vlc_mutex_init( &p_sys->lock );
159     if( EqzInit( p_filter, p_filter->fmt_in.audio.i_rate ) != VLC_SUCCESS )
160     {
161         vlc_mutex_destroy( &p_sys->lock );
162         free( p_sys );
163         return VLC_EGENERIC;
164     }
165
166     p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
167     p_filter->fmt_out.audio = p_filter->fmt_in.audio;
168     p_filter->pf_audio_filter = DoWork;
169
170     return VLC_SUCCESS;
171 }
172
173 /*****************************************************************************
174  * Close: close the plugin
175  *****************************************************************************/
176 static void Close( vlc_object_t *p_this )
177 {
178     filter_t     *p_filter = (filter_t *)p_this;
179     filter_sys_t *p_sys = p_filter->p_sys;
180
181     EqzClean( p_filter );
182     vlc_mutex_destroy( &p_sys->lock );
183     free( p_sys );
184 }
185
186 /*****************************************************************************
187  * DoWork: process samples buffer
188  *****************************************************************************
189  *
190  *****************************************************************************/
191 static block_t * DoWork( filter_t * p_filter, block_t * p_in_buf )
192 {
193     EqzFilter( p_filter, (float*)p_in_buf->p_buffer,
194                (float*)p_in_buf->p_buffer, p_in_buf->i_nb_samples,
195                aout_FormatNbChannels( &p_filter->fmt_in.audio ) );
196     return p_in_buf;
197 }
198
199 /*****************************************************************************
200  * Equalizer stuff
201  *****************************************************************************/
202 typedef struct
203 {
204     int   i_band;
205
206     struct
207     {
208         float f_frequency;
209         float f_alpha;
210         float f_beta;
211         float f_gamma;
212     } band[EQZ_BANDS_MAX];
213
214 } eqz_config_t;
215
216 /* Equalizer coefficient calculation function based on equ-xmms */
217 static void EqzCoeffs( int i_rate, float f_octave_percent,
218                        bool b_use_vlc_freqs,
219                        eqz_config_t *p_eqz_config )
220 {
221     const float *f_freq_table_10b = b_use_vlc_freqs
222                                   ? f_vlc_frequency_table_10b
223                                   : f_iso_frequency_table_10b;
224     float f_rate = (float) i_rate;
225     float f_nyquist_freq = 0.5f * f_rate;
226     float f_octave_factor = powf( 2.0f, 0.5f * f_octave_percent );
227     float f_octave_factor_1 = 0.5f * ( f_octave_factor + 1.0f );
228     float f_octave_factor_2 = 0.5f * ( f_octave_factor - 1.0f );
229
230     p_eqz_config->i_band = EQZ_BANDS_MAX;
231
232     for( int i = 0; i < EQZ_BANDS_MAX; i++ )
233     {
234         float f_freq = f_freq_table_10b[i];
235
236         p_eqz_config->band[i].f_frequency = f_freq;
237
238         if( f_freq <= f_nyquist_freq )
239         {
240             float f_theta_1 = ( 2.0f * (float) M_PI * f_freq ) / f_rate;
241             float f_theta_2 = f_theta_1 / f_octave_factor;
242             float f_sin     = sinf( f_theta_2 );
243             float f_sin_prd = sinf( f_theta_2 * f_octave_factor_1 )
244                             * sinf( f_theta_2 * f_octave_factor_2 );
245             float f_sin_hlf = f_sin * 0.5f;
246             float f_den     = f_sin_hlf + f_sin_prd;
247
248             p_eqz_config->band[i].f_alpha = f_sin_prd / f_den;
249             p_eqz_config->band[i].f_beta  = ( f_sin_hlf - f_sin_prd ) / f_den;
250             p_eqz_config->band[i].f_gamma = f_sin * cosf( f_theta_1 ) / f_den;
251         }
252         else
253         {
254             /* Any frequency beyond the Nyquist frequency is no good... */
255             p_eqz_config->band[i].f_alpha =
256             p_eqz_config->band[i].f_beta  =
257             p_eqz_config->band[i].f_gamma = 0.0f;
258         }
259     }
260 }
261
262 static inline float EqzConvertdB( float db )
263 {
264     /* Map it to gain,
265      * (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)
266      * db = 20*log( out / in ) with out = in + amp*iir(i/EQZ_IN_FACTOR)
267      * or iir(i) == i for the center freq so
268      * db = 20*log( 1 + amp/EQZ_IN_FACTOR )
269      * -> amp = EQZ_IN_FACTOR*(10^(db/20) - 1)
270      **/
271
272     if( db < -20.0f )
273         db = -20.0f;
274     else if(  db > 20.0f )
275         db = 20.0f;
276     return EQZ_IN_FACTOR * ( powf( 10.0f, db / 20.0f ) - 1.0f );
277 }
278
279 static int EqzInit( filter_t *p_filter, int i_rate )
280 {
281     filter_sys_t *p_sys = p_filter->p_sys;
282     eqz_config_t cfg;
283     int i, ch;
284     vlc_value_t val1, val2, val3;
285     vlc_object_t *p_aout = p_filter->p_parent;
286     int i_ret = VLC_ENOMEM;
287
288     bool b_vlcFreqs = var_InheritBool( p_aout, "equalizer-vlcfreqs" );
289     EqzCoeffs( i_rate, 1.0f, b_vlcFreqs, &cfg );
290
291     /* Create the static filter config */
292     p_sys->i_band = cfg.i_band;
293     p_sys->f_alpha = malloc( p_sys->i_band * sizeof(float) );
294     p_sys->f_beta  = malloc( p_sys->i_band * sizeof(float) );
295     p_sys->f_gamma = malloc( p_sys->i_band * sizeof(float) );
296     if( !p_sys->f_alpha || !p_sys->f_beta || !p_sys->f_gamma )
297         goto error;
298
299     for( i = 0; i < p_sys->i_band; i++ )
300     {
301         p_sys->f_alpha[i] = cfg.band[i].f_alpha;
302         p_sys->f_beta[i]  = cfg.band[i].f_beta;
303         p_sys->f_gamma[i] = cfg.band[i].f_gamma;
304     }
305
306     /* Filter dyn config */
307     p_sys->b_2eqz = false;
308     p_sys->f_gamp = 1.0f;
309     p_sys->f_amp  = malloc( p_sys->i_band * sizeof(float) );
310     if( !p_sys->f_amp )
311         goto error;
312
313     for( i = 0; i < p_sys->i_band; i++ )
314     {
315         p_sys->f_amp[i] = 0.0f;
316     }
317
318     /* Filter state */
319     for( ch = 0; ch < 32; ch++ )
320     {
321         p_sys->x[ch][0]  =
322         p_sys->x[ch][1]  =
323         p_sys->x2[ch][0] =
324         p_sys->x2[ch][1] = 0.0f;
325
326         for( i = 0; i < p_sys->i_band; i++ )
327         {
328             p_sys->y[ch][i][0]  =
329             p_sys->y[ch][i][1]  =
330             p_sys->y2[ch][i][0] =
331             p_sys->y2[ch][i][1] = 0.0f;
332         }
333     }
334
335     var_Create( p_aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
336     var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
337
338     p_sys->b_2eqz = var_CreateGetBool( p_aout, "equalizer-2pass" );
339
340     var_Create( p_aout, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
341
342     /* Get initial values */
343     var_Get( p_aout, "equalizer-preset", &val1 );
344     var_Get( p_aout, "equalizer-bands", &val2 );
345     var_Get( p_aout, "equalizer-preamp", &val3 );
346
347     /* Load the preset only if equalizer-bands is not set. */
348     if ( val2.psz_string == NULL || *val2.psz_string == '\0' )
349         PresetCallback( VLC_OBJECT( p_aout ), NULL, val1, val1, p_sys );
350     free( val1.psz_string );
351     BandsCallback(  VLC_OBJECT( p_aout ), NULL, val2, val2, p_sys );
352     PreampCallback( VLC_OBJECT( p_aout ), NULL, val3, val3, p_sys );
353
354     /* Exit if we have no preset and no bands value */
355     if (!val2.psz_string || !*val2.psz_string)
356     {
357         msg_Err(p_filter, "No preset selected");
358         free( val2.psz_string );
359         free( p_sys->f_amp );
360         i_ret = VLC_EGENERIC;
361         goto error;
362     }
363     free( val2.psz_string );
364
365     /* Add our own callbacks */
366     var_AddCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
367     var_AddCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
368     var_AddCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
369     var_AddCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
370
371     msg_Dbg( p_filter, "equalizer loaded for %d Hz with %d bands %d pass",
372                         i_rate, p_sys->i_band, p_sys->b_2eqz ? 2 : 1 );
373     for( i = 0; i < p_sys->i_band; i++ )
374     {
375         msg_Dbg( p_filter, "   %.2f Hz -> factor:%f alpha:%f beta:%f gamma:%f",
376                  cfg.band[i].f_frequency, p_sys->f_amp[i],
377                  p_sys->f_alpha[i], p_sys->f_beta[i], p_sys->f_gamma[i]);
378     }
379     return VLC_SUCCESS;
380
381 error:
382     free( p_sys->f_alpha );
383     free( p_sys->f_beta );
384     free( p_sys->f_gamma );
385     return i_ret;
386 }
387
388 static void EqzFilter( filter_t *p_filter, float *out, float *in,
389                        int i_samples, int i_channels )
390 {
391     filter_sys_t *p_sys = p_filter->p_sys;
392     int i, ch, j;
393
394     vlc_mutex_lock( &p_sys->lock );
395     for( i = 0; i < i_samples; i++ )
396     {
397         for( ch = 0; ch < i_channels; ch++ )
398         {
399             const float x = in[ch];
400             float o = 0.0f;
401
402             for( j = 0; j < p_sys->i_band; j++ )
403             {
404                 float y = p_sys->f_alpha[j] * ( x - p_sys->x[ch][1] ) +
405                           p_sys->f_gamma[j] * p_sys->y[ch][j][0] -
406                           p_sys->f_beta[j]  * p_sys->y[ch][j][1];
407
408                 p_sys->y[ch][j][1] = p_sys->y[ch][j][0];
409                 p_sys->y[ch][j][0] = y;
410
411                 o += y * p_sys->f_amp[j];
412             }
413             p_sys->x[ch][1] = p_sys->x[ch][0];
414             p_sys->x[ch][0] = x;
415
416             /* Second filter */
417             if( p_sys->b_2eqz )
418             {
419                 const float x2 = EQZ_IN_FACTOR * x + o;
420                 o = 0.0f;
421                 for( j = 0; j < p_sys->i_band; j++ )
422                 {
423                     float y = p_sys->f_alpha[j] * ( x2 - p_sys->x2[ch][1] ) +
424                               p_sys->f_gamma[j] * p_sys->y2[ch][j][0] -
425                               p_sys->f_beta[j]  * p_sys->y2[ch][j][1];
426
427                     p_sys->y2[ch][j][1] = p_sys->y2[ch][j][0];
428                     p_sys->y2[ch][j][0] = y;
429
430                     o += y * p_sys->f_amp[j];
431                 }
432                 p_sys->x2[ch][1] = p_sys->x2[ch][0];
433                 p_sys->x2[ch][0] = x2;
434
435                 /* We add source PCM + filtered PCM */
436                 out[ch] = p_sys->f_gamp * p_sys->f_gamp *( EQZ_IN_FACTOR * x2 + o );
437             }
438             else
439             {
440                 /* We add source PCM + filtered PCM */
441                 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o );
442             }
443         }
444
445         in  += i_channels;
446         out += i_channels;
447     }
448     vlc_mutex_unlock( &p_sys->lock );
449 }
450
451 static void EqzClean( filter_t *p_filter )
452 {
453     filter_sys_t *p_sys = p_filter->p_sys;
454     vlc_object_t *p_aout = p_filter->p_parent;
455
456     var_DelCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
457     var_DelCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
458     var_DelCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
459     var_DelCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
460
461     free( p_sys->f_alpha );
462     free( p_sys->f_beta );
463     free( p_sys->f_gamma );
464
465     free( p_sys->f_amp );
466 }
467
468
469 static int PresetCallback( vlc_object_t *p_aout, char const *psz_cmd,
470                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
471 {
472     const eqz_preset_t *preset = NULL;
473     const char *psz_preset = newval.psz_string;
474
475     for( unsigned i = 0; i < NB_PRESETS; i++ )
476         if( !strcasecmp( eqz_preset_10b[i].psz_name, psz_preset ) )
477         {
478             preset = eqz_preset_10b + i;
479             break;
480         }
481
482     if( preset == NULL )
483     {
484         msg_Err( p_aout, "equalizer preset '%s' not found", psz_preset );
485         msg_Info( p_aout, "full list:" );
486         for( unsigned i = 0; i < NB_PRESETS; i++ )
487              msg_Info( p_aout, "  - '%s'", eqz_preset_10b[i].psz_name );
488         return VLC_EGENERIC;
489     }
490
491     char *bands = NULL;
492
493     for( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
494     {
495         char *psz;
496
497         lldiv_t d = lldiv( lroundf(preset->f_amp[i] * 10000000.f), 10000000 );
498
499         if( asprintf( &psz, "%s %lld.%07llu", i ? bands : "",
500                       d.quot, d.rem ) == -1 )
501             psz = NULL;
502
503         free( bands );
504         if( unlikely(psz == NULL) )
505             return VLC_ENOMEM;
506         bands = psz;
507     }
508
509     var_SetFloat( p_aout, "equalizer-preamp", preset->f_preamp );
510     var_SetString( p_aout, "equalizer-bands", bands );
511     free( bands );
512     (void) psz_cmd; (void) oldval; (void) p_data;
513     return VLC_SUCCESS;
514 }
515
516 static int PreampCallback( vlc_object_t *p_this, char const *psz_cmd,
517                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
518 {
519     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
520     filter_sys_t *p_sys = p_data;
521     float preamp;
522
523     if( newval.f_float < -20.f )
524         preamp = .1f;
525     else if( newval.f_float < 20.f )
526         preamp = powf( 10.f, newval.f_float / 20.f );
527     else
528         preamp = 10.f;
529
530     vlc_mutex_lock( &p_sys->lock );
531     p_sys->f_gamp = preamp;
532     vlc_mutex_unlock( &p_sys->lock );
533     return VLC_SUCCESS;
534 }
535
536 static int BandsCallback( vlc_object_t *p_this, char const *psz_cmd,
537                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
538 {
539     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
540     filter_sys_t *p_sys = p_data;
541     const char *p = newval.psz_string;
542     int i = 0;
543
544     /* Same thing for bands */
545     vlc_mutex_lock( &p_sys->lock );
546     while( i < p_sys->i_band )
547     {
548         char *next;
549         /* Read dB -20/20 */
550         float f = us_strtof( p, &next );
551         if( next == p || isnan( f ) )
552             break; /* no conversion */
553
554         p_sys->f_amp[i++] = EqzConvertdB( f );
555
556         if( *next == '\0' )
557             break; /* end of line */
558         p = &next[1];
559     }
560     while( i < p_sys->i_band )
561         p_sys->f_amp[i++] = EqzConvertdB( 0.f );
562     vlc_mutex_unlock( &p_sys->lock );
563     return VLC_SUCCESS;
564 }
565 static int TwoPassCallback( vlc_object_t *p_this, char const *psz_cmd,
566                             vlc_value_t oldval, vlc_value_t newval, void *p_data )
567 {
568     VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
569     filter_sys_t *p_sys = p_data;
570
571     vlc_mutex_lock( &p_sys->lock );
572     p_sys->b_2eqz = newval.b_bool;
573     vlc_mutex_unlock( &p_sys->lock );
574     return VLC_SUCCESS;
575 }
576