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