Mercurial > mplayer.hg
annotate libao2/pl_volnorm.c @ 8448:1564db05e39d
sync
author | nicolas |
---|---|
date | Sat, 14 Dec 2002 13:11:08 +0000 |
parents | 48deec5d2050 |
children | 46d21c0f36aa |
rev | line source |
---|---|
4941 | 1 /* Normalizer plugin |
2 * | |
3 * Limitations: | |
4 * - only AFMT_S16_LE supported | |
5 * - no parameters yet => tweak the values by editing the #defines | |
6 * | |
7 * License: GPLv2 | |
8 * Author: pl <p_l@gmx.fr> (c) 2002 and beyond... | |
9 * | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
10 * Sources: some ideas from volnorm plugin for xmms |
4941 | 11 * |
12 * */ | |
13 | |
14 #define PLUGIN | |
15 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
16 /* Values for AVG: |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
17 * 1: uses a 1 value memory and coefficients new=a*old+b*cur (with a+b=1) |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
18 * |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
19 * 2: uses several samples to smooth the variations (standard weighted mean |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
20 * on past samples) |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
21 * |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
22 * */ |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
23 #define AVG 1 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
24 |
4941 | 25 #include <stdio.h> |
26 #include <stdlib.h> | |
27 #include <inttypes.h> | |
28 #include <math.h> // for sqrt() | |
29 | |
30 #include "audio_out.h" | |
31 #include "audio_plugin.h" | |
32 #include "audio_plugin_internal.h" | |
33 #include "afmt.h" | |
8218 | 34 #include "../config.h" |
4941 | 35 |
36 static ao_info_t info = { | |
37 "Volume normalizer", | |
38 "volnorm", | |
39 "pl <p_l@gmx.fr>", | |
40 "" | |
41 }; | |
42 | |
43 LIBAO_PLUGIN_EXTERN(volnorm) | |
44 | |
45 // mul is the value by which the samples are scaled | |
46 // and has to be in [MUL_MIN, MUL_MAX] | |
47 #define MUL_INIT 1.0 | |
48 #define MUL_MIN 0.1 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
49 #define MUL_MAX 5.0 |
4941 | 50 static float mul; |
51 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
52 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
53 #if AVG==1 |
4941 | 54 // "history" value of the filter |
55 static float lastavg; | |
56 | |
57 // SMOOTH_* must be in ]0.0, 1.0[ | |
58 // The new value accounts for SMOOTH_MUL in the value and history | |
59 #define SMOOTH_MUL 0.06 | |
60 #define SMOOTH_LASTAVG 0.06 | |
61 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
62 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
63 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
64 // Size of the memory array |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
65 // FIXME: should depend on the frequency of the data (should be a few seconds) |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
66 #define NSAMPLES 128 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
67 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
68 // Indicates where to write (in 0..NSAMPLES-1) |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
69 static int idx; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
70 // The array |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
71 static struct { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
72 float avg; // average level of the sample |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
73 int32_t len; // sample size (weight) |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
74 } mem[NSAMPLES]; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
75 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
76 // If summing all the mem[].len is lower than MIN_SAMPLE_SIZE bytes, then we |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
77 // choose to ignore the computed value as it's not significant enough |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
78 // FIXME: should depend on the frequency of the data (0.5s maybe) |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
79 #define MIN_SAMPLE_SIZE 32000 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
80 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
81 #else |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
82 // Kab00m ! |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
83 #error "Unknown AVG" |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
84 #endif |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
85 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
86 |
4943
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
87 // Some limits |
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
88 #define MIN_S16 -32768 |
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
89 #define MAX_S16 32767 |
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
90 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
91 // "Ideal" level |
4943
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
92 #define MID_S16 (MAX_S16 * 0.25) |
4941 | 93 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
94 // Silence level |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
95 // FIXME: should be relative to the level of the samples |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
96 #define SIL_S16 (MAX_S16 * 0.01) |
4941 | 97 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
98 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
99 // Local data |
4941 | 100 static struct { |
101 int inuse; // This plugin is in use TRUE, FALSE | |
102 int format; // sample fomat | |
103 } pl_volnorm = {0, 0}; | |
104 | |
105 | |
106 // minimal interface | |
107 static int control(int cmd,int arg){ | |
108 switch(cmd){ | |
109 case AOCONTROL_PLUGIN_SET_LEN: | |
110 return CONTROL_OK; | |
111 } | |
112 return CONTROL_UNKNOWN; | |
113 } | |
114 | |
115 // minimal interface | |
116 // open & setup audio device | |
117 // return: 1=success 0=fail | |
118 static int init(){ | |
119 switch(ao_plugin_data.format){ | |
8218 | 120 #ifndef WORDS_BIGENDIAN |
4941 | 121 case(AFMT_S16_LE): |
8218 | 122 #else |
123 case(AFMT_S16_BE): | |
124 #endif | |
4941 | 125 break; |
126 default: | |
127 fprintf(stderr,"[pl_volnorm] Audio format not yet supported.\n"); | |
128 return 0; | |
129 } | |
130 | |
131 pl_volnorm.format = ao_plugin_data.format; | |
132 pl_volnorm.inuse = 1; | |
133 | |
134 reset(); | |
135 | |
136 printf("[pl_volnorm] Normalizer plugin in use.\n"); | |
137 return 1; | |
138 } | |
139 | |
140 // close plugin | |
141 static void uninit(){ | |
142 pl_volnorm.inuse=0; | |
143 } | |
144 | |
145 // empty buffers | |
146 static void reset(){ | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
147 int i; |
4941 | 148 mul = MUL_INIT; |
149 switch(ao_plugin_data.format) { | |
8218 | 150 #ifndef WORDS_BIGENDIAN |
4941 | 151 case(AFMT_S16_LE): |
8218 | 152 #else |
153 case(AFMT_S16_BE): | |
154 #endif | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
155 #if AVG==1 |
4941 | 156 lastavg = MID_S16; |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
157 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
158 for(i=0; i < NSAMPLES; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
159 mem[i].len = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
160 mem[i].avg = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
161 } |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
162 idx = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
163 #endif |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
164 |
4941 | 165 break; |
166 default: | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
167 fprintf(stderr,"[pl_volnorm] internal inconsistency - bugreport !\n"); |
4941 | 168 *(char *) 0 = 0; |
169 } | |
170 } | |
171 | |
172 // processes 'ao_plugin_data.len' bytes of 'data' | |
173 // called for every block of data | |
174 static int play(){ | |
175 | |
176 switch(pl_volnorm.format){ | |
8218 | 177 #ifndef WORDS_BIGENDIAN |
4941 | 178 case(AFMT_S16_LE): { |
8218 | 179 #else |
180 case(AFMT_S16_BE): { | |
181 #endif | |
4941 | 182 #define CLAMP(x,m,M) do { if ((x)<(m)) (x) = (m); else if ((x)>(M)) (x) = (M); } while(0) |
183 | |
184 int16_t* data=(int16_t*)ao_plugin_data.data; | |
185 int len=ao_plugin_data.len / 2; // 16 bits samples | |
186 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
187 int32_t i, tmp; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
188 float curavg, newavg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
189 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
190 #if AVG==1 |
4941 | 191 float neededmul; |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
192 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
193 float avg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
194 int32_t totallen; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
195 #endif |
4941 | 196 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
197 // Evaluate current samples average level |
4941 | 198 curavg = 0.0; |
199 for (i = 0; i < len ; ++i) { | |
200 tmp = data[i]; | |
201 curavg += tmp * tmp; | |
202 } | |
203 curavg = sqrt(curavg / (float) len); | |
204 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
205 // Evaluate an adequate 'mul' coefficient based on previous state, current |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
206 // samples level, etc |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
207 #if AVG==1 |
4941 | 208 if (curavg > SIL_S16) { |
209 neededmul = MID_S16 / ( curavg * mul); | |
210 mul = (1.0 - SMOOTH_MUL) * mul + SMOOTH_MUL * neededmul; | |
211 | |
212 // Clamp the mul coefficient | |
213 CLAMP(mul, MUL_MIN, MUL_MAX); | |
214 } | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
215 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
216 avg = 0.0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
217 totallen = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
218 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
219 for (i = 0; i < NSAMPLES; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
220 avg += mem[i].avg * (float) mem[i].len; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
221 totallen += mem[i].len; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
222 } |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
223 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
224 if (totallen > MIN_SAMPLE_SIZE) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
225 avg /= (float) totallen; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
226 if (avg >= SIL_S16) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
227 mul = (float) MID_S16 / avg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
228 CLAMP(mul, MUL_MIN, MUL_MAX); |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
229 } |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
230 } |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
231 #endif |
4941 | 232 |
233 // Scale & clamp the samples | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
234 for (i = 0; i < len ; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
235 tmp = mul * data[i]; |
4943
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
236 CLAMP(tmp, MIN_S16, MAX_S16); |
4941 | 237 data[i] = tmp; |
238 } | |
239 | |
240 // Evaluation of newavg (not 100% accurate because of values clamping) | |
241 newavg = mul * curavg; | |
242 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
243 // Stores computed values for future smoothing |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
244 #if AVG==1 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
245 lastavg = (1.0 - SMOOTH_LASTAVG) * lastavg + SMOOTH_LASTAVG * newavg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
246 //printf("\rmul=%02.1f ", mul); |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
247 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
248 mem[idx].len = len; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
249 mem[idx].avg = newavg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
250 idx = (idx + 1) % NSAMPLES; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
251 //printf("\rmul=%02.1f (%04dKiB) ", mul, totallen/1024); |
4941 | 252 #endif |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
253 //fflush(stdout); |
4941 | 254 |
255 break; | |
256 } | |
257 default: | |
258 return 0; | |
259 } | |
260 return 1; | |
261 | |
262 } | |
263 |