Mercurial > mplayer.hg
annotate libao2/pl_volnorm.c @ 8779:43b2ecb7543c
Fix spelling of my name
author | jkeil |
---|---|
date | Sat, 04 Jan 2003 19:23:29 +0000 |
parents | 46d21c0f36aa |
children | 12b1790038b0 |
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){ | |
8741
46d21c0f36aa
(nicer) endianness fix for every plugin except pl_format
colin
parents:
8218
diff
changeset
|
119 case(AFMT_S16_NE): |
4941 | 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) { | |
8741
46d21c0f36aa
(nicer) endianness fix for every plugin except pl_format
colin
parents:
8218
diff
changeset
|
145 case(AFMT_S16_NE): |
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){ | |
8741
46d21c0f36aa
(nicer) endianness fix for every plugin except pl_format
colin
parents:
8218
diff
changeset
|
168 case(AFMT_S16_NE): { |
4941 | 169 #define CLAMP(x,m,M) do { if ((x)<(m)) (x) = (m); else if ((x)>(M)) (x) = (M); } while(0) |
170 | |
171 int16_t* data=(int16_t*)ao_plugin_data.data; | |
172 int len=ao_plugin_data.len / 2; // 16 bits samples | |
173 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
174 int32_t i, tmp; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
175 float curavg, newavg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
176 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
177 #if AVG==1 |
4941 | 178 float neededmul; |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
179 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
180 float avg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
181 int32_t totallen; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
182 #endif |
4941 | 183 |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
184 // Evaluate current samples average level |
4941 | 185 curavg = 0.0; |
186 for (i = 0; i < len ; ++i) { | |
187 tmp = data[i]; | |
188 curavg += tmp * tmp; | |
189 } | |
190 curavg = sqrt(curavg / (float) len); | |
191 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
192 // 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
|
193 // samples level, etc |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
194 #if AVG==1 |
4941 | 195 if (curavg > SIL_S16) { |
196 neededmul = MID_S16 / ( curavg * mul); | |
197 mul = (1.0 - SMOOTH_MUL) * mul + SMOOTH_MUL * neededmul; | |
198 | |
199 // Clamp the mul coefficient | |
200 CLAMP(mul, MUL_MIN, MUL_MAX); | |
201 } | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
202 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
203 avg = 0.0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
204 totallen = 0; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
205 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
206 for (i = 0; i < NSAMPLES; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
207 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
|
208 totallen += mem[i].len; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
209 } |
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 if (totallen > MIN_SAMPLE_SIZE) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
212 avg /= (float) totallen; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
213 if (avg >= SIL_S16) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
214 mul = (float) MID_S16 / avg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
215 CLAMP(mul, MUL_MIN, MUL_MAX); |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
216 } |
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 #endif |
4941 | 219 |
220 // Scale & clamp the samples | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
221 for (i = 0; i < len ; ++i) { |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
222 tmp = mul * data[i]; |
4943
511e8d8117e9
proper bsd fix & preventive fix for other archs w/o INT_MAX
pl
parents:
4942
diff
changeset
|
223 CLAMP(tmp, MIN_S16, MAX_S16); |
4941 | 224 data[i] = tmp; |
225 } | |
226 | |
227 // Evaluation of newavg (not 100% accurate because of values clamping) | |
228 newavg = mul * curavg; | |
229 | |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
230 // Stores computed values for future smoothing |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
231 #if AVG==1 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
232 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
|
233 //printf("\rmul=%02.1f ", mul); |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
234 #elif AVG==2 |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
235 mem[idx].len = len; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
236 mem[idx].avg = newavg; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
237 idx = (idx + 1) % NSAMPLES; |
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
238 //printf("\rmul=%02.1f (%04dKiB) ", mul, totallen/1024); |
4941 | 239 #endif |
5025
6d8971d55e40
new smoothing method ('#define AVG 2' to enable'n'test it)
pl
parents:
4943
diff
changeset
|
240 //fflush(stdout); |
4941 | 241 |
242 break; | |
243 } | |
244 default: | |
245 return 0; | |
246 } | |
247 return 1; | |
248 | |
249 } | |
250 |