summaryrefslogtreecommitdiffstats
path: root/media/libeffects/testlibs/AudioEqualizer.cpp
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-07-09 12:28:50 -0700
committerEric Laurent <elaurent@google.com>2010-07-17 06:33:00 -0700
commit2c8e5cab3faa6d360e222b7a6c40a80083d021ac (patch)
treefd19b8baa829edb78116b089d1122ea4ef0921e1 /media/libeffects/testlibs/AudioEqualizer.cpp
parentada2ac8e09b6d3f2b3c3155a852ba0fffae1b592 (diff)
downloadframeworks_av-2c8e5cab3faa6d360e222b7a6c40a80083d021ac.zip
frameworks_av-2c8e5cab3faa6d360e222b7a6c40a80083d021ac.tar.gz
frameworks_av-2c8e5cab3faa6d360e222b7a6c40a80083d021ac.tar.bz2
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
Diffstat (limited to 'media/libeffects/testlibs/AudioEqualizer.cpp')
-rw-r--r--media/libeffects/testlibs/AudioEqualizer.cpp315
1 files changed, 315 insertions, 0 deletions
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 <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) {
+ 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<AudioPeakingFilter *>(pMem);
+ for (int i = 0; i < mNumPeaking; ++i) {
+ new (&mpPeakingFilters[i]) AudioPeakingFilter(nChannels,
+ sampleRate);
+ }
+ }
+ reset();
+}
+
+}