/* * Copyright 2009, The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "AudioEqualizer" #include <assert.h> #include <stdlib.h> #include <new> #include <utils/Log.h> #include "AudioEqualizer.h" #include "AudioPeakingFilter.h" #include "AudioShelvingFilter.h" #include "EffectsMath.h" namespace android { size_t AudioEqualizer::GetInstanceSize(int nBands) { assert(nBands >= 2); return sizeof(AudioEqualizer) + sizeof(AudioShelvingFilter) * 2 + sizeof(AudioPeakingFilter) * (nBands - 2); } AudioEqualizer * AudioEqualizer::CreateInstance(void * pMem, int nBands, int nChannels, int sampleRate, const PresetConfig * presets, int nPresets) { ALOGV("AudioEqualizer::CreateInstance(pMem=%p, nBands=%d, nChannels=%d, " "sampleRate=%d, nPresets=%d)", pMem, nBands, nChannels, sampleRate, nPresets); assert(nBands >= 2); bool ownMem = false; if (pMem == NULL) { pMem = malloc(GetInstanceSize(nBands)); if (pMem == NULL) { return NULL; } ownMem = true; } return new (pMem) AudioEqualizer(pMem, nBands, nChannels, sampleRate, ownMem, presets, nPresets); } void AudioEqualizer::configure(int nChannels, int sampleRate) { ALOGV("AudioEqualizer::configure(nChannels=%d, sampleRate=%d)", nChannels, sampleRate); mpLowShelf->configure(nChannels, sampleRate); for (int i = 0; i < mNumPeaking; ++i) { mpPeakingFilters[i].configure(nChannels, sampleRate); } mpHighShelf->configure(nChannels, sampleRate); } void AudioEqualizer::clear() { ALOGV("AudioEqualizer::clear()"); mpLowShelf->clear(); for (int i = 0; i < mNumPeaking; ++i) { mpPeakingFilters[i].clear(); } mpHighShelf->clear(); } void AudioEqualizer::free() { ALOGV("AudioEqualizer::free()"); if (mpMem != NULL) { ::free(mpMem); } } void AudioEqualizer::reset() { ALOGV("AudioEqualizer::reset()"); const int32_t bottom = Effects_log2(kMinFreq); const int32_t top = Effects_log2(mSampleRate * 500); const int32_t jump = (top - bottom) / (mNumPeaking + 2); int32_t centerFreq = bottom + jump/2; mpLowShelf->reset(); mpLowShelf->setFrequency(Effects_exp2(centerFreq)); centerFreq += jump; for (int i = 0; i < mNumPeaking; ++i) { mpPeakingFilters[i].reset(); mpPeakingFilters[i].setFrequency(Effects_exp2(centerFreq)); centerFreq += jump; } mpHighShelf->reset(); mpHighShelf->setFrequency(Effects_exp2(centerFreq)); commit(true); mCurPreset = PRESET_CUSTOM; } void AudioEqualizer::setGain(int band, int32_t millibel) { ALOGV("AudioEqualizer::setGain(band=%d, millibel=%d)", band, millibel); assert(band >= 0 && band < mNumPeaking + 2); if (band == 0) { mpLowShelf->setGain(millibel); } else if (band == mNumPeaking + 1) { mpHighShelf->setGain(millibel); } else { mpPeakingFilters[band - 1].setGain(millibel); } mCurPreset = PRESET_CUSTOM; } void AudioEqualizer::setFrequency(int band, uint32_t millihertz) { ALOGV("AudioEqualizer::setFrequency(band=%d, millihertz=%d)", band, millihertz); assert(band >= 0 && band < mNumPeaking + 2); if (band == 0) { mpLowShelf->setFrequency(millihertz); } else if (band == mNumPeaking + 1) { mpHighShelf->setFrequency(millihertz); } else { mpPeakingFilters[band - 1].setFrequency(millihertz); } mCurPreset = PRESET_CUSTOM; } void AudioEqualizer::setBandwidth(int band, uint32_t cents) { ALOGV("AudioEqualizer::setBandwidth(band=%d, cents=%d)", band, cents); assert(band >= 0 && band < mNumPeaking + 2); if (band > 0 && band < mNumPeaking + 1) { mpPeakingFilters[band - 1].setBandwidth(cents); mCurPreset = PRESET_CUSTOM; } } int32_t AudioEqualizer::getGain(int band) const { assert(band >= 0 && band < mNumPeaking + 2); if (band == 0) { return mpLowShelf->getGain(); } else if (band == mNumPeaking + 1) { return mpHighShelf->getGain(); } else { return mpPeakingFilters[band - 1].getGain(); } } uint32_t AudioEqualizer::getFrequency(int band) const { assert(band >= 0 && band < mNumPeaking + 2); if (band == 0) { return mpLowShelf->getFrequency(); } else if (band == mNumPeaking + 1) { return mpHighShelf->getFrequency(); } else { return mpPeakingFilters[band - 1].getFrequency(); } } uint32_t AudioEqualizer::getBandwidth(int band) const { assert(band >= 0 && band < mNumPeaking + 2); if (band == 0 || band == mNumPeaking + 1) { return 0; } else { return mpPeakingFilters[band - 1].getBandwidth(); } } void AudioEqualizer::getBandRange(int band, uint32_t & low, uint32_t & high) const { assert(band >= 0 && band < mNumPeaking + 2); if (band == 0) { low = 0; high = mpLowShelf->getFrequency(); } else if (band == mNumPeaking + 1) { low = mpHighShelf->getFrequency(); high = mSampleRate * 500; } else { mpPeakingFilters[band - 1].getBandRange(low, high); } } const char * AudioEqualizer::getPresetName(int preset) const { assert(preset < mNumPresets && preset >= PRESET_CUSTOM); if (preset == PRESET_CUSTOM) { return "Custom"; } else { return mpPresets[preset].name; } } int AudioEqualizer::getNumPresets() const { return mNumPresets; } int AudioEqualizer::getPreset() const { return mCurPreset; } void AudioEqualizer::setPreset(int preset) { ALOGV("AudioEqualizer::setPreset(preset=%d)", preset); assert(preset < mNumPresets && preset >= 0); const PresetConfig &presetCfg = mpPresets[preset]; for (int band = 0; band < (mNumPeaking + 2); ++band) { const BandConfig & bandCfg = presetCfg.bandConfigs[band]; setGain(band, bandCfg.gain); setFrequency(band, bandCfg.freq); setBandwidth(band, bandCfg.bandwidth); } mCurPreset = preset; } void AudioEqualizer::commit(bool immediate) { ALOGV("AudioEqualizer::commit(immediate=%d)", immediate); mpLowShelf->commit(immediate); for (int i = 0; i < mNumPeaking; ++i) { mpPeakingFilters[i].commit(immediate); } mpHighShelf->commit(immediate); } void AudioEqualizer::process(const audio_sample_t * pIn, audio_sample_t * pOut, int frameCount) { // ALOGV("AudioEqualizer::process(frameCount=%d)", frameCount); mpLowShelf->process(pIn, pOut, frameCount); for (int i = 0; i < mNumPeaking; ++i) { mpPeakingFilters[i].process(pIn, pOut, frameCount); } mpHighShelf->process(pIn, pOut, frameCount); } void AudioEqualizer::enable(bool immediate) { ALOGV("AudioEqualizer::enable(immediate=%d)", immediate); mpLowShelf->enable(immediate); for (int i = 0; i < mNumPeaking; ++i) { mpPeakingFilters[i].enable(immediate); } mpHighShelf->enable(immediate); } void AudioEqualizer::disable(bool immediate) { ALOGV("AudioEqualizer::disable(immediate=%d)", immediate); mpLowShelf->disable(immediate); for (int i = 0; i < mNumPeaking; ++i) { mpPeakingFilters[i].disable(immediate); } mpHighShelf->disable(immediate); } int AudioEqualizer::getMostRelevantBand(uint32_t targetFreq) const { // First, find the two bands that the target frequency is between. uint32_t low = mpLowShelf->getFrequency(); if (targetFreq <= low) { return 0; } uint32_t high = mpHighShelf->getFrequency(); if (targetFreq >= high) { return mNumPeaking + 1; } int band = mNumPeaking; for (int i = 0; i < mNumPeaking; ++i) { uint32_t freq = mpPeakingFilters[i].getFrequency(); if (freq >= targetFreq) { high = freq; band = i; break; } low = freq; } // Now, low is right below the target and high is right above. See which one // is closer on a log scale. low = Effects_log2(low); high = Effects_log2(high); targetFreq = Effects_log2(targetFreq); if (high - targetFreq < targetFreq - low) { return band + 1; } else { return band; } } AudioEqualizer::AudioEqualizer(void * pMem, int nBands, int nChannels, int sampleRate, bool ownMem, const PresetConfig * presets, int nPresets) : mSampleRate(sampleRate) , mpPresets(presets) , mNumPresets(nPresets) { assert(pMem != NULL); assert(nPresets == 0 || nPresets > 0 && presets != NULL); mpMem = ownMem ? pMem : NULL; pMem = (char *) pMem + sizeof(AudioEqualizer); mpLowShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kLowShelf, nChannels, sampleRate); pMem = (char *) pMem + sizeof(AudioShelvingFilter); mpHighShelf = new (pMem) AudioShelvingFilter(AudioShelvingFilter::kHighShelf, nChannels, sampleRate); pMem = (char *) pMem + sizeof(AudioShelvingFilter); mNumPeaking = nBands - 2; if (mNumPeaking > 0) { mpPeakingFilters = reinterpret_cast<AudioPeakingFilter *>(pMem); for (int i = 0; i < mNumPeaking; ++i) { new (&mpPeakingFilters[i]) AudioPeakingFilter(nChannels, sampleRate); } } reset(); } }