Eric Laurent | 5fe37c6 | 2010-05-21 06:05:13 -0700 | [diff] [blame] | 1 | /* //device/include/server/AudioFlinger/AudioPeakingFilter.cpp |
| 2 | ** |
| 3 | ** Copyright 2007, 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 "AudioPeakingFilter.h" |
| 19 | #include "AudioCommon.h" |
| 20 | #include "EffectsMath.h" |
| 21 | |
| 22 | #include <new> |
| 23 | #include <assert.h> |
| 24 | |
| 25 | #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) |
| 26 | #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) |
| 27 | |
| 28 | namespace android { |
| 29 | // Format of the coefficient table: |
| 30 | // kCoefTable[freq][gain][bw][coef] |
| 31 | // freq - peak frequency, in octaves below Nyquist,from -9 to -1. |
| 32 | // gain - gain, in millibel, starting at -9600, jumps of 1024, to 4736 millibel. |
| 33 | // bw - bandwidth, starting at 1 cent, jumps of 1024, to 3073 cents. |
| 34 | // coef - 0: b0 |
| 35 | // 1: b1 |
| 36 | // 2: b2 |
| 37 | // 3: -a1 |
| 38 | // 4: -a2 |
| 39 | static const size_t kInDims[3] = {9, 15, 4}; |
| 40 | static const audio_coef_t kCoefTable[9*15*4*5] = { |
| 41 | #include "AudioPeakingFilterCoef.inl" |
| 42 | }; |
| 43 | |
| 44 | AudioCoefInterpolator AudioPeakingFilter::mCoefInterp(3, kInDims, 5, (const audio_coef_t*) kCoefTable); |
| 45 | |
| 46 | AudioPeakingFilter::AudioPeakingFilter(int nChannels, int sampleRate) |
| 47 | : mBiquad(nChannels, sampleRate) { |
| 48 | configure(nChannels, sampleRate); |
| 49 | reset(); |
| 50 | } |
| 51 | |
| 52 | void AudioPeakingFilter::configure(int nChannels, int sampleRate) { |
| 53 | mNiquistFreq = sampleRate * 500; |
| 54 | mFrequencyFactor = ((1ull) << 42) / mNiquistFreq; |
| 55 | mBiquad.configure(nChannels, sampleRate); |
| 56 | setFrequency(mNominalFrequency); |
| 57 | commit(true); |
| 58 | } |
| 59 | |
| 60 | void AudioPeakingFilter::reset() { |
| 61 | setGain(0); |
| 62 | setFrequency(0); |
| 63 | setBandwidth(2400); |
| 64 | commit(true); |
| 65 | } |
| 66 | |
| 67 | void AudioPeakingFilter::setFrequency(uint32_t millihertz) { |
| 68 | mNominalFrequency = millihertz; |
| 69 | if (UNLIKELY(millihertz > mNiquistFreq / 2)) { |
| 70 | millihertz = mNiquistFreq / 2; |
| 71 | } |
| 72 | uint32_t normFreq = static_cast<uint32_t>( |
| 73 | (static_cast<uint64_t>(millihertz) * mFrequencyFactor) >> 10); |
| 74 | if (LIKELY(normFreq > (1 << 23))) { |
| 75 | mFrequency = (Effects_log2(normFreq) - ((32-9) << 15)) << (FREQ_PRECISION_BITS - 15); |
| 76 | } else { |
| 77 | mFrequency = 0; |
| 78 | } |
| 79 | } |
| 80 | |
| 81 | void AudioPeakingFilter::setGain(int32_t millibel) { |
| 82 | mGain = millibel + 9600; |
| 83 | } |
| 84 | |
| 85 | void AudioPeakingFilter::setBandwidth(uint32_t cents) { |
| 86 | mBandwidth = cents - 1; |
| 87 | } |
| 88 | |
| 89 | void AudioPeakingFilter::commit(bool immediate) { |
| 90 | audio_coef_t coefs[5]; |
| 91 | int intCoord[3] = { |
| 92 | mFrequency >> FREQ_PRECISION_BITS, |
| 93 | mGain >> GAIN_PRECISION_BITS, |
| 94 | mBandwidth >> BANDWIDTH_PRECISION_BITS |
| 95 | }; |
| 96 | uint32_t fracCoord[3] = { |
| 97 | mFrequency << (32 - FREQ_PRECISION_BITS), |
| 98 | static_cast<uint32_t>(mGain) << (32 - GAIN_PRECISION_BITS), |
| 99 | mBandwidth << (32 - BANDWIDTH_PRECISION_BITS) |
| 100 | }; |
| 101 | mCoefInterp.getCoef(intCoord, fracCoord, coefs); |
| 102 | mBiquad.setCoefs(coefs, immediate); |
| 103 | } |
| 104 | |
| 105 | void AudioPeakingFilter::getBandRange(uint32_t & low, uint32_t & high) const { |
| 106 | // Half bandwidth, in octaves, 15-bit precision |
| 107 | int32_t halfBW = (((mBandwidth + 1) / 2) << 15) / 1200; |
| 108 | |
| 109 | low = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(-halfBW + (16 << 15))) >> 16); |
| 110 | if (UNLIKELY(halfBW >= (16 << 15))) { |
| 111 | high = mNiquistFreq; |
| 112 | } else { |
| 113 | high = static_cast<uint32_t>((static_cast<uint64_t>(mNominalFrequency) * Effects_exp2(halfBW + (16 << 15))) >> 16); |
| 114 | if (UNLIKELY(high > mNiquistFreq)) { |
| 115 | high = mNiquistFreq; |
| 116 | } |
| 117 | } |
| 118 | } |
| 119 | |
| 120 | } |
| 121 | |