1135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent/* //device/servers/AudioFlinger/AudioBiquadFilter.cpp
2135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent**
3135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** Copyright 2009, The Android Open Source Project
4135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent**
5135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** Licensed under the Apache License, Version 2.0 (the "License");
6135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** you may not use this file except in compliance with the License.
7135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** You may obtain a copy of the License at
8135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent**
9135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent**     http://www.apache.org/licenses/LICENSE-2.0
10135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent**
11135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** Unless required by applicable law or agreed to in writing, software
12135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** distributed under the License is distributed on an "AS IS" BASIS,
13135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** See the License for the specific language governing permissions and
15135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent** limitations under the License.
16135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent*/
17135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
18135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent#include <string.h>
19135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent#include <assert.h>
20f6b1678f8f508b447155a81b44e214475ab634a8Glenn Kasten#include <cutils/compiler.h>
21135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
22135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent#include "AudioBiquadFilter.h"
23135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
24135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentnamespace android {
25135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
26135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentconst audio_coef_t AudioBiquadFilter::IDENTITY_COEFS[AudioBiquadFilter::NUM_COEFS] = { AUDIO_COEF_ONE, 0, 0, 0, 0 };
27135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
28135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric LaurentAudioBiquadFilter::AudioBiquadFilter(int nChannels, int sampleRate) {
29135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    configure(nChannels, sampleRate);
30135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    reset();
31135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
32135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
33135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::configure(int nChannels, int sampleRate) {
34135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    assert(nChannels > 0 && nChannels <= MAX_CHANNELS);
35135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    assert(sampleRate > 0);
36135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mNumChannels  = nChannels;
37135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mMaxDelta = static_cast<int64_t>(MAX_DELTA_PER_SEC)
38135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                * AUDIO_COEF_ONE
39135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                / sampleRate;
40135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    clear();
41135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
42135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
43135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::reset() {
44135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
45135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mCoefDirtyBits = 0;
46135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    setState(STATE_BYPASS);
47135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
48135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
49135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::clear() {
50135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    memset(mDelays, 0, sizeof(mDelays));
51135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
52135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
53135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate) {
54135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    memcpy(mTargetCoefs, coefs, sizeof(mTargetCoefs));
55135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    if (mState & STATE_ENABLED_MASK) {
56f6b1678f8f508b447155a81b44e214475ab634a8Glenn Kasten        if (CC_UNLIKELY(immediate)) {
57135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            memcpy(mCoefs, coefs, sizeof(mCoefs));
58135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            setState(STATE_NORMAL);
59135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        } else {
60135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            setState(STATE_TRANSITION_TO_NORMAL);
61135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        }
62135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
63135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
64135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
65135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process(const audio_sample_t in[], audio_sample_t out[],
66135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                int frameCount) {
67135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    (this->*mCurProcessFunc)(in, out, frameCount);
68135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
69135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
70135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::enable(bool immediate) {
71f6b1678f8f508b447155a81b44e214475ab634a8Glenn Kasten    if (CC_UNLIKELY(immediate)) {
72135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        memcpy(mCoefs, mTargetCoefs, sizeof(mCoefs));
73135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        setState(STATE_NORMAL);
74135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    } else {
75135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        setState(STATE_TRANSITION_TO_NORMAL);
76135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
77135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
78135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
79135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::disable(bool immediate) {
80f6b1678f8f508b447155a81b44e214475ab634a8Glenn Kasten    if (CC_UNLIKELY(immediate)) {
81135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
82135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        setState(STATE_BYPASS);
83135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    } else {
84135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        setState(STATE_TRANSITION_TO_BYPASS);
85135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
86135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
87135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
88135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::setState(state_t state) {
89135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    switch (state) {
90135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    case STATE_BYPASS:
91135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      mCurProcessFunc = &AudioBiquadFilter::process_bypass;
92135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      break;
93135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    case STATE_TRANSITION_TO_BYPASS:
94135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      if (mNumChannels == 1) {
95135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_mono;
96135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      } else {
97135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_multi;
98135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      }
99135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      mCoefDirtyBits = (1 << NUM_COEFS) - 1;
100135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      break;
101135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    case STATE_TRANSITION_TO_NORMAL:
102135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      if (mNumChannels == 1) {
103135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_mono;
104135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      } else {
105135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_multi;
106135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      }
107135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      mCoefDirtyBits = (1 << NUM_COEFS) - 1;
108135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      break;
109135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    case STATE_NORMAL:
110135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      if (mNumChannels == 1) {
111135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mCurProcessFunc = &AudioBiquadFilter::process_normal_mono;
112135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      } else {
113135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mCurProcessFunc = &AudioBiquadFilter::process_normal_multi;
114135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      }
115135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      break;
116135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
117135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mState = state;
118135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
119135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
120135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentbool AudioBiquadFilter::updateCoefs(const audio_coef_t coefs[NUM_COEFS],
121135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                    int frameCount) {
122135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    int64_t maxDelta = mMaxDelta * frameCount;
123135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    for (int i = 0; i < NUM_COEFS; ++i) {
124135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        if (mCoefDirtyBits & (1<<i)) {
125135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            audio_coef_t diff = coefs[i] - mCoefs[i];
126135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            if (diff > maxDelta) {
127135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                mCoefs[i] += maxDelta;
128135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            } else if (diff < -maxDelta) {
129135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                mCoefs[i] -= maxDelta;
130135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            } else {
131135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                mCoefs[i] = coefs[i];
132135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                mCoefDirtyBits ^= (1<<i);
133135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            }
134135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        }
135135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
136135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    return mCoefDirtyBits == 0;
137135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
138135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
139135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process_bypass(const audio_sample_t * in,
140135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                       audio_sample_t * out,
141135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                       int frameCount) {
142135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    // The common case is in-place processing, because this is what the EQ does.
143f6b1678f8f508b447155a81b44e214475ab634a8Glenn Kasten    if (CC_UNLIKELY(in != out)) {
144135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        memcpy(out, in, frameCount * mNumChannels * sizeof(audio_sample_t));
145135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
146135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
147135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
148135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process_normal_mono(const audio_sample_t * in,
149135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                            audio_sample_t * out,
150135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                            int frameCount) {
151135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    size_t nFrames = frameCount;
152135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    audio_sample_t x1 = mDelays[0][0];
153135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    audio_sample_t x2 = mDelays[0][1];
154135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    audio_sample_t y1 = mDelays[0][2];
155135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    audio_sample_t y2 = mDelays[0][3];
156135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t b0 = mCoefs[0];
157135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t b1 = mCoefs[1];
158135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t b2 = mCoefs[2];
159135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t a1 = mCoefs[3];
160135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t a2 = mCoefs[4];
161135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    while (nFrames-- > 0) {
162135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        audio_sample_t x0 = *(in++);
163135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        audio_coef_sample_acc_t acc;
164135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        acc = mul_coef_sample(b0, x0);
165135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        acc = mac_coef_sample(b1, x1, acc);
166135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        acc = mac_coef_sample(b2, x2, acc);
167135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        acc = mac_coef_sample(a1, y1, acc);
168135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        acc = mac_coef_sample(a2, y2, acc);
169135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        audio_sample_t y0 = coef_sample_acc_to_sample(acc);
170135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        y2 = y1;
171135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        y1 = y0;
172135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        x2 = x1;
173135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        x1 = x0;
174135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        (*out++) = y0;
175135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
176135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mDelays[0][0] = x1;
177135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mDelays[0][1] = x2;
178135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mDelays[0][2] = y1;
179135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    mDelays[0][3] = y2;
180135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
181135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
182135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process_transition_normal_mono(const audio_sample_t * in,
183135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                       audio_sample_t * out,
184135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                       int frameCount) {
185135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    if (updateCoefs(mTargetCoefs, frameCount)) {
186135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        setState(STATE_NORMAL);
187135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
188135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    process_normal_mono(in, out, frameCount);
189135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
190135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
191135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process_transition_bypass_mono(const audio_sample_t * in,
192135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                       audio_sample_t * out,
193135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                       int frameCount)  {
194135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent  if (updateCoefs(IDENTITY_COEFS, frameCount)) {
195135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent      setState(STATE_NORMAL);
196135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent  }
197135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent  process_normal_mono(in, out, frameCount);
198135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
199135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
200135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process_normal_multi(const audio_sample_t * in,
201135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                             audio_sample_t * out,
202135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                             int frameCount) {
203135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t b0 = mCoefs[0];
204135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t b1 = mCoefs[1];
205135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t b2 = mCoefs[2];
206135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t a1 = mCoefs[3];
207135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    const audio_coef_t a2 = mCoefs[4];
208135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    for (int ch = 0; ch < mNumChannels; ++ch) {
209135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        size_t nFrames = frameCount;
210135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        audio_sample_t x1 = mDelays[ch][0];
211135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        audio_sample_t x2 = mDelays[ch][1];
212135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        audio_sample_t y1 = mDelays[ch][2];
213135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        audio_sample_t y2 = mDelays[ch][3];
214135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        while (nFrames-- > 0) {
215135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            audio_sample_t x0 = *in;
216135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            audio_coef_sample_acc_t acc;
217135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            acc = mul_coef_sample(b0, x0);
218135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            acc = mac_coef_sample(b1, x1, acc);
219135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            acc = mac_coef_sample(b2, x2, acc);
220135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            acc = mac_coef_sample(a1, y1, acc);
221135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            acc = mac_coef_sample(a2, y2, acc);
222135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            audio_sample_t y0 = coef_sample_acc_to_sample(acc);
223135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            y2 = y1;
224135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            y1 = y0;
225135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            x2 = x1;
226135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            x1 = x0;
227135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            *out = y0;
228135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            in += mNumChannels;
229135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent            out += mNumChannels;
230135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        }
231135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mDelays[ch][0] = x1;
232135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mDelays[ch][1] = x2;
233135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mDelays[ch][2] = y1;
234135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        mDelays[ch][3] = y2;
235135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        in -= frameCount * mNumChannels - 1;
236135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        out -= frameCount * mNumChannels - 1;
237135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
238135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
239135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
240135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process_transition_normal_multi(const audio_sample_t * in,
241135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                        audio_sample_t * out,
242135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                        int frameCount) {
243135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    if (updateCoefs(mTargetCoefs, frameCount)) {
244135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        setState(STATE_NORMAL);
245135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
246135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    process_normal_multi(in, out, frameCount);
247135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
248135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
249135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurentvoid AudioBiquadFilter::process_transition_bypass_multi(const audio_sample_t * in,
250135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                        audio_sample_t * out,
251135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent                                                        int frameCount)  {
252135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    if (updateCoefs(IDENTITY_COEFS, frameCount)) {
253135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent        setState(STATE_NORMAL);
254135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    }
255135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent    process_normal_multi(in, out, frameCount);
256135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
257135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent
258135ad07e33d30e5202deb21061a0e3ecf0ffad35Eric Laurent}
259