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
29namespace android {
30
31size_t AudioEqualizer::GetInstanceSize(int nBands) {
32    assert(nBands >= 2);
33    return sizeof(AudioEqualizer) +
34           sizeof(AudioShelvingFilter) * 2 +
35           sizeof(AudioPeakingFilter) * (nBands - 2);
36}
37
38AudioEqualizer * 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
58void 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
68void 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
77void AudioEqualizer::free() {
78    ALOGV("AudioEqualizer::free()");
79    if (mpMem != NULL) {
80        ::free(mpMem);
81    }
82}
83
84void 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
105void 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
118void 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
132void 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
141int32_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
152uint32_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
163uint32_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
172void 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
186const 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
195int AudioEqualizer::getNumPresets() const {
196    return mNumPresets;
197}
198
199int AudioEqualizer::getPreset() const {
200    return mCurPreset;
201}
202
203void 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
216void 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
225void 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
236void 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
245void 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
254int 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
287AudioEqualizer::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