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 *
|
|
10 * Sources: some ideas from volnorm for xmms
|
|
11 *
|
|
12 * */
|
|
13
|
|
14 #define PLUGIN
|
|
15
|
|
16 #include <stdio.h>
|
|
17 #include <stdlib.h>
|
|
18 #include <inttypes.h>
|
|
19 #include <math.h> // for sqrt()
|
|
20
|
|
21 #include "audio_out.h"
|
|
22 #include "audio_plugin.h"
|
|
23 #include "audio_plugin_internal.h"
|
|
24 #include "afmt.h"
|
|
25
|
4942
|
26 #ifdef __FreeBSD__
|
|
27 #include "machine/limits.h"
|
|
28 #define INT16_MAX INT_MAX
|
|
29 #define INT16_MIN INT_MIN
|
|
30 #endif
|
|
31
|
4941
|
32 static ao_info_t info = {
|
|
33 "Volume normalizer",
|
|
34 "volnorm",
|
|
35 "pl <p_l@gmx.fr>",
|
|
36 ""
|
|
37 };
|
|
38
|
|
39 LIBAO_PLUGIN_EXTERN(volnorm)
|
|
40
|
|
41 // mul is the value by which the samples are scaled
|
|
42 // and has to be in [MUL_MIN, MUL_MAX]
|
|
43 #define MUL_INIT 1.0
|
|
44 #define MUL_MIN 0.1
|
|
45 #define MUL_MAX 15.0
|
|
46 static float mul;
|
|
47
|
|
48 // "history" value of the filter
|
|
49 static float lastavg;
|
|
50
|
|
51 // SMOOTH_* must be in ]0.0, 1.0[
|
|
52 // The new value accounts for SMOOTH_MUL in the value and history
|
|
53 #define SMOOTH_MUL 0.06
|
|
54 #define SMOOTH_LASTAVG 0.06
|
|
55
|
|
56 // ideal average level
|
|
57 #define MID_S16 (INT16_MAX * 0.25)
|
|
58
|
|
59 // silence level
|
|
60 #define SIL_S16 (INT16_MAX * 0.02)
|
|
61
|
|
62 // local data
|
|
63 static struct {
|
|
64 int inuse; // This plugin is in use TRUE, FALSE
|
|
65 int format; // sample fomat
|
|
66 } pl_volnorm = {0, 0};
|
|
67
|
|
68
|
|
69 // minimal interface
|
|
70 static int control(int cmd,int arg){
|
|
71 switch(cmd){
|
|
72 case AOCONTROL_PLUGIN_SET_LEN:
|
|
73 return CONTROL_OK;
|
|
74 }
|
|
75 return CONTROL_UNKNOWN;
|
|
76 }
|
|
77
|
|
78 // minimal interface
|
|
79 // open & setup audio device
|
|
80 // return: 1=success 0=fail
|
|
81 static int init(){
|
|
82 switch(ao_plugin_data.format){
|
|
83 case(AFMT_S16_LE):
|
|
84 break;
|
|
85 default:
|
|
86 fprintf(stderr,"[pl_volnorm] Audio format not yet supported.\n");
|
|
87 return 0;
|
|
88 }
|
|
89
|
|
90 pl_volnorm.format = ao_plugin_data.format;
|
|
91 pl_volnorm.inuse = 1;
|
|
92
|
|
93 reset();
|
|
94
|
|
95 printf("[pl_volnorm] Normalizer plugin in use.\n");
|
|
96 return 1;
|
|
97 }
|
|
98
|
|
99 // close plugin
|
|
100 static void uninit(){
|
|
101 pl_volnorm.inuse=0;
|
|
102 }
|
|
103
|
|
104 // empty buffers
|
|
105 static void reset(){
|
|
106 mul = MUL_INIT;
|
|
107 switch(ao_plugin_data.format) {
|
|
108 case(AFMT_S16_LE):
|
|
109 lastavg = MID_S16;
|
|
110 break;
|
|
111 default:
|
|
112 fprintf(stderr,"[pl_volnorm] internal inconsistency - please bugreport.\n");
|
|
113 *(char *) 0 = 0;
|
|
114 }
|
|
115 }
|
|
116
|
|
117 // processes 'ao_plugin_data.len' bytes of 'data'
|
|
118 // called for every block of data
|
|
119 static int play(){
|
|
120
|
|
121 switch(pl_volnorm.format){
|
|
122 case(AFMT_S16_LE): {
|
|
123
|
|
124 #define CLAMP(x,m,M) do { if ((x)<(m)) (x) = (m); else if ((x)>(M)) (x) = (M); } while(0)
|
|
125
|
|
126 int16_t* data=(int16_t*)ao_plugin_data.data;
|
|
127 int len=ao_plugin_data.len / 2; // 16 bits samples
|
|
128
|
|
129 int32_t i;
|
|
130 register int32_t tmp;
|
|
131 register float curavg;
|
|
132 float newavg;
|
|
133 float neededmul;
|
|
134
|
|
135 // average of the current samples
|
|
136 curavg = 0.0;
|
|
137 for (i = 0; i < len ; ++i) {
|
|
138 tmp = data[i];
|
|
139 curavg += tmp * tmp;
|
|
140 }
|
|
141 curavg = sqrt(curavg / (float) len);
|
|
142
|
|
143 if (curavg > SIL_S16) {
|
|
144 neededmul = MID_S16 / ( curavg * mul);
|
|
145 mul = (1.0 - SMOOTH_MUL) * mul + SMOOTH_MUL * neededmul;
|
|
146
|
|
147 // Clamp the mul coefficient
|
|
148 CLAMP(mul, MUL_MIN, MUL_MAX);
|
|
149 }
|
|
150
|
|
151 // Scale & clamp the samples
|
|
152 for (i=0; i < len ; ++i) {
|
|
153 tmp = data[i] * mul;
|
|
154 CLAMP(tmp, INT16_MIN, INT16_MAX);
|
|
155 data[i] = tmp;
|
|
156 }
|
|
157
|
|
158 // Evaluation of newavg (not 100% accurate because of values clamping)
|
|
159 newavg = mul * curavg;
|
|
160
|
|
161 #if 0
|
|
162 printf("time = %d len = %d curavg = %6.0f lastavg = %6.0f newavg = %6.0f\n"
|
|
163 " needed_m = %2.2f m = %2.2f\n\n",
|
|
164 time(NULL), len, curavg, lastavg, newavg, neededmul, mul);
|
|
165 #endif
|
|
166
|
|
167 lastavg = (1.0 - SMOOTH_LASTAVG) * lastavg + SMOOTH_LASTAVG * newavg;
|
|
168
|
|
169 break;
|
|
170 }
|
|
171 default:
|
|
172 return 0;
|
|
173 }
|
|
174 return 1;
|
|
175
|
|
176 }
|
|
177
|