1 /*
2  * Copyright 2009, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "AudioEqualizer"
18 
19 #include <assert.h>
20 #include <stdlib.h>
21 #include <new>
22 #include <utils/Log.h>
23 
24 #include "AudioEqualizer.h"
25 #include "AudioPeakingFilter.h"
26 #include "AudioShelvingFilter.h"
27 #include "EffectsMath.h"
28 
29 namespace android {
30 
GetInstanceSize(int nBands)31 size_t AudioEqualizer::GetInstanceSize(int nBands) {
32     assert(nBands >= 2);
33     return sizeof(AudioEqualizer) +
34            sizeof(AudioShelvingFilter) * 2 +
35            sizeof(AudioPeakingFilter) * (nBands - 2);
36 }
37 
CreateInstance(void * pMem,int nBands,int nChannels,int sampleRate,const PresetConfig * presets,int nPresets)38 AudioEqualizer * AudioEqualizer::CreateInstance(void * pMem, int nBands,
39                                                 int nChannels, int sampleRate,
40                                                 const PresetConfig * presets,
41                                                 int nPresets) {
42     ALOGV("AudioEqualizer::CreateInstance(pMem=%p, nBands=%d, nChannels=%d, "
43          "sampleRate=%d, nPresets=%d)",
44          pMem, nBands, nChannels, sampleRate, nPresets);
45     assert(nBands >= 2);
46     bool ownMem = false;
47     if (pMem == NULL) {
48         pMem = malloc(GetInstanceSize(nBands));
49         if (pMem == NULL) {
50             return NULL;
51         }
52         ownMem = true;
53     }
54     return new (pMem) AudioEqualizer(pMem, nBands, nChannels, sampleRate,
55                                      ownMem, presets, nPresets);
56 }
57 
configure(int nChannels,int sampleRate)58 void AudioEqualizer::configure(int nChannels, int sampleRate) {
59     ALOGV("AudioEqualizer::configure(nChannels=%d, sampleRate=%d)", nChannels,
60          sampleRate);
61     mpLowShelf->configure(nChannels, sampleRate);
62     for (int i = 0; i < mNumPeaking; ++i) {
63         mpPeakingFilters[i].configure(nChannels, sampleRate);
64     }
65     mpHighShelf->configure(nChannels, sampleRate);
66 }
67 
clear()68 void AudioEqualizer::clear() {
69     ALOGV("AudioEqualizer::clear()");
70     mpLowShelf->clear();
71     for (int i = 0; i < mNumPeaking; ++i) {
72         mpPeakingFilters[i].clear();
73     }
74     mpHighShelf->clear();
75 }
76 
free()77 void AudioEqualizer::free() {
78     ALOGV("AudioEqualizer::free()");
79     if (mpMem != NULL) {
80         ::free(mpMem);
81     }
82 }
83 
reset()84 void AudioEqualizer::reset() {
85     ALOGV("AudioEqualizer::reset()");
86     const int32_t bottom = Effects_log2(kMinFreq);
87     const int32_t top = Effects_log2(mSampleRate * 500);
88     const int32_t jump = (top - bottom) / (mNumPeaking + 2);
89     int32_t centerFreq = bottom + jump/2;
90 
91     mpLowShelf->reset();
92     mpLowShelf->setFrequency(Effects_exp2(centerFreq));
93     centerFreq += jump;
94     for (int i = 0; i < mNumPeaking; ++i) {
95         mpPeakingFilters[i].reset();
96         mpPeakingFilters[i].setFrequency(Effects_exp2(centerFreq));
97         centerFreq += jump;
98     }
99     mpHighShelf->reset();
100     mpHighShelf->setFrequency(Effects_exp2(centerFreq));
101     commit(true);
102     mCurPreset = PRESET_CUSTOM;
103 }
104 
setGain(int band,int32_t millibel)105 void AudioEqualizer::setGain(int band, int32_t millibel) {
106     ALOGV("AudioEqualizer::setGain(band=%d, millibel=%d)", band, millibel);
107     assert(band >= 0 && band < mNumPeaking + 2);
108     if (band == 0) {
109         mpLowShelf->setGain(millibel);
110     } else if (band == mNumPeaking + 1) {
111         mpHighShelf->setGain(millibel);
112     } else {
113         mpPeakingFilters[band - 1].setGain(millibel);
114     }
115     mCurPreset = PRESET_CUSTOM;
116 }
117 
setFrequency(int band,uint32_t millihertz)118 void AudioEqualizer::setFrequency(int band, uint32_t millihertz) {
119     ALOGV("AudioEqualizer::setFrequency(band=%d, millihertz=%d)", band,
120          millihertz);
121     assert(band >= 0 && band < mNumPeaking + 2);
122     if (band == 0) {
123         mpLowShelf->setFrequency(millihertz);
124     } else if (band == mNumPeaking + 1) {
125         mpHighShelf->setFrequency(millihertz);
126     } else {
127         mpPeakingFilters[band - 1].setFrequency(millihertz);
128     }
129     mCurPreset = PRESET_CUSTOM;
130 }
131 
setBandwidth(int band,uint32_t cents)132 void AudioEqualizer::setBandwidth(int band, uint32_t cents) {
133     ALOGV("AudioEqualizer::setBandwidth(band=%d, cents=%d)", band, cents);
134     assert(band >= 0 && band < mNumPeaking + 2);
135     if (band > 0 && band < mNumPeaking + 1) {
136         mpPeakingFilters[band - 1].setBandwidth(cents);
137         mCurPreset = PRESET_CUSTOM;
138     }
139 }
140 
getGain(int band) const141 int32_t AudioEqualizer::getGain(int band) const {
142     assert(band >= 0 && band < mNumPeaking + 2);
143     if (band == 0) {
144         return mpLowShelf->getGain();
145     } else if (band == mNumPeaking + 1) {
146         return mpHighShelf->getGain();
147     } else {
148         return mpPeakingFilters[band - 1].getGain();
149     }
150 }
151 
getFrequency(int band) const152 uint32_t AudioEqualizer::getFrequency(int band) const {
153     assert(band >= 0 && band < mNumPeaking + 2);
154     if (band == 0) {
155         return mpLowShelf->getFrequency();
156     } else if (band == mNumPeaking + 1) {
157         return mpHighShelf->getFrequency();
158     } else {
159         return mpPeakingFilters[band - 1].getFrequency();
160     }
161 }
162 
getBandwidth(int band) const163 uint32_t AudioEqualizer::getBandwidth(int band) const {
164     assert(band >= 0 && band < mNumPeaking + 2);
165     if (band == 0 || band == mNumPeaking + 1) {
166         return 0;
167     } else {
168         return mpPeakingFilters[band - 1].getBandwidth();
169     }
170 }
171 
getBandRange(int band,uint32_t & low,uint32_t & high) const172 void AudioEqualizer::getBandRange(int band, uint32_t & low,
173                                   uint32_t & high) const {
174     assert(band >= 0 && band < mNumPeaking + 2);
175     if (band == 0) {
176         low = 0;
177         high = mpLowShelf->getFrequency();
178     } else if (band == mNumPeaking + 1) {
179         low = mpHighShelf->getFrequency();
180         high = mSampleRate * 500;
181     } else {
182         mpPeakingFilters[band - 1].getBandRange(low, high);
183     }
184 }
185 
getPresetName(int preset) const186 const char * AudioEqualizer::getPresetName(int preset) const {
187     assert(preset < mNumPresets && preset >= PRESET_CUSTOM);
188     if (preset == PRESET_CUSTOM) {
189         return "Custom";
190     } else {
191         return mpPresets[preset].name;
192     }
193 }
194 
getNumPresets() const195 int AudioEqualizer::getNumPresets() const {
196     return mNumPresets;
197 }
198 
getPreset() const199 int AudioEqualizer::getPreset() const {
200     return mCurPreset;
201 }
202 
setPreset(int preset)203 void AudioEqualizer::setPreset(int preset) {
204     ALOGV("AudioEqualizer::setPreset(preset=%d)", preset);
205     assert(preset < mNumPresets && preset >= 0);
206     const PresetConfig &presetCfg = mpPresets[preset];
207     for (int band = 0; band < (mNumPeaking + 2); ++band) {
208         const BandConfig & bandCfg = presetCfg.bandConfigs[band];
209         setGain(band, bandCfg.gain);
210         setFrequency(band, bandCfg.freq);
211         setBandwidth(band, bandCfg.bandwidth);
212     }
213     mCurPreset = preset;
214 }
215 
commit(bool immediate)216 void AudioEqualizer::commit(bool immediate) {
217     ALOGV("AudioEqualizer::commit(immediate=%d)", immediate);
218     mpLowShelf->commit(immediate);
219     for (int i = 0; i < mNumPeaking; ++i) {
220         mpPeakingFilters[i].commit(immediate);
221     }
222     mpHighShelf->commit(immediate);
223 }
224 
process(const audio_sample_t * pIn,audio_sample_t * pOut,int frameCount)225 void AudioEqualizer::process(const audio_sample_t * pIn,
226                              audio_sample_t * pOut,
227                              int frameCount) {
228 //    ALOGV("AudioEqualizer::process(frameCount=%d)", frameCount);
229     mpLowShelf->process(pIn, pOut, frameCount);
230     for (int i = 0; i < mNumPeaking; ++i) {
231         mpPeakingFilters[i].process(pIn, pOut, frameCount);
232     }
233     mpHighShelf->process(pIn, pOut, frameCount);
234 }
235 
enable(bool immediate)236 void AudioEqualizer::enable(bool immediate) {
237     ALOGV("AudioEqualizer::enable(immediate=%d)", immediate);
238     mpLowShelf->enable(immediate);
239     for (int i = 0; i < mNumPeaking; ++i) {
240         mpPeakingFilters[i].enable(immediate);
241     }
242     mpHighShelf->enable(immediate);
243 }
244 
disable(bool immediate)245 void AudioEqualizer::disable(bool immediate) {
246     ALOGV("AudioEqualizer::disable(immediate=%d)", immediate);
247     mpLowShelf->disable(immediate);
248     for (int i = 0; i < mNumPeaking; ++i) {
249         mpPeakingFilters[i].disable(immediate);
250     }
251     mpHighShelf->disable(immediate);
252 }
253 
getMostRelevantBand(uint32_t targetFreq) const254 int AudioEqualizer::getMostRelevantBand(uint32_t targetFreq) const {
255     // First, find the two bands that the target frequency is between.
256     uint32_t low = mpLowShelf->getFrequency();
257     if (targetFreq <= low) {
258         return 0;
259     }
260     uint32_t high = mpHighShelf->getFrequency();
261     if (targetFreq >= high) {
262         return mNumPeaking + 1;
263     }
264     int band = mNumPeaking;
265     for (int i = 0; i < mNumPeaking; ++i) {
266         uint32_t freq = mpPeakingFilters[i].getFrequency();
267         if (freq >= targetFreq) {
268             high = freq;
269             band = i;
270             break;
271         }
272         low = freq;
273     }
274     // Now, low is right below the target and high is right above. See which one
275     // is closer on a log scale.
276     low = Effects_log2(low);
277     high = Effects_log2(high);
278     targetFreq = Effects_log2(targetFreq);
279     if (high - targetFreq < targetFreq - low) {
280         return band + 1;
281     } else {
282         return band;
283     }
284 }
285 
286 
AudioEqualizer(void * pMem,int nBands,int nChannels,int sampleRate,bool ownMem,const PresetConfig * presets,int nPresets)287 AudioEqualizer::AudioEqualizer(void * pMem, int nBands, int nChannels,
288                                int sampleRate, bool ownMem,
289                                const PresetConfig * presets, int nPresets)
290                                : mSampleRate(sampleRate)
291                                , mpPresets(presets)
292                                , mNumPresets(nPresets) {
293     assert(pMem != NULL);
294     assert(nPresets == 0 || nPresets > 0 && presets != NULL);
295     mpMem = ownMem ? pMem : NULL;
296 
297     pMem = (char *) pMem + sizeof(AudioEqualizer);
298     mpLowShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kLowShelf,
299                                                 nChannels, sampleRate);
300     pMem = (char *) pMem + sizeof(AudioShelvingFilter);
301     mpHighShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kHighShelf,
302                                                  nChannels, sampleRate);
303     pMem = (char *) pMem + sizeof(AudioShelvingFilter);
304     mNumPeaking = nBands - 2;
305     if (mNumPeaking > 0) {
306         mpPeakingFilters = reinterpret_cast<AudioPeakingFilter *>(pMem);
307         for (int i = 0; i < mNumPeaking; ++i) {
308             new (&mpPeakingFilters[i]) AudioPeakingFilter(nChannels,
309                                                           sampleRate);
310         }
311     }
312     reset();
313 }
314 
315 }
316