1 /* //device/servers/AudioFlinger/AudioBiquadFilter.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 <string.h> 19 #include <assert.h> 20 21 #include "AudioBiquadFilter.h" 22 23 #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) 24 #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) 25 26 namespace android { 27 28 const audio_coef_t AudioBiquadFilter::IDENTITY_COEFS[AudioBiquadFilter::NUM_COEFS] = { AUDIO_COEF_ONE, 0, 0, 0, 0 }; 29 30 AudioBiquadFilter::AudioBiquadFilter(int nChannels, int sampleRate) { 31 configure(nChannels, sampleRate); 32 reset(); 33 } 34 35 void AudioBiquadFilter::configure(int nChannels, int sampleRate) { 36 assert(nChannels > 0 && nChannels <= MAX_CHANNELS); 37 assert(sampleRate > 0); 38 mNumChannels = nChannels; 39 mMaxDelta = static_cast<int64_t>(MAX_DELTA_PER_SEC) 40 * AUDIO_COEF_ONE 41 / sampleRate; 42 clear(); 43 } 44 45 void AudioBiquadFilter::reset() { 46 memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs)); 47 mCoefDirtyBits = 0; 48 setState(STATE_BYPASS); 49 } 50 51 void AudioBiquadFilter::clear() { 52 memset(mDelays, 0, sizeof(mDelays)); 53 } 54 55 void AudioBiquadFilter::setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate) { 56 memcpy(mTargetCoefs, coefs, sizeof(mTargetCoefs)); 57 if (mState & STATE_ENABLED_MASK) { 58 if (UNLIKELY(immediate)) { 59 memcpy(mCoefs, coefs, sizeof(mCoefs)); 60 setState(STATE_NORMAL); 61 } else { 62 setState(STATE_TRANSITION_TO_NORMAL); 63 } 64 } 65 } 66 67 void AudioBiquadFilter::process(const audio_sample_t in[], audio_sample_t out[], 68 int frameCount) { 69 (this->*mCurProcessFunc)(in, out, frameCount); 70 } 71 72 void AudioBiquadFilter::enable(bool immediate) { 73 if (UNLIKELY(immediate)) { 74 memcpy(mCoefs, mTargetCoefs, sizeof(mCoefs)); 75 setState(STATE_NORMAL); 76 } else { 77 setState(STATE_TRANSITION_TO_NORMAL); 78 } 79 } 80 81 void AudioBiquadFilter::disable(bool immediate) { 82 if (UNLIKELY(immediate)) { 83 memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs)); 84 setState(STATE_BYPASS); 85 } else { 86 setState(STATE_TRANSITION_TO_BYPASS); 87 } 88 } 89 90 void AudioBiquadFilter::setState(state_t state) { 91 switch (state) { 92 case STATE_BYPASS: 93 mCurProcessFunc = &AudioBiquadFilter::process_bypass; 94 break; 95 case STATE_TRANSITION_TO_BYPASS: 96 if (mNumChannels == 1) { 97 mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_mono; 98 } else { 99 mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_multi; 100 } 101 mCoefDirtyBits = (1 << NUM_COEFS) - 1; 102 break; 103 case STATE_TRANSITION_TO_NORMAL: 104 if (mNumChannels == 1) { 105 mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_mono; 106 } else { 107 mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_multi; 108 } 109 mCoefDirtyBits = (1 << NUM_COEFS) - 1; 110 break; 111 case STATE_NORMAL: 112 if (mNumChannels == 1) { 113 mCurProcessFunc = &AudioBiquadFilter::process_normal_mono; 114 } else { 115 mCurProcessFunc = &AudioBiquadFilter::process_normal_multi; 116 } 117 break; 118 } 119 mState = state; 120 } 121 122 bool AudioBiquadFilter::updateCoefs(const audio_coef_t coefs[NUM_COEFS], 123 int frameCount) { 124 int64_t maxDelta = mMaxDelta * frameCount; 125 for (int i = 0; i < NUM_COEFS; ++i) { 126 if (mCoefDirtyBits & (1<<i)) { 127 audio_coef_t diff = coefs[i] - mCoefs[i]; 128 if (diff > maxDelta) { 129 mCoefs[i] += maxDelta; 130 } else if (diff < -maxDelta) { 131 mCoefs[i] -= maxDelta; 132 } else { 133 mCoefs[i] = coefs[i]; 134 mCoefDirtyBits ^= (1<<i); 135 } 136 } 137 } 138 return mCoefDirtyBits == 0; 139 } 140 141 void AudioBiquadFilter::process_bypass(const audio_sample_t * in, 142 audio_sample_t * out, 143 int frameCount) { 144 // The common case is in-place processing, because this is what the EQ does. 145 if (UNLIKELY(in != out)) { 146 memcpy(out, in, frameCount * mNumChannels * sizeof(audio_sample_t)); 147 } 148 } 149 150 void AudioBiquadFilter::process_normal_mono(const audio_sample_t * in, 151 audio_sample_t * out, 152 int frameCount) { 153 size_t nFrames = frameCount; 154 audio_sample_t x1 = mDelays[0][0]; 155 audio_sample_t x2 = mDelays[0][1]; 156 audio_sample_t y1 = mDelays[0][2]; 157 audio_sample_t y2 = mDelays[0][3]; 158 const audio_coef_t b0 = mCoefs[0]; 159 const audio_coef_t b1 = mCoefs[1]; 160 const audio_coef_t b2 = mCoefs[2]; 161 const audio_coef_t a1 = mCoefs[3]; 162 const audio_coef_t a2 = mCoefs[4]; 163 while (nFrames-- > 0) { 164 audio_sample_t x0 = *(in++); 165 audio_coef_sample_acc_t acc; 166 acc = mul_coef_sample(b0, x0); 167 acc = mac_coef_sample(b1, x1, acc); 168 acc = mac_coef_sample(b2, x2, acc); 169 acc = mac_coef_sample(a1, y1, acc); 170 acc = mac_coef_sample(a2, y2, acc); 171 audio_sample_t y0 = coef_sample_acc_to_sample(acc); 172 y2 = y1; 173 y1 = y0; 174 x2 = x1; 175 x1 = x0; 176 (*out++) = y0; 177 } 178 mDelays[0][0] = x1; 179 mDelays[0][1] = x2; 180 mDelays[0][2] = y1; 181 mDelays[0][3] = y2; 182 } 183 184 void AudioBiquadFilter::process_transition_normal_mono(const audio_sample_t * in, 185 audio_sample_t * out, 186 int frameCount) { 187 if (updateCoefs(mTargetCoefs, frameCount)) { 188 setState(STATE_NORMAL); 189 } 190 process_normal_mono(in, out, frameCount); 191 } 192 193 void AudioBiquadFilter::process_transition_bypass_mono(const audio_sample_t * in, 194 audio_sample_t * out, 195 int frameCount) { 196 if (updateCoefs(IDENTITY_COEFS, frameCount)) { 197 setState(STATE_NORMAL); 198 } 199 process_normal_mono(in, out, frameCount); 200 } 201 202 void AudioBiquadFilter::process_normal_multi(const audio_sample_t * in, 203 audio_sample_t * out, 204 int frameCount) { 205 const audio_coef_t b0 = mCoefs[0]; 206 const audio_coef_t b1 = mCoefs[1]; 207 const audio_coef_t b2 = mCoefs[2]; 208 const audio_coef_t a1 = mCoefs[3]; 209 const audio_coef_t a2 = mCoefs[4]; 210 for (int ch = 0; ch < mNumChannels; ++ch) { 211 size_t nFrames = frameCount; 212 audio_sample_t x1 = mDelays[ch][0]; 213 audio_sample_t x2 = mDelays[ch][1]; 214 audio_sample_t y1 = mDelays[ch][2]; 215 audio_sample_t y2 = mDelays[ch][3]; 216 while (nFrames-- > 0) { 217 audio_sample_t x0 = *in; 218 audio_coef_sample_acc_t acc; 219 acc = mul_coef_sample(b0, x0); 220 acc = mac_coef_sample(b1, x1, acc); 221 acc = mac_coef_sample(b2, x2, acc); 222 acc = mac_coef_sample(a1, y1, acc); 223 acc = mac_coef_sample(a2, y2, acc); 224 audio_sample_t y0 = coef_sample_acc_to_sample(acc); 225 y2 = y1; 226 y1 = y0; 227 x2 = x1; 228 x1 = x0; 229 *out = y0; 230 in += mNumChannels; 231 out += mNumChannels; 232 } 233 mDelays[ch][0] = x1; 234 mDelays[ch][1] = x2; 235 mDelays[ch][2] = y1; 236 mDelays[ch][3] = y2; 237 in -= frameCount * mNumChannels - 1; 238 out -= frameCount * mNumChannels - 1; 239 } 240 } 241 242 void AudioBiquadFilter::process_transition_normal_multi(const audio_sample_t * in, 243 audio_sample_t * out, 244 int frameCount) { 245 if (updateCoefs(mTargetCoefs, frameCount)) { 246 setState(STATE_NORMAL); 247 } 248 process_normal_multi(in, out, frameCount); 249 } 250 251 void AudioBiquadFilter::process_transition_bypass_multi(const audio_sample_t * in, 252 audio_sample_t * out, 253 int frameCount) { 254 if (updateCoefs(IDENTITY_COEFS, frameCount)) { 255 setState(STATE_NORMAL); 256 } 257 process_normal_multi(in, out, frameCount); 258 } 259 260 } 261