1 /***************************************************************************
2 \file audiofilter_normalize
3 \brief absolute or automatic gain filter
4 -------------------
5
6 copyright : (C) 2002/2009 by mean
7 email : fixounet@free.fr
8
9 Compute the ratio so that the maximum is at -3db
10
11 ***************************************************************************/
12
13 /***************************************************************************
14 * *
15 * This program is free software; you can redistribute it and/or modify *
16 * it under the terms of the GNU General Public License as published by *
17 * the Free Software Foundation; either version 2 of the License, or *
18 * (at your option) any later version. *
19 * *
20 ***************************************************************************/
21
22
23
24 #include "ADM_default.h"
25 #include <math.h>
26 #include "ADM_audioFilter.h"
27 #include "audiofilter_normalize_param.h"
28 #include "audiofilter_normalize.h"
29 #include "audiofilter_dolby.h"
30
31 #include "ADM_coreAudio.h"
32
33 #if defined (_WIN32) || defined (__HAIKU__)
34 #define POW10(x) pow(10,x)
35 #elif defined(ADM_BSD_FAMILY) || defined(__sun__)
36 #define POW10(x) powf(10.0,x)
37 #else
38 #define POW10(x) exp10f(x)
39 #endif
40
41 #define LINEAR_TO_DB(x) (20.*log10(x))
42 #define DB_TO_LINEAR(x) (POW10((x/20.)))
43
44 static int32_t max_level_x10;
45
46 /**
47 \fn Ctor
48 **/
49
AUDMAudioFilterNormalize(AUDMAudioFilter * instream,GAINparam * param)50 AUDMAudioFilterNormalize::AUDMAudioFilterNormalize(AUDMAudioFilter * instream,GAINparam *param):AUDMAudioFilter (instream)
51 {
52 float db_out;
53 // nothing special here...
54 switch(param->mode)
55 {
56 case ADM_NO_GAIN: _ratio=1;_scanned=1;ADM_info("[Gain] Gain of 1.0\n");break;
57 case ADM_GAIN_AUTOMATIC:
58 _ratio=1;
59 _scanned=0;
60 max_level_x10 = param->maxlevel10;
61 ADM_info("[Gain] Automatic gain, max level %.1f\n",max_level_x10/10.0);
62 break;
63 case ADM_GAIN_MANUAL:
64 _scanned=1;
65 db_out = param->gain10/10.0; // Dbout is in 10*DB (!)
66 _ratio = DB_TO_LINEAR(db_out);
67 ADM_info("[Gain] %f db (p=%d)\n", (float)(param->gain10)/10.,param->gain10);
68 ADM_info("[Gain] Linear ratio of : %03.3f\n", _ratio);
69 break;
70 default:
71 ADM_error("Unknown normalize mode\n");
72 ADM_assert(0);
73 break;
74 }
75 _previous->rewind();
76 };
77 /**
78 \fn dtor
79 */
~AUDMAudioFilterNormalize()80 AUDMAudioFilterNormalize::~AUDMAudioFilterNormalize()
81 {
82 ADM_info("Destroying normalize audio filter\n");
83 }
84 /**
85 \fn preprocess
86 \brief Search for max value to compute gain
87 */
preprocess(void)88 uint8_t AUDMAudioFilterNormalize::preprocess(void)
89 {
90
91
92 uint32_t scanned = 0;
93 AUD_Status status;
94 _ratio = 0;
95
96 float *max=new float[_wavHeader.channels];
97 _previous->rewind();
98 ADMDolbyContext::DolbySkip(1);
99 ADM_info("Seeking for maximum value, that can take a while\n");
100
101 for(int i=0;i<_wavHeader.channels;i++) max[i]=0;
102 while (1)
103 {
104 int ready=_previous->fill(AUD_PROCESS_BUFFER_SIZE>>2,_incomingBuffer.at(0),&status);
105 if(!ready)
106 {
107 if(status==AUD_END_OF_STREAM)
108 {
109 break;
110 }
111 else
112 {
113 ADM_error("Unknown cause : %d\n",status);
114 ADM_assert(0);
115 }
116 }
117 ADM_assert(!(ready %_wavHeader.channels));
118
119 int index=0;
120 float current;
121
122 // printf("*\n");
123 int sample= ready /_wavHeader.channels;
124 for(int j=0;j<sample;j++)
125 for(int chan=0;chan<_wavHeader.channels;chan++)
126 {
127 current=fabs(_incomingBuffer[index++]);
128 if(current>max[chan]) max[chan]=current;
129 }
130 scanned+=ready;
131 }
132
133
134
135
136 _previous->rewind();
137 float mx=0;
138 for(int chan=0;chan<_wavHeader.channels;chan++)
139 {
140 if(max[chan]>mx) mx=max[chan];
141 ADM_info("[Normalize] maximum found for channel %d : %f\n", chan,max[chan]);
142 }
143 ADM_info("[Normalize] Using : %0.4f as max value \n", mx);
144 double db_in, db_out=max_level_x10/10.0;
145
146 if (mx>0.001)
147 db_in = LINEAR_TO_DB(mx);
148 else
149 db_in = -20; // We consider -20 DB to be noise
150
151 printf("--> %2.2f db / %2.2f \n", db_in, db_out);
152
153 // search ratio
154 _ratio=1;
155
156 float db_delta=db_out-db_in;
157 ADM_info("[Normalize]Gain %f dB\n",db_delta);
158 _ratio = DB_TO_LINEAR(db_delta);
159 ADM_info("\n Using ratio of : %f\n", _ratio);
160
161 _scanned = 1;
162 ADMDolbyContext::DolbySkip(0);
163 _previous->rewind();
164 delete [] max;
165 return 1;
166 }
167 /**
168 \fn fill
169 \brief
170 */
fill(uint32_t max,float * buffer,AUD_Status * status)171 uint32_t AUDMAudioFilterNormalize::fill( uint32_t max, float * buffer,AUD_Status *status)
172 {
173 uint32_t rd, i;
174
175 *status=AUD_OK;
176 if(!_scanned) preprocess();
177 rd = _previous->fill(max, _incomingBuffer.at(0),status);
178 if(!rd)
179 {
180 if(*status==AUD_END_OF_STREAM) return 0;
181 ADM_assert(0);
182 }
183 float tmp;
184 for (i = 0; i < rd; i++)
185 {
186 tmp=_incomingBuffer[i];
187 tmp*=_ratio;
188 buffer[i]=tmp;
189 }
190 return rd;
191 };
192 //EOF
193
194