00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <stdlib.h>
00035 #include <string.h>
00036
00037 #include <errno.h>
00038 #include <stdio.h>
00039 #include <ctype.h>
00040 #include <signal.h>
00041
00042 #include <math.h>
00043
00044
00045 #include <vlc/vlc.h>
00046 #include <vlc/aout.h>
00047
00048 #include <aout_internal.h>
00049
00050
00051
00052
00053
00054 static int Open ( vlc_object_t * );
00055 static void Close ( vlc_object_t * );
00056 static void DoWork ( aout_instance_t * , aout_filter_t *,
00057 aout_buffer_t * , aout_buffer_t *);
00058
00059 typedef struct aout_filter_sys_t
00060 {
00061 int i_nb;
00062 float *p_last;
00063 float f_max;
00064 } aout_filter_sys_t;
00065
00066
00067
00068
00069 #define BUFF_TEXT N_("Number of audio buffers" )
00070 #define BUFF_LONGTEXT N_("This is the number of audio buffers on which the " \
00071 "power measurement is made. A higher number of buffers will " \
00072 "increase the response time of the filter to a high " \
00073 "power but will make it less sensitive to short variations." )
00074
00075 #define LEVEL_TEXT N_("Max level" )
00076 #define LEVEL_LONGTEXT N_("If the average power over the last N buffers " \
00077 "is higher than this value, the volume will be normalized. " \
00078 "This value is a positive floating point number. A value " \
00079 "between 0.5 and 10 seems sensible." )
00080
00081 vlc_module_begin();
00082 set_description( _("Volume normalizer") );
00083 set_shortname( N_("Volume normalizer") );
00084 set_category( CAT_AUDIO );
00085 set_subcategory( SUBCAT_AUDIO_AFILTER );
00086 add_shortcut( "volnorm" );
00087 add_integer( "norm-buff-size", 20 ,NULL ,BUFF_TEXT, BUFF_LONGTEXT,
00088 VLC_TRUE);
00089 add_float( "norm-max-level", 2.0, NULL, LEVEL_TEXT,
00090 LEVEL_LONGTEXT, VLC_TRUE );
00091 set_capability( "audio filter", 0 );
00092 set_callbacks( Open, Close );
00093 vlc_module_end();
00094
00095
00096
00097
00098 static int Open( vlc_object_t *p_this )
00099 {
00100 aout_filter_t *p_filter = (aout_filter_t*)p_this;
00101 vlc_bool_t b_fit = VLC_TRUE;
00102 int i_channels;
00103 aout_filter_sys_t *p_sys = p_filter->p_sys =
00104 malloc( sizeof( aout_filter_sys_t ) );
00105
00106 if( p_filter->input.i_format != VLC_FOURCC('f','l','3','2' ) ||
00107 p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
00108 {
00109 b_fit = VLC_FALSE;
00110 p_filter->input.i_format = VLC_FOURCC('f','l','3','2');
00111 p_filter->output.i_format = VLC_FOURCC('f','l','3','2');
00112 msg_Warn( p_filter, "Bad input or output format" );
00113 }
00114
00115 if ( !AOUT_FMTS_SIMILAR( &p_filter->input, &p_filter->output ) )
00116 {
00117 b_fit = VLC_FALSE;
00118 memcpy( &p_filter->output, &p_filter->input,
00119 sizeof(audio_sample_format_t) );
00120 msg_Warn( p_filter, "input and output formats are not similar" );
00121 }
00122
00123 if ( ! b_fit )
00124 {
00125 return VLC_EGENERIC;
00126 }
00127
00128 p_filter->pf_do_work = DoWork;
00129 p_filter->b_in_place = VLC_TRUE;
00130
00131 i_channels = aout_FormatNbChannels( &p_filter->input );
00132
00133 p_sys->i_nb = var_CreateGetInteger( p_filter->p_parent, "norm-buff-size" );
00134 p_sys->f_max = var_CreateGetFloat( p_filter->p_parent, "norm-max-level" );
00135
00136 if( p_sys->f_max <= 0 ) p_sys->f_max = 0.01;
00137
00138
00139 p_sys->p_last = malloc( sizeof( float ) * (i_channels) *
00140 (p_filter->p_sys->i_nb + 2) );
00141 memset( p_sys->p_last, 0 ,sizeof( float ) * (i_channels) *
00142 (p_filter->p_sys->i_nb + 2) );
00143 return VLC_SUCCESS;
00144 }
00145
00146
00147
00148
00149 static void DoWork( aout_instance_t *p_aout, aout_filter_t *p_filter,
00150 aout_buffer_t *p_in_buf, aout_buffer_t *p_out_buf )
00151 {
00152 float *pf_sum;
00153 float *pf_gain;
00154 float f_average = 0;
00155 int i, i_chan;
00156
00157 int i_samples = p_in_buf->i_nb_samples;
00158 int i_channels = aout_FormatNbChannels( &p_filter->input );
00159 float *p_out = (float*)p_out_buf->p_buffer;
00160 float *p_in = (float*)p_in_buf->p_buffer;
00161
00162 struct aout_filter_sys_t *p_sys = p_filter->p_sys;
00163
00164 pf_sum = (float *)malloc( sizeof(float) * i_channels );
00165 memset( pf_sum, 0, sizeof(float) * i_channels );
00166
00167 pf_gain = (float *)malloc( sizeof(float) * i_channels );
00168
00169 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
00170 p_out_buf->i_nb_bytes = p_in_buf->i_nb_bytes;
00171
00172
00173 for( i = 0 ; i < i_samples; i++ )
00174 {
00175 for( i_chan = 0; i_chan < i_channels; i_chan++ )
00176 {
00177 float f_sample = p_in[i_chan];
00178 float f_square = pow( f_sample, 2 );
00179 pf_sum[i_chan] += f_square;
00180 }
00181 p_in += i_channels;
00182 }
00183
00184
00185 for( i_chan = 0; i_chan < i_channels; i_chan++ )
00186 {
00187
00188 memmove( &p_sys->p_last[ i_chan * p_sys->i_nb],
00189 &p_sys->p_last[i_chan * p_sys->i_nb + 1],
00190 (p_sys->i_nb-1) * sizeof( float ) );
00191
00192
00193 p_sys->p_last[ i_chan * p_sys->i_nb + p_sys->i_nb - 1] =
00194 sqrt( pf_sum[i_chan] );
00195
00196 pf_sum[i_chan] = 0;
00197
00198
00199 f_average = 0;
00200 for( i = 0; i < p_sys->i_nb ; i++)
00201 {
00202 f_average += p_sys->p_last[ i_chan * p_sys->i_nb + i ];
00203 }
00204 f_average = f_average / p_sys->i_nb;
00205
00206
00207 p_sys->f_max = var_GetFloat( p_aout, "norm-max-level" );
00208
00209
00210 if( f_average > p_sys->f_max )
00211 {
00212 pf_gain[i_chan] = f_average / p_sys->f_max;
00213 }
00214 else
00215 {
00216 pf_gain[i_chan] = 1;
00217 }
00218 }
00219
00220
00221 for( i = 0; i < i_samples; i++)
00222 {
00223 for( i_chan = 0; i_chan < i_channels; i_chan++ )
00224 {
00225 p_out[i_chan] /= pf_gain[i_chan];
00226 }
00227 p_out += i_channels;
00228 }
00229
00230 free( pf_sum );
00231 free( pf_gain );
00232
00233 return;
00234 }
00235
00236
00237
00238
00239 static void Close( vlc_object_t *p_this )
00240 {
00241 aout_filter_t *p_filter = (aout_filter_t*)p_this;
00242 aout_filter_sys_t *p_sys = p_filter->p_sys;
00243
00244 if( p_sys )
00245 {
00246 if( p_sys->p_last) free( p_sys->p_last );
00247 free( p_sys );
00248 }
00249 }