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