Mercurial > mplayer.hg
comparison libaf/af_volnorm.c @ 13550:81e62cbe57d9
reimplementation of the pl_extrastereo and pl_volnorm plugins
author | alex |
---|---|
date | Mon, 04 Oct 2004 19:11:05 +0000 |
parents | |
children | 14090f7300a8 |
comparison
equal
deleted
inserted
replaced
13549:4604fc855b3a | 13550:81e62cbe57d9 |
---|---|
1 /*============================================================================= | |
2 // | |
3 // This software has been released under the terms of the GNU Public | |
4 // license. See http://www.gnu.org/copyleft/gpl.html for details. | |
5 // | |
6 // Copyright 2004 Alex Beregszaszi & Pierre Lombard | |
7 // | |
8 //============================================================================= | |
9 */ | |
10 | |
11 #include <stdio.h> | |
12 #include <stdlib.h> | |
13 #include <string.h> | |
14 | |
15 #include <unistd.h> | |
16 #include <inttypes.h> | |
17 #include <math.h> | |
18 #include <limits.h> | |
19 | |
20 #include "af.h" | |
21 | |
22 // Methods: | |
23 // 1: uses a 1 value memory and coefficients new=a*old+b*cur (with a+b=1) | |
24 // 2: uses several samples to smooth the variations (standard weighted mean | |
25 // on past samples) | |
26 | |
27 // Size of the memory array | |
28 // FIXME: should depend on the frequency of the data (should be a few seconds) | |
29 #define NSAMPLES 128 | |
30 | |
31 // If summing all the mem[].len is lower than MIN_SAMPLE_SIZE bytes, then we | |
32 // choose to ignore the computed value as it's not significant enough | |
33 // FIXME: should depend on the frequency of the data (0.5s maybe) | |
34 #define MIN_SAMPLE_SIZE 32000 | |
35 | |
36 // mul is the value by which the samples are scaled | |
37 // and has to be in [MUL_MIN, MUL_MAX] | |
38 #define MUL_INIT 1.0 | |
39 #define MUL_MIN 0.1 | |
40 #define MUL_MAX 5.0 | |
41 // "Ideal" level | |
42 #define MID_S16 (SHRT_MAX * 0.25) | |
43 #define MID_FLOAT (INT_MAX * 0.25) | |
44 | |
45 // Silence level | |
46 // FIXME: should be relative to the level of the samples | |
47 #define SIL_S16 (SHRT_MAX * 0.01) | |
48 #define SIL_FLOAT (INT_MAX * 0.01) // FIXME | |
49 | |
50 // smooth must be in ]0.0, 1.0[ | |
51 #define SMOOTH_MUL 0.06 | |
52 #define SMOOTH_LASTAVG 0.06 | |
53 | |
54 // Data for specific instances of this filter | |
55 typedef struct af_volume_s | |
56 { | |
57 int method; // method used | |
58 float mul; | |
59 // method 1 | |
60 float lastavg; // history value of the filter | |
61 // method 2 | |
62 int idx; | |
63 struct { | |
64 float avg; // average level of the sample | |
65 int len; // sample size (weight) | |
66 } mem[NSAMPLES]; | |
67 }af_volnorm_t; | |
68 | |
69 // Initialization and runtime control | |
70 static int control(struct af_instance_s* af, int cmd, void* arg) | |
71 { | |
72 af_volnorm_t* s = (af_volnorm_t*)af->setup; | |
73 | |
74 switch(cmd){ | |
75 case AF_CONTROL_REINIT: | |
76 // Sanity check | |
77 if(!arg) return AF_ERROR; | |
78 | |
79 af->data->rate = ((af_data_t*)arg)->rate; | |
80 af->data->nch = ((af_data_t*)arg)->nch; | |
81 | |
82 if(((af_data_t*)arg)->format != (AF_FORMAT_F | AF_FORMAT_NE) && | |
83 ((af_data_t*)arg)->format != (AF_FORMAT_SI | AF_FORMAT_NE)) | |
84 return AF_ERROR; | |
85 | |
86 if(((af_data_t*)arg)->format == (AF_FORMAT_SI | AF_FORMAT_NE)){ | |
87 af->data->format = AF_FORMAT_SI | AF_FORMAT_NE; | |
88 af->data->bps = 2; | |
89 }else{ | |
90 af->data->format = AF_FORMAT_F | AF_FORMAT_NE; | |
91 af->data->bps = 4; | |
92 } | |
93 return af_test_output(af,(af_data_t*)arg); | |
94 case AF_CONTROL_COMMAND_LINE:{ | |
95 int i; | |
96 sscanf((char*)arg,"%d", &i); | |
97 if (i != 1 && i != 2) | |
98 return AF_ERROR; | |
99 s->method = i-1; | |
100 return AF_OK; | |
101 } | |
102 } | |
103 return AF_UNKNOWN; | |
104 } | |
105 | |
106 // Deallocate memory | |
107 static void uninit(struct af_instance_s* af) | |
108 { | |
109 if(af->data) | |
110 free(af->data); | |
111 if(af->setup) | |
112 free(af->setup); | |
113 } | |
114 | |
115 static void method1_int16(af_volnorm_t *s, af_data_t *c) | |
116 { | |
117 register int i = 0; | |
118 int16_t *data = (int16_t*)c->audio; // Audio data | |
119 int len = c->len/2; // Number of samples | |
120 float curavg = 0.0, newavg, neededmul; | |
121 int tmp; | |
122 | |
123 for (i = 0; i < len; i++) | |
124 { | |
125 tmp = data[i]; | |
126 curavg += tmp * tmp; | |
127 } | |
128 curavg = sqrt(curavg / (float) len); | |
129 | |
130 // Evaluate an adequate 'mul' coefficient based on previous state, current | |
131 // samples level, etc | |
132 | |
133 if (curavg > SIL_S16) | |
134 { | |
135 neededmul = MID_S16 / (curavg * s->mul); | |
136 s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul; | |
137 | |
138 // clamp the mul coefficient | |
139 s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); | |
140 } | |
141 | |
142 // Scale & clamp the samples | |
143 for (i = 0; i < len; i++) | |
144 { | |
145 tmp = s->mul * data[i]; | |
146 tmp = clamp(tmp, SHRT_MIN, SHRT_MAX); | |
147 data[i] = tmp; | |
148 } | |
149 | |
150 // Evaulation of newavg (not 100% accurate because of values clamping) | |
151 newavg = s->mul * curavg; | |
152 | |
153 // Stores computed values for future smoothing | |
154 s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg; | |
155 } | |
156 | |
157 static void method1_float(af_volnorm_t *s, af_data_t *c) | |
158 { | |
159 register int i = 0; | |
160 float *data = (float*)c->audio; // Audio data | |
161 int len = c->len/4; // Number of samples | |
162 float curavg = 0.0, newavg, neededmul, tmp; | |
163 | |
164 for (i = 0; i < len; i++) | |
165 { | |
166 tmp = data[i]; | |
167 curavg += tmp * tmp; | |
168 } | |
169 curavg = sqrt(curavg / (float) len); | |
170 | |
171 // Evaluate an adequate 'mul' coefficient based on previous state, current | |
172 // samples level, etc | |
173 | |
174 if (curavg > SIL_FLOAT) // FIXME | |
175 { | |
176 neededmul = MID_FLOAT / (curavg * s->mul); | |
177 s->mul = (1.0 - SMOOTH_MUL) * s->mul + SMOOTH_MUL * neededmul; | |
178 | |
179 // clamp the mul coefficient | |
180 s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); | |
181 } | |
182 | |
183 // Scale & clamp the samples | |
184 for (i = 0; i < len; i++) | |
185 data[i] *= s->mul; | |
186 | |
187 // Evaulation of newavg (not 100% accurate because of values clamping) | |
188 newavg = s->mul * curavg; | |
189 | |
190 // Stores computed values for future smoothing | |
191 s->lastavg = (1.0 - SMOOTH_LASTAVG) * s->lastavg + SMOOTH_LASTAVG * newavg; | |
192 } | |
193 | |
194 static void method2_int16(af_volnorm_t *s, af_data_t *c) | |
195 { | |
196 register int i = 0; | |
197 int16_t *data = (int16_t*)c->audio; // Audio data | |
198 int len = c->len/2; // Number of samples | |
199 float curavg = 0.0, newavg, avg = 0.0; | |
200 int tmp, totallen = 0; | |
201 | |
202 for (i = 0; i < len; i++) | |
203 { | |
204 tmp = data[i]; | |
205 curavg += tmp * tmp; | |
206 } | |
207 curavg = sqrt(curavg / (float) len); | |
208 | |
209 // Evaluate an adequate 'mul' coefficient based on previous state, current | |
210 // samples level, etc | |
211 for (i = 0; i < NSAMPLES; i++) | |
212 { | |
213 avg += s->mem[i].avg * (float)s->mem[i].len; | |
214 totallen += s->mem[i].len; | |
215 } | |
216 | |
217 if (totallen > MIN_SAMPLE_SIZE) | |
218 { | |
219 avg /= (float)totallen; | |
220 if (avg >= SIL_S16) | |
221 { | |
222 s->mul = MID_S16 / avg; | |
223 s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); | |
224 } | |
225 } | |
226 | |
227 // Scale & clamp the samples | |
228 for (i = 0; i < len; i++) | |
229 { | |
230 tmp = s->mul * data[i]; | |
231 tmp = clamp(tmp, SHRT_MIN, SHRT_MAX); | |
232 data[i] = tmp; | |
233 } | |
234 | |
235 // Evaulation of newavg (not 100% accurate because of values clamping) | |
236 newavg = s->mul * curavg; | |
237 | |
238 // Stores computed values for future smoothing | |
239 s->mem[s->idx].len = len; | |
240 s->mem[s->idx].avg = newavg; | |
241 s->idx = (s->idx + 1) % NSAMPLES; | |
242 } | |
243 | |
244 static void method2_float(af_volnorm_t *s, af_data_t *c) | |
245 { | |
246 register int i = 0; | |
247 float *data = (float*)c->audio; // Audio data | |
248 int len = c->len/4; // Number of samples | |
249 float curavg = 0.0, newavg, avg = 0.0, tmp; | |
250 int totallen = 0; | |
251 | |
252 for (i = 0; i < len; i++) | |
253 { | |
254 tmp = data[i]; | |
255 curavg += tmp * tmp; | |
256 } | |
257 curavg = sqrt(curavg / (float) len); | |
258 | |
259 // Evaluate an adequate 'mul' coefficient based on previous state, current | |
260 // samples level, etc | |
261 for (i = 0; i < NSAMPLES; i++) | |
262 { | |
263 avg += s->mem[i].avg * (float)s->mem[i].len; | |
264 totallen += s->mem[i].len; | |
265 } | |
266 | |
267 if (totallen > MIN_SAMPLE_SIZE) | |
268 { | |
269 avg /= (float)totallen; | |
270 if (avg >= SIL_FLOAT) | |
271 { | |
272 s->mul = MID_FLOAT / avg; | |
273 s->mul = clamp(s->mul, MUL_MIN, MUL_MAX); | |
274 } | |
275 } | |
276 | |
277 // Scale & clamp the samples | |
278 for (i = 0; i < len; i++) | |
279 data[i] *= s->mul; | |
280 | |
281 // Evaulation of newavg (not 100% accurate because of values clamping) | |
282 newavg = s->mul * curavg; | |
283 | |
284 // Stores computed values for future smoothing | |
285 s->mem[s->idx].len = len; | |
286 s->mem[s->idx].avg = newavg; | |
287 s->idx = (s->idx + 1) % NSAMPLES; | |
288 } | |
289 | |
290 // Filter data through filter | |
291 static af_data_t* play(struct af_instance_s* af, af_data_t* data) | |
292 { | |
293 af_volnorm_t *s = af->setup; | |
294 | |
295 if(af->data->format == (AF_FORMAT_SI | AF_FORMAT_NE)) | |
296 { | |
297 if (s->method) | |
298 method2_int16(s, data); | |
299 else | |
300 method1_int16(s, data); | |
301 } | |
302 else if(af->data->format == (AF_FORMAT_F | AF_FORMAT_NE)) | |
303 { | |
304 if (s->method) | |
305 method2_float(s, data); | |
306 else | |
307 method1_float(s, data); | |
308 } | |
309 return data; | |
310 } | |
311 | |
312 // Allocate memory and set function pointers | |
313 static int open(af_instance_t* af){ | |
314 int i = 0; | |
315 af->control=control; | |
316 af->uninit=uninit; | |
317 af->play=play; | |
318 af->mul.n=1; | |
319 af->mul.d=1; | |
320 af->data=calloc(1,sizeof(af_data_t)); | |
321 af->setup=calloc(1,sizeof(af_volnorm_t)); | |
322 if(af->data == NULL || af->setup == NULL) | |
323 return AF_ERROR; | |
324 | |
325 ((af_volnorm_t*)af->setup)->mul = MUL_INIT; | |
326 ((af_volnorm_t*)af->setup)->lastavg = MID_S16; | |
327 ((af_volnorm_t*)af->setup)->idx = 0; | |
328 for (i = 0; i < NSAMPLES; i++) | |
329 { | |
330 ((af_volnorm_t*)af->setup)->mem[i].len = 0; | |
331 ((af_volnorm_t*)af->setup)->mem[i].avg = 0; | |
332 } | |
333 return AF_OK; | |
334 } | |
335 | |
336 // Description of this filter | |
337 af_info_t af_info_volnorm = { | |
338 "Volume normalizer filter", | |
339 "volnorm", | |
340 "Alex Beregszaszi & Pierre Lombard", | |
341 "", | |
342 AF_FLAGS_NOT_REENTRANT, | |
343 open | |
344 }; |