1 /*****************************************************************************
2 * normvol.c: volume normalizer
3 *****************************************************************************
4 * Copyright (C) 2001, 2006 the VideoLAN team
7 * Authors: Clément Stenac <zorglub@videolan.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 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 General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
27 * We should detect fast power increases and react faster to these
28 * This way, we can increase the buffer size to get a more stable filter */
31 /*****************************************************************************
33 *****************************************************************************/
34 #include <stdlib.h> /* malloc(), free() */
37 #include <errno.h> /* ENOMEM */
49 /*****************************************************************************
51 *****************************************************************************/
53 static int Open ( vlc_object_t
* );
54 static void Close ( vlc_object_t
* );
55 static void DoWork ( aout_instance_t
* , aout_filter_t
*,
56 aout_buffer_t
* , aout_buffer_t
*);
58 typedef struct aout_filter_sys_t
65 /*****************************************************************************
67 *****************************************************************************/
68 #define BUFF_TEXT N_("Number of audio buffers" )
69 #define BUFF_LONGTEXT N_("This is the number of audio buffers on which the " \
70 "power measurement is made. A higher number of buffers will " \
71 "increase the response time of the filter to a spike " \
72 "but will make it less sensitive to short variations." )
74 #define LEVEL_TEXT N_("Max level" )
75 #define LEVEL_LONGTEXT N_("If the average power over the last N buffers " \
76 "is higher than this value, the volume will be normalized. " \
77 "This value is a positive floating point number. A value " \
78 "between 0.5 and 10 seems sensible." )
81 set_description( _("Volume normalizer") );
82 set_shortname( _("Volume normalizer") );
83 set_category( CAT_AUDIO
);
84 set_subcategory( SUBCAT_AUDIO_AFILTER
);
85 add_shortcut( "volnorm" );
86 add_integer( "norm-buff-size", 20 ,NULL
,BUFF_TEXT
, BUFF_LONGTEXT
,
88 add_float( "norm-max-level", 2.0, NULL
, LEVEL_TEXT
,
89 LEVEL_LONGTEXT
, VLC_TRUE
);
90 set_capability( "audio filter", 0 );
91 set_callbacks( Open
, Close
);
94 /*****************************************************************************
95 * Open: initialize and create stuff
96 *****************************************************************************/
97 static int Open( vlc_object_t
*p_this
)
99 aout_filter_t
*p_filter
= (aout_filter_t
*)p_this
;
100 vlc_bool_t b_fit
= VLC_TRUE
;
102 aout_filter_sys_t
*p_sys
;
104 if( p_filter
->input
.i_format
!= VLC_FOURCC('f','l','3','2' ) ||
105 p_filter
->output
.i_format
!= VLC_FOURCC('f','l','3','2') )
108 p_filter
->input
.i_format
= VLC_FOURCC('f','l','3','2');
109 p_filter
->output
.i_format
= VLC_FOURCC('f','l','3','2');
110 msg_Warn( p_filter
, "bad input or output format" );
113 if ( !AOUT_FMTS_SIMILAR( &p_filter
->input
, &p_filter
->output
) )
116 memcpy( &p_filter
->output
, &p_filter
->input
,
117 sizeof(audio_sample_format_t
) );
118 msg_Warn( p_filter
, "input and output formats are not similar" );
126 p_filter
->pf_do_work
= DoWork
;
127 p_filter
->b_in_place
= VLC_TRUE
;
129 i_channels
= aout_FormatNbChannels( &p_filter
->input
);
131 p_sys
= p_filter
->p_sys
= malloc( sizeof( aout_filter_sys_t
) );
132 p_sys
->i_nb
= var_CreateGetInteger( p_filter
->p_parent
, "norm-buff-size" );
133 p_sys
->f_max
= var_CreateGetFloat( p_filter
->p_parent
, "norm-max-level" );
135 if( p_sys
->f_max
<= 0 ) p_sys
->f_max
= 0.01;
137 /* We need to store (nb_buffers+1)*nb_channels floats */
138 p_sys
->p_last
= malloc( sizeof( float ) * (i_channels
) *
139 (p_filter
->p_sys
->i_nb
+ 2) );
140 memset( p_sys
->p_last
, 0 ,sizeof( float ) * (i_channels
) *
141 (p_filter
->p_sys
->i_nb
+ 2) );
145 /*****************************************************************************
146 * DoWork : normalizes and sends a buffer
147 *****************************************************************************/
148 static void DoWork( aout_instance_t
*p_aout
, aout_filter_t
*p_filter
,
149 aout_buffer_t
*p_in_buf
, aout_buffer_t
*p_out_buf
)
156 int i_samples
= p_in_buf
->i_nb_samples
;
157 int i_channels
= aout_FormatNbChannels( &p_filter
->input
);
158 float *p_out
= (float*)p_out_buf
->p_buffer
;
159 float *p_in
= (float*)p_in_buf
->p_buffer
;
161 struct aout_filter_sys_t
*p_sys
= p_filter
->p_sys
;
163 pf_sum
= (float *)malloc( sizeof(float) * i_channels
);
164 memset( pf_sum
, 0, sizeof(float) * i_channels
);
166 pf_gain
= (float *)malloc( sizeof(float) * i_channels
);
168 p_out_buf
->i_nb_samples
= p_in_buf
->i_nb_samples
;
169 p_out_buf
->i_nb_bytes
= p_in_buf
->i_nb_bytes
;
171 /* Calculate the average power level on this buffer */
172 for( i
= 0 ; i
< i_samples
; i
++ )
174 for( i_chan
= 0; i_chan
< i_channels
; i_chan
++ )
176 float f_sample
= p_in
[i_chan
];
177 float f_square
= pow( f_sample
, 2 );
178 pf_sum
[i_chan
] += f_square
;
183 /* sum now contains for each channel the sigma(value²) */
184 for( i_chan
= 0; i_chan
< i_channels
; i_chan
++ )
186 /* Shift our lastbuff */
187 memmove( &p_sys
->p_last
[ i_chan
* p_sys
->i_nb
],
188 &p_sys
->p_last
[i_chan
* p_sys
->i_nb
+ 1],
189 (p_sys
->i_nb
-1) * sizeof( float ) );
191 /* Insert the new average : sqrt(sigma(value²)) */
192 p_sys
->p_last
[ i_chan
* p_sys
->i_nb
+ p_sys
->i_nb
- 1] =
193 sqrt( pf_sum
[i_chan
] );
197 /* Get the average power on the lastbuff */
199 for( i
= 0; i
< p_sys
->i_nb
; i
++)
201 f_average
+= p_sys
->p_last
[ i_chan
* p_sys
->i_nb
+ i
];
203 f_average
= f_average
/ p_sys
->i_nb
;
205 /* Seuil arbitraire */
206 p_sys
->f_max
= var_GetFloat( p_aout
, "norm-max-level" );
208 //fprintf(stderr,"Average %f, max %f\n", f_average, p_sys->f_max );
209 if( f_average
> p_sys
->f_max
)
211 pf_gain
[i_chan
] = f_average
/ p_sys
->f_max
;
220 for( i
= 0; i
< i_samples
; i
++)
222 for( i_chan
= 0; i_chan
< i_channels
; i_chan
++ )
224 p_out
[i_chan
] /= pf_gain
[i_chan
];
235 /**********************************************************************
237 **********************************************************************/
238 static void Close( vlc_object_t
*p_this
)
240 aout_filter_t
*p_filter
= (aout_filter_t
*)p_this
;
241 aout_filter_sys_t
*p_sys
= p_filter
->p_sys
;
245 if( p_sys
->p_last
) free( p_sys
->p_last
);