From 2c8e5cab3faa6d360e222b7a6c40a80083d021ac Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Fri, 9 Jul 2010 12:28:50 -0700 Subject: First submission of audio effect library from NXP software. This CL contains the first open sourceable version of the audio effect library from NXP software. The effects implemented are: - Bass boost - Virtualizer (stereo widening) - Equalizer - Spectrum analyzer Source file for the effect engines are located under libeffects/lvm/lib The wrapper implementing the interface with the audio effect framework in under libeffects/lvm/wrapper The code of other effect libraries has also been reorganized fo clarity: - the effect factory is now under libeffects/factory - the test equalizer and reverb effects are under libeffect/testlibs - the visualizer is under libeffects/virtualizer Change-Id: I8d91e2181f81b89f8fc0c1e1e6bf552c5809b2eb --- media/libeffects/testlibs/AudioEqualizer.cpp | 315 +++++++++++++++++++++++++++ 1 file changed, 315 insertions(+) create mode 100644 media/libeffects/testlibs/AudioEqualizer.cpp (limited to 'media/libeffects/testlibs/AudioEqualizer.cpp') diff --git a/media/libeffects/testlibs/AudioEqualizer.cpp b/media/libeffects/testlibs/AudioEqualizer.cpp new file mode 100644 index 0000000..44c9476 --- /dev/null +++ b/media/libeffects/testlibs/AudioEqualizer.cpp @@ -0,0 +1,315 @@ +/* + * 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 +#include +#include +#include + +#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) { + LOGV("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) { + LOGV("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() { + LOGV("AudioEqualizer::clear()"); + mpLowShelf->clear(); + for (int i = 0; i < mNumPeaking; ++i) { + mpPeakingFilters[i].clear(); + } + mpHighShelf->clear(); +} + +void AudioEqualizer::free() { + LOGV("AudioEqualizer::free()"); + if (mpMem != NULL) { + ::free(mpMem); + } +} + +void AudioEqualizer::reset() { + LOGV("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) { + LOGV("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) { + LOGV("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) { + LOGV("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) { + LOGV("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) { + LOGV("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) { +// LOGV("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) { + LOGV("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) { + LOGV("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(pMem); + for (int i = 0; i < mNumPeaking; ++i) { + new (&mpPeakingFilters[i]) AudioPeakingFilter(nChannels, + sampleRate); + } + } + reset(); +} + +} -- cgit v1.1