Eric Laurent | 5fe37c6 | 2010-05-21 06:05:13 -0700 | [diff] [blame] | 1 | /* /android/src/frameworks/base/libs/audioflinger/AudioShelvingFilter.cpp |
| 2 | ** |
| 3 | ** Copyright 2009, The Android Open Source Project |
| 4 | ** |
| 5 | ** Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | ** you may not use this file except in compliance with the License. |
| 7 | ** You may obtain a copy of the License at |
| 8 | ** |
| 9 | ** http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | ** |
| 11 | ** Unless required by applicable law or agreed to in writing, software |
| 12 | ** distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | ** See the License for the specific language governing permissions and |
| 15 | ** limitations under the License. |
| 16 | */ |
| 17 | |
| 18 | #include "AudioShelvingFilter.h" |
| 19 | #include "AudioCommon.h" |
| 20 | #include "EffectsMath.h" |
| 21 | |
| 22 | #include <new> |
| 23 | #include <assert.h> |
Glenn Kasten | e80a4cc | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 24 | #include <cutils/compiler.h> |
Eric Laurent | 5fe37c6 | 2010-05-21 06:05:13 -0700 | [diff] [blame] | 25 | |
| 26 | namespace android { |
| 27 | // Format of the coefficient tables: |
| 28 | // kCoefTable[freq][gain][coef] |
| 29 | // freq - cutoff frequency, in octaves below Nyquist,from -10 to -6 in low |
| 30 | // shelf, -2 to 0 in high shelf. |
| 31 | // gain - gain, in millibel, starting at -9600, jumps of 1024, to 4736 millibel. |
| 32 | // coef - 0: b0 |
| 33 | // 1: b1 |
| 34 | // 2: b2 |
| 35 | // 3: -a1 |
| 36 | // 4: -a2 |
| 37 | static const size_t kHiInDims[2] = {3, 15}; |
| 38 | static const audio_coef_t kHiCoefTable[3*15*5] = { |
| 39 | #include "AudioHighShelfFilterCoef.inl" |
| 40 | }; |
| 41 | static const size_t kLoInDims[2] = {5, 15}; |
| 42 | static const audio_coef_t kLoCoefTable[5*15*5] = { |
| 43 | #include "AudioLowShelfFilterCoef.inl" |
| 44 | }; |
| 45 | |
| 46 | AudioCoefInterpolator AudioShelvingFilter::mHiCoefInterp(2, kHiInDims, 5, (const audio_coef_t*) kHiCoefTable); |
| 47 | AudioCoefInterpolator AudioShelvingFilter::mLoCoefInterp(2, kLoInDims, 5, (const audio_coef_t*) kLoCoefTable); |
| 48 | |
| 49 | AudioShelvingFilter::AudioShelvingFilter(ShelfType type, int nChannels, |
| 50 | int sampleRate) |
Eric Laurent | 53334cd | 2010-06-23 17:38:20 -0700 | [diff] [blame] | 51 | : mType(type), |
| 52 | mBiquad(nChannels, sampleRate) { |
Eric Laurent | 5fe37c6 | 2010-05-21 06:05:13 -0700 | [diff] [blame] | 53 | configure(nChannels, sampleRate); |
| 54 | } |
| 55 | |
| 56 | void AudioShelvingFilter::configure(int nChannels, int sampleRate) { |
| 57 | mNiquistFreq = sampleRate * 500; |
| 58 | mFrequencyFactor = ((1ull) << 42) / mNiquistFreq; |
| 59 | mBiquad.configure(nChannels, sampleRate); |
| 60 | setFrequency(mNominalFrequency); |
| 61 | commit(true); |
| 62 | } |
| 63 | |
| 64 | void AudioShelvingFilter::reset() { |
| 65 | setGain(0); |
| 66 | setFrequency(mType == kLowShelf ? 0 : mNiquistFreq); |
| 67 | commit(true); |
| 68 | } |
| 69 | |
| 70 | void AudioShelvingFilter::setFrequency(uint32_t millihertz) { |
| 71 | mNominalFrequency = millihertz; |
Glenn Kasten | e80a4cc | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 72 | if (CC_UNLIKELY(millihertz > mNiquistFreq / 2)) { |
Eric Laurent | 5fe37c6 | 2010-05-21 06:05:13 -0700 | [diff] [blame] | 73 | millihertz = mNiquistFreq / 2; |
| 74 | } |
| 75 | uint32_t normFreq = static_cast<uint32_t>( |
| 76 | (static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10); |
| 77 | uint32_t log2minFreq = (mType == kLowShelf ? (32-10) : (32-2)); |
Glenn Kasten | e80a4cc | 2011-12-15 09:51:17 -0800 | [diff] [blame] | 78 | if (CC_LIKELY(normFreq > (1U << log2minFreq))) { |
Eric Laurent | 5fe37c6 | 2010-05-21 06:05:13 -0700 | [diff] [blame] | 79 | mFrequency = (Effects_log2(normFreq) - (log2minFreq << 15)) << (FREQ_PRECISION_BITS - 15); |
| 80 | } else { |
| 81 | mFrequency = 0; |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | void AudioShelvingFilter::setGain(int32_t millibel) { |
| 86 | mGain = millibel + 9600; |
| 87 | } |
| 88 | |
| 89 | void AudioShelvingFilter::commit(bool immediate) { |
| 90 | audio_coef_t coefs[5]; |
| 91 | int intCoord[2] = { |
| 92 | mFrequency >> FREQ_PRECISION_BITS, |
| 93 | mGain >> GAIN_PRECISION_BITS |
| 94 | }; |
| 95 | uint32_t fracCoord[2] = { |
| 96 | mFrequency << (32 - FREQ_PRECISION_BITS), |
| 97 | static_cast<uint32_t>(mGain) << (32 - GAIN_PRECISION_BITS) |
| 98 | }; |
| 99 | if (mType == kHighShelf) { |
| 100 | mHiCoefInterp.getCoef(intCoord, fracCoord, coefs); |
| 101 | } else { |
| 102 | mLoCoefInterp.getCoef(intCoord, fracCoord, coefs); |
| 103 | } |
| 104 | mBiquad.setCoefs(coefs, immediate); |
| 105 | } |
| 106 | |
| 107 | } |