d3d11: handle VLC_CODEC_D3D11_OPAQUE_10B upload/download
[vlc.git] / modules / audio_filter / equalizer.c
blobf83d4599caba5d237aac0627c89afc9f6f4c7649
1 /*****************************************************************************
2 * equalizer.c:
3 *****************************************************************************
4 * Copyright (C) 2004-2012 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
25 * Preamble
26 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <math.h>
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_charset.h>
38 #include <vlc_aout.h>
39 #include <vlc_filter.h>
41 #include "equalizer_presets.h"
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 * - ...
52 /*****************************************************************************
53 * Module descriptor
54 *****************************************************************************/
55 static int Open ( vlc_object_t * );
56 static void Close( vlc_object_t * );
58 #define PRESET_TEXT N_( "Equalizer preset" )
59 #define PRESET_LONGTEXT N_("Preset to use for the equalizer." )
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\"." )
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." )
72 #define TWOPASS_TEXT N_( "Two pass" )
73 #define TWOPASS_LONGTEXT N_( "Filter the audio twice. This provides a more " \
74 "intense effect.")
76 #define PREAMP_TEXT N_("Global gain" )
77 #define PREAMP_LONGTEXT N_("Set the global gain in dB (-20 ... 20)." )
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 )
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 ()
101 /*****************************************************************************
102 * Local prototypes
103 *****************************************************************************/
104 struct filter_sys_t
106 /* Filter static config */
107 int i_band;
108 float *f_alpha;
109 float *f_beta;
110 float *f_gamma;
112 /* Filter dyn config */
113 float *f_amp; /* Per band amp */
114 float f_gamp; /* Global preamp */
115 bool b_2eqz;
117 /* Filter state */
118 float x[32][2];
119 float y[32][128][2];
121 /* Second filter state */
122 float x2[32][2];
123 float y2[32][128][2];
125 vlc_mutex_t lock;
128 static block_t *DoWork( filter_t *, block_t * );
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 * );
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 * );
146 /*****************************************************************************
147 * Open:
148 *****************************************************************************/
149 static int Open( vlc_object_t *p_this )
151 filter_t *p_filter = (filter_t *)p_this;
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;
158 vlc_mutex_init( &p_sys->lock );
159 if( EqzInit( p_filter, p_filter->fmt_in.audio.i_rate ) != VLC_SUCCESS )
161 vlc_mutex_destroy( &p_sys->lock );
162 free( p_sys );
163 return VLC_EGENERIC;
166 p_filter->fmt_in.audio.i_format = VLC_CODEC_FL32;
167 aout_FormatPrepare(&p_filter->fmt_in.audio);
168 p_filter->fmt_out.audio = p_filter->fmt_in.audio;
169 p_filter->pf_audio_filter = DoWork;
171 return VLC_SUCCESS;
174 /*****************************************************************************
175 * Close: close the plugin
176 *****************************************************************************/
177 static void Close( vlc_object_t *p_this )
179 filter_t *p_filter = (filter_t *)p_this;
180 filter_sys_t *p_sys = p_filter->p_sys;
182 EqzClean( p_filter );
183 vlc_mutex_destroy( &p_sys->lock );
184 free( p_sys );
187 /*****************************************************************************
188 * DoWork: process samples buffer
189 *****************************************************************************
191 *****************************************************************************/
192 static block_t * DoWork( filter_t * p_filter, block_t * p_in_buf )
194 EqzFilter( p_filter, (float*)p_in_buf->p_buffer,
195 (float*)p_in_buf->p_buffer, p_in_buf->i_nb_samples,
196 aout_FormatNbChannels( &p_filter->fmt_in.audio ) );
197 return p_in_buf;
200 /*****************************************************************************
201 * Equalizer stuff
202 *****************************************************************************/
203 typedef struct
205 int i_band;
207 struct
209 float f_frequency;
210 float f_alpha;
211 float f_beta;
212 float f_gamma;
213 } band[EQZ_BANDS_MAX];
215 } eqz_config_t;
217 /* Equalizer coefficient calculation function based on equ-xmms */
218 static void EqzCoeffs( int i_rate, float f_octave_percent,
219 bool b_use_vlc_freqs,
220 eqz_config_t *p_eqz_config )
222 const float *f_freq_table_10b = b_use_vlc_freqs
223 ? f_vlc_frequency_table_10b
224 : f_iso_frequency_table_10b;
225 float f_rate = (float) i_rate;
226 float f_nyquist_freq = 0.5f * f_rate;
227 float f_octave_factor = powf( 2.0f, 0.5f * f_octave_percent );
228 float f_octave_factor_1 = 0.5f * ( f_octave_factor + 1.0f );
229 float f_octave_factor_2 = 0.5f * ( f_octave_factor - 1.0f );
231 p_eqz_config->i_band = EQZ_BANDS_MAX;
233 for( int i = 0; i < EQZ_BANDS_MAX; i++ )
235 float f_freq = f_freq_table_10b[i];
237 p_eqz_config->band[i].f_frequency = f_freq;
239 if( f_freq <= f_nyquist_freq )
241 float f_theta_1 = ( 2.0f * (float) M_PI * f_freq ) / f_rate;
242 float f_theta_2 = f_theta_1 / f_octave_factor;
243 float f_sin = sinf( f_theta_2 );
244 float f_sin_prd = sinf( f_theta_2 * f_octave_factor_1 )
245 * sinf( f_theta_2 * f_octave_factor_2 );
246 float f_sin_hlf = f_sin * 0.5f;
247 float f_den = f_sin_hlf + f_sin_prd;
249 p_eqz_config->band[i].f_alpha = f_sin_prd / f_den;
250 p_eqz_config->band[i].f_beta = ( f_sin_hlf - f_sin_prd ) / f_den;
251 p_eqz_config->band[i].f_gamma = f_sin * cosf( f_theta_1 ) / f_den;
253 else
255 /* Any frequency beyond the Nyquist frequency is no good... */
256 p_eqz_config->band[i].f_alpha =
257 p_eqz_config->band[i].f_beta =
258 p_eqz_config->band[i].f_gamma = 0.0f;
263 static inline float EqzConvertdB( float db )
265 /* Map it to gain,
266 * (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)
267 * db = 20*log( out / in ) with out = in + amp*iir(i/EQZ_IN_FACTOR)
268 * or iir(i) == i for the center freq so
269 * db = 20*log( 1 + amp/EQZ_IN_FACTOR )
270 * -> amp = EQZ_IN_FACTOR*(10^(db/20) - 1)
273 if( db < -20.0f )
274 db = -20.0f;
275 else if( db > 20.0f )
276 db = 20.0f;
277 return EQZ_IN_FACTOR * ( powf( 10.0f, db / 20.0f ) - 1.0f );
280 static int EqzInit( filter_t *p_filter, int i_rate )
282 filter_sys_t *p_sys = p_filter->p_sys;
283 eqz_config_t cfg;
284 int i, ch;
285 vlc_value_t val1, val2, val3;
286 vlc_object_t *p_aout = p_filter->obj.parent;
287 int i_ret = VLC_ENOMEM;
289 bool b_vlcFreqs = var_InheritBool( p_aout, "equalizer-vlcfreqs" );
290 EqzCoeffs( i_rate, 1.0f, b_vlcFreqs, &cfg );
292 /* Create the static filter config */
293 p_sys->i_band = cfg.i_band;
294 p_sys->f_alpha = vlc_alloc( p_sys->i_band, sizeof(float) );
295 p_sys->f_beta = vlc_alloc( p_sys->i_band, sizeof(float) );
296 p_sys->f_gamma = vlc_alloc( p_sys->i_band, sizeof(float) );
297 if( !p_sys->f_alpha || !p_sys->f_beta || !p_sys->f_gamma )
298 goto error;
300 for( i = 0; i < p_sys->i_band; i++ )
302 p_sys->f_alpha[i] = cfg.band[i].f_alpha;
303 p_sys->f_beta[i] = cfg.band[i].f_beta;
304 p_sys->f_gamma[i] = cfg.band[i].f_gamma;
307 /* Filter dyn config */
308 p_sys->b_2eqz = false;
309 p_sys->f_gamp = 1.0f;
310 p_sys->f_amp = vlc_alloc( p_sys->i_band, sizeof(float) );
311 if( !p_sys->f_amp )
312 goto error;
314 for( i = 0; i < p_sys->i_band; i++ )
316 p_sys->f_amp[i] = 0.0f;
319 /* Filter state */
320 for( ch = 0; ch < 32; ch++ )
322 p_sys->x[ch][0] =
323 p_sys->x[ch][1] =
324 p_sys->x2[ch][0] =
325 p_sys->x2[ch][1] = 0.0f;
327 for( i = 0; i < p_sys->i_band; i++ )
329 p_sys->y[ch][i][0] =
330 p_sys->y[ch][i][1] =
331 p_sys->y2[ch][i][0] =
332 p_sys->y2[ch][i][1] = 0.0f;
336 var_Create( p_aout, "equalizer-bands", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
337 var_Create( p_aout, "equalizer-preset", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
339 p_sys->b_2eqz = var_CreateGetBool( p_aout, "equalizer-2pass" );
341 var_Create( p_aout, "equalizer-preamp", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT );
343 /* Get initial values */
344 var_Get( p_aout, "equalizer-preset", &val1 );
345 var_Get( p_aout, "equalizer-bands", &val2 );
346 var_Get( p_aout, "equalizer-preamp", &val3 );
348 /* Load the preset only if equalizer-bands is not set. */
349 if ( val2.psz_string == NULL || *val2.psz_string == '\0' )
350 PresetCallback( VLC_OBJECT( p_aout ), NULL, val1, val1, p_sys );
351 free( val1.psz_string );
352 BandsCallback( VLC_OBJECT( p_aout ), NULL, val2, val2, p_sys );
353 PreampCallback( VLC_OBJECT( p_aout ), NULL, val3, val3, p_sys );
355 /* Exit if we have no preset and no bands value */
356 if (!val2.psz_string || !*val2.psz_string)
358 msg_Err(p_filter, "No preset selected");
359 free( val2.psz_string );
360 free( p_sys->f_amp );
361 i_ret = VLC_EGENERIC;
362 goto error;
364 free( val2.psz_string );
366 /* Add our own callbacks */
367 var_AddCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
368 var_AddCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
369 var_AddCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
370 var_AddCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
372 msg_Dbg( p_filter, "equalizer loaded for %d Hz with %d bands %d pass",
373 i_rate, p_sys->i_band, p_sys->b_2eqz ? 2 : 1 );
374 for( i = 0; i < p_sys->i_band; i++ )
376 msg_Dbg( p_filter, " %.2f Hz -> factor:%f alpha:%f beta:%f gamma:%f",
377 cfg.band[i].f_frequency, p_sys->f_amp[i],
378 p_sys->f_alpha[i], p_sys->f_beta[i], p_sys->f_gamma[i]);
380 return VLC_SUCCESS;
382 error:
383 free( p_sys->f_alpha );
384 free( p_sys->f_beta );
385 free( p_sys->f_gamma );
386 return i_ret;
389 static void EqzFilter( filter_t *p_filter, float *out, float *in,
390 int i_samples, int i_channels )
392 filter_sys_t *p_sys = p_filter->p_sys;
393 int i, ch, j;
395 vlc_mutex_lock( &p_sys->lock );
396 for( i = 0; i < i_samples; i++ )
398 for( ch = 0; ch < i_channels; ch++ )
400 const float x = in[ch];
401 float o = 0.0f;
403 for( j = 0; j < p_sys->i_band; j++ )
405 float y = p_sys->f_alpha[j] * ( x - p_sys->x[ch][1] ) +
406 p_sys->f_gamma[j] * p_sys->y[ch][j][0] -
407 p_sys->f_beta[j] * p_sys->y[ch][j][1];
409 p_sys->y[ch][j][1] = p_sys->y[ch][j][0];
410 p_sys->y[ch][j][0] = y;
412 o += y * p_sys->f_amp[j];
414 p_sys->x[ch][1] = p_sys->x[ch][0];
415 p_sys->x[ch][0] = x;
417 /* Second filter */
418 if( p_sys->b_2eqz )
420 const float x2 = EQZ_IN_FACTOR * x + o;
421 o = 0.0f;
422 for( j = 0; j < p_sys->i_band; j++ )
424 float y = p_sys->f_alpha[j] * ( x2 - p_sys->x2[ch][1] ) +
425 p_sys->f_gamma[j] * p_sys->y2[ch][j][0] -
426 p_sys->f_beta[j] * p_sys->y2[ch][j][1];
428 p_sys->y2[ch][j][1] = p_sys->y2[ch][j][0];
429 p_sys->y2[ch][j][0] = y;
431 o += y * p_sys->f_amp[j];
433 p_sys->x2[ch][1] = p_sys->x2[ch][0];
434 p_sys->x2[ch][0] = x2;
436 /* We add source PCM + filtered PCM */
437 out[ch] = p_sys->f_gamp * p_sys->f_gamp *( EQZ_IN_FACTOR * x2 + o );
439 else
441 /* We add source PCM + filtered PCM */
442 out[ch] = p_sys->f_gamp *( EQZ_IN_FACTOR * x + o );
446 in += i_channels;
447 out += i_channels;
449 vlc_mutex_unlock( &p_sys->lock );
452 static void EqzClean( filter_t *p_filter )
454 filter_sys_t *p_sys = p_filter->p_sys;
455 vlc_object_t *p_aout = p_filter->obj.parent;
457 var_DelCallback( p_aout, "equalizer-bands", BandsCallback, p_sys );
458 var_DelCallback( p_aout, "equalizer-preset", PresetCallback, p_sys );
459 var_DelCallback( p_aout, "equalizer-preamp", PreampCallback, p_sys );
460 var_DelCallback( p_aout, "equalizer-2pass", TwoPassCallback, p_sys );
462 free( p_sys->f_alpha );
463 free( p_sys->f_beta );
464 free( p_sys->f_gamma );
466 free( p_sys->f_amp );
470 static int PresetCallback( vlc_object_t *p_aout, char const *psz_cmd,
471 vlc_value_t oldval, vlc_value_t newval, void *p_data )
473 const eqz_preset_t *preset = NULL;
474 const char *psz_preset = newval.psz_string;
476 for( unsigned i = 0; i < NB_PRESETS; i++ )
477 if( !strcasecmp( eqz_preset_10b[i].psz_name, psz_preset ) )
479 preset = eqz_preset_10b + i;
480 break;
483 if( preset == NULL )
485 msg_Err( p_aout, "equalizer preset '%s' not found", psz_preset );
486 msg_Info( p_aout, "full list:" );
487 for( unsigned i = 0; i < NB_PRESETS; i++ )
488 msg_Info( p_aout, " - '%s'", eqz_preset_10b[i].psz_name );
489 return VLC_EGENERIC;
492 char *bands = NULL;
494 for( unsigned i = 0; i < EQZ_BANDS_MAX; i++ )
496 char *psz;
498 lldiv_t d = lldiv( lroundf(preset->f_amp[i] * 10000000.f), 10000000 );
500 if( asprintf( &psz, "%s %lld.%07llu", i ? bands : "",
501 d.quot, d.rem ) == -1 )
502 psz = NULL;
504 free( bands );
505 if( unlikely(psz == NULL) )
506 return VLC_ENOMEM;
507 bands = psz;
510 var_SetFloat( p_aout, "equalizer-preamp", preset->f_preamp );
511 var_SetString( p_aout, "equalizer-bands", bands );
512 free( bands );
513 (void) psz_cmd; (void) oldval; (void) p_data;
514 return VLC_SUCCESS;
517 static int PreampCallback( vlc_object_t *p_this, char const *psz_cmd,
518 vlc_value_t oldval, vlc_value_t newval, void *p_data )
520 VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
521 filter_sys_t *p_sys = p_data;
522 float preamp;
524 if( newval.f_float < -20.f )
525 preamp = .1f;
526 else if( newval.f_float < 20.f )
527 preamp = powf( 10.f, newval.f_float / 20.f );
528 else
529 preamp = 10.f;
531 vlc_mutex_lock( &p_sys->lock );
532 p_sys->f_gamp = preamp;
533 vlc_mutex_unlock( &p_sys->lock );
534 return VLC_SUCCESS;
537 static int BandsCallback( vlc_object_t *p_this, char const *psz_cmd,
538 vlc_value_t oldval, vlc_value_t newval, void *p_data )
540 VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
541 filter_sys_t *p_sys = p_data;
542 const char *p = newval.psz_string;
543 int i = 0;
545 /* Same thing for bands */
546 vlc_mutex_lock( &p_sys->lock );
547 while( i < p_sys->i_band )
549 char *next;
550 /* Read dB -20/20 */
551 float f = us_strtof( p, &next );
552 if( next == p || isnan( f ) )
553 break; /* no conversion */
555 p_sys->f_amp[i++] = EqzConvertdB( f );
557 if( *next == '\0' )
558 break; /* end of line */
559 p = &next[1];
561 while( i < p_sys->i_band )
562 p_sys->f_amp[i++] = EqzConvertdB( 0.f );
563 vlc_mutex_unlock( &p_sys->lock );
564 return VLC_SUCCESS;
566 static int TwoPassCallback( vlc_object_t *p_this, char const *psz_cmd,
567 vlc_value_t oldval, vlc_value_t newval, void *p_data )
569 VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
570 filter_sys_t *p_sys = p_data;
572 vlc_mutex_lock( &p_sys->lock );
573 p_sys->b_2eqz = newval.b_bool;
574 vlc_mutex_unlock( &p_sys->lock );
575 return VLC_SUCCESS;