Mercurial > mplayer.hg
annotate libao2/pl_volnorm.c @ 6540:5b3cace64e9d
100l (non mmx versions didnt compile)
some cleanup
author | michael |
---|---|
date | Mon, 24 Jun 2002 00:18:29 +0000 |
parents | 6d8971d55e40 |
children | 48deec5d2050 |
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" | |
34 | |
35 static ao_info_t info = { | |
36 "Volume normalizer", | |
37 "volnorm", | |
38 "pl <p_l@gmx.fr>", | |
39 "" | |
40 }; | |
41 | |
42 LIBAO_PLUGIN_EXTERN(volnorm) | |
43 | |
44 // mul is the value by which the samples are scaled | |
45 // and has to be in [MUL_MIN, MUL_MAX] | |
46 #define MUL_INIT 1.0 | |
47 #define MUL_MIN 0.1 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
48 #define MUL_MAX 5.0 |
4941 | 49 static float mul; |
50 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
51 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
52 #if AVG==1 |
4941 | 53 // "history" value of the filter |
54 static float lastavg; | |
55 | |
56 // SMOOTH_* must be in ]0.0, 1.0[ | |
57 // The new value accounts for SMOOTH_MUL in the value and history | |
58 #define SMOOTH_MUL 0.06 | |
59 #define SMOOTH_LASTAVG 0.06 | |
60 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
61 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
62 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
63 // Size of the memory array |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
64 // 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
|
65 #define NSAMPLES 128 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
66 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
67 // 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
|
68 static int idx; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
69 // The array |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
70 static struct { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
71 float avg; // average level of the sample |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
72 int32_t len; // sample size (weight) |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
73 } mem[NSAMPLES]; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
74 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
75 // 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
|
76 // 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
|
77 // 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
|
78 #define MIN_SAMPLE_SIZE 32000 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
79 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
80 #else |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
81 // Kab00m ! |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
82 #error "Unknown AVG" |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
83 #endif |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
84 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
85 |
4943
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
86 // Some limits |
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
87 #define MIN_S16 -32768 |
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
88 #define MAX_S16 32767 |
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
89 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
90 // "Ideal" level |
4943
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
91 #define MID_S16 (MAX_S16 * 0.25) |
4941 | 92 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
93 // Silence level |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
94 // 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
|
95 #define SIL_S16 (MAX_S16 * 0.01) |
4941 | 96 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
97 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
98 // Local data |
4941 | 99 static struct { |
100 int inuse; // This plugin is in use TRUE, FALSE | |
101 int format; // sample fomat | |
102 } pl_volnorm = {0, 0}; | |
103 | |
104 | |
105 // minimal interface | |
106 static int control(int cmd,int arg){ | |
107 switch(cmd){ | |
108 case AOCONTROL_PLUGIN_SET_LEN: | |
109 return CONTROL_OK; | |
110 } | |
111 return CONTROL_UNKNOWN; | |
112 } | |
113 | |
114 // minimal interface | |
115 // open & setup audio device | |
116 // return: 1=success 0=fail | |
117 static int init(){ | |
118 switch(ao_plugin_data.format){ | |
119 case(AFMT_S16_LE): | |
120 break; | |
121 default: | |
122 fprintf(stderr,"[pl_volnorm] Audio format not yet supported.\n"); | |
123 return 0; | |
124 } | |
125 | |
126 pl_volnorm.format = ao_plugin_data.format; | |
127 pl_volnorm.inuse = 1; | |
128 | |
129 reset(); | |
130 | |
131 printf("[pl_volnorm] Normalizer plugin in use.\n"); | |
132 return 1; | |
133 } | |
134 | |
135 // close plugin | |
136 static void uninit(){ | |
137 pl_volnorm.inuse=0; | |
138 } | |
139 | |
140 // empty buffers | |
141 static void reset(){ | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
142 int i; |
4941 | 143 mul = MUL_INIT; |
144 switch(ao_plugin_data.format) { | |
145 case(AFMT_S16_LE): | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
146 #if AVG==1 |
4941 | 147 lastavg = MID_S16; |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
148 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
149 for(i=0; i < NSAMPLES; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
150 mem[i].len = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
151 mem[i].avg = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
152 } |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
153 idx = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
154 #endif |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
155 |
4941 | 156 break; |
157 default: | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
158 fprintf(stderr,"[pl_volnorm] internal inconsistency - bugreport !\n"); |
4941 | 159 *(char *) 0 = 0; |
160 } | |
161 } | |
162 | |
163 // processes 'ao_plugin_data.len' bytes of 'data' | |
164 // called for every block of data | |
165 static int play(){ | |
166 | |
167 switch(pl_volnorm.format){ | |
168 case(AFMT_S16_LE): { | |
169 | |
170 #define CLAMP(x,m,M) do { if ((x)<(m)) (x) = (m); else if ((x)>(M)) (x) = (M); } while(0) | |
171 | |
172 int16_t* data=(int16_t*)ao_plugin_data.data; | |
173 int len=ao_plugin_data.len / 2; // 16 bits samples | |
174 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
175 int32_t i, tmp; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
176 float curavg, newavg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
177 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
178 #if AVG==1 |
4941 | 179 float neededmul; |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
180 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
181 float avg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
182 int32_t totallen; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
183 #endif |
4941 | 184 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
185 // Evaluate current samples average level |
4941 | 186 curavg = 0.0; |
187 for (i = 0; i < len ; ++i) { | |
188 tmp = data[i]; | |
189 curavg += tmp * tmp; | |
190 } | |
191 curavg = sqrt(curavg / (float) len); | |
192 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
193 // 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
|
194 // samples level, etc |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
195 #if AVG==1 |
4941 | 196 if (curavg > SIL_S16) { |
197 neededmul = MID_S16 / ( curavg * mul); | |
198 mul = (1.0 - SMOOTH_MUL) * mul + SMOOTH_MUL * neededmul; | |
199 | |
200 // Clamp the mul coefficient | |
201 CLAMP(mul, MUL_MIN, MUL_MAX); | |
202 } | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
203 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
204 avg = 0.0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
205 totallen = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
206 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
207 for (i = 0; i < NSAMPLES; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
208 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
|
209 totallen += mem[i].len; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
210 } |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
211 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
212 if (totallen > MIN_SAMPLE_SIZE) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
213 avg /= (float) totallen; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
214 if (avg >= SIL_S16) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
215 mul = (float) MID_S16 / avg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
216 CLAMP(mul, MUL_MIN, MUL_MAX); |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
217 } |
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 #endif |
4941 | 220 |
221 // Scale & clamp the samples | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
222 for (i = 0; i < len ; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
223 tmp = mul * data[i]; |
4943
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
224 CLAMP(tmp, MIN_S16, MAX_S16); |
4941 | 225 data[i] = tmp; |
226 } | |
227 | |
228 // Evaluation of newavg (not 100% accurate because of values clamping) | |
229 newavg = mul * curavg; | |
230 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
231 // Stores computed values for future smoothing |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
232 #if AVG==1 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
233 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
|
234 //printf("\rmul=%02.1f ", mul); |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
235 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
236 mem[idx].len = len; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
237 mem[idx].avg = newavg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
238 idx = (idx + 1) % NSAMPLES; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
239 //printf("\rmul=%02.1f (%04dKiB) ", mul, totallen/1024); |
4941 | 240 #endif |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
241 //fflush(stdout); |
4941 | 242 |
243 break; | |
244 } | |
245 default: | |
246 return 0; | |
247 } | |
248 return 1; | |
249 | |
250 } | |
251 |