AudioBiquadFilter.cpp revision 2c8e5cab3faa6d360e222b7a6c40a80083d021ac
15460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao/* //device/servers/AudioFlinger/AudioBiquadFilter.cpp
25460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao**
35460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** Copyright 2009, The Android Open Source Project
45460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao**
55460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** Licensed under the Apache License, Version 2.0 (the "License");
65460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** you may not use this file except in compliance with the License.
75460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** You may obtain a copy of the License at
85460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao**
95460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao**     http://www.apache.org/licenses/LICENSE-2.0
105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao**
115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** Unless required by applicable law or agreed to in writing, software
125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** distributed under the License is distributed on an "AS IS" BASIS,
135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** See the License for the specific language governing permissions and
155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao** limitations under the License.
165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao*/
175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
18f767be5432ccac097334be48698e48621d730190Shih-wei Liao#include <string.h>
195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include <assert.h>
205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#include "AudioBiquadFilter.h"
225460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))
255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaonamespace android {
275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaoconst audio_coef_t AudioBiquadFilter::IDENTITY_COEFS[AudioBiquadFilter::NUM_COEFS] = { AUDIO_COEF_ONE, 0, 0, 0, 0 };
295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
305460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei LiaoAudioBiquadFilter::AudioBiquadFilter(int nChannels, int sampleRate) {
315460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    configure(nChannels, sampleRate);
325460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    reset();
335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
345460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::configure(int nChannels, int sampleRate) {
365460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    assert(nChannels > 0 && nChannels <= MAX_CHANNELS);
375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    assert(sampleRate > 0);
385460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mNumChannels  = nChannels;
395460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mMaxDelta = static_cast<int64_t>(MAX_DELTA_PER_SEC)
405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                * AUDIO_COEF_ONE
415460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                / sampleRate;
425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    clear();
435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::reset() {
465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mCoefDirtyBits = 0;
485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    setState(STATE_BYPASS);
495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::clear() {
525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    memset(mDelays, 0, sizeof(mDelays));
535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::setCoefs(const audio_coef_t coefs[NUM_COEFS], bool immediate) {
565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    memcpy(mTargetCoefs, coefs, sizeof(mTargetCoefs));
575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (mState & STATE_ENABLED_MASK) {
585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        if (UNLIKELY(immediate)) {
595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            memcpy(mCoefs, coefs, sizeof(mCoefs));
605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            setState(STATE_NORMAL);
615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        } else {
625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            setState(STATE_TRANSITION_TO_NORMAL);
635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        }
645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process(const audio_sample_t in[], audio_sample_t out[],
685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                int frameCount) {
695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    (this->*mCurProcessFunc)(in, out, frameCount);
705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::enable(bool immediate) {
735460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (UNLIKELY(immediate)) {
745460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        memcpy(mCoefs, mTargetCoefs, sizeof(mCoefs));
755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        setState(STATE_NORMAL);
765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    } else {
775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        setState(STATE_TRANSITION_TO_NORMAL);
785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::disable(bool immediate) {
825460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (UNLIKELY(immediate)) {
83f767be5432ccac097334be48698e48621d730190Shih-wei Liao        memcpy(mCoefs, IDENTITY_COEFS, sizeof(mCoefs));
845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        setState(STATE_BYPASS);
855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    } else {
865460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        setState(STATE_TRANSITION_TO_BYPASS);
875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
895460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::setState(state_t state) {
915460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    switch (state) {
925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    case STATE_BYPASS:
935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      mCurProcessFunc = &AudioBiquadFilter::process_bypass;
945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      break;
955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    case STATE_TRANSITION_TO_BYPASS:
965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      if (mNumChannels == 1) {
975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_mono;
985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      } else {
995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mCurProcessFunc = &AudioBiquadFilter::process_transition_bypass_multi;
1005460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      }
1015460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      mCoefDirtyBits = (1 << NUM_COEFS) - 1;
1025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      break;
1035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    case STATE_TRANSITION_TO_NORMAL:
1045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      if (mNumChannels == 1) {
1055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_mono;
1065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      } else {
1075460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mCurProcessFunc = &AudioBiquadFilter::process_transition_normal_multi;
108f767be5432ccac097334be48698e48621d730190Shih-wei Liao      }
1095460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      mCoefDirtyBits = (1 << NUM_COEFS) - 1;
1105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      break;
1115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    case STATE_NORMAL:
1125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      if (mNumChannels == 1) {
1135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mCurProcessFunc = &AudioBiquadFilter::process_normal_mono;
1145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      } else {
1155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mCurProcessFunc = &AudioBiquadFilter::process_normal_multi;
1165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      }
1175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      break;
1185460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
1195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mState = state;
1205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1225460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaobool AudioBiquadFilter::updateCoefs(const audio_coef_t coefs[NUM_COEFS],
1235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                    int frameCount) {
1245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    int64_t maxDelta = mMaxDelta * frameCount;
1255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    for (int i = 0; i < NUM_COEFS; ++i) {
1265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        if (mCoefDirtyBits & (1<<i)) {
1275460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            audio_coef_t diff = coefs[i] - mCoefs[i];
1285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            if (diff > maxDelta) {
1295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                mCoefs[i] += maxDelta;
1305460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            } else if (diff < -maxDelta) {
1315460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                mCoefs[i] -= maxDelta;
132f767be5432ccac097334be48698e48621d730190Shih-wei Liao            } else {
1335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                mCoefs[i] = coefs[i];
1345460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                mCoefDirtyBits ^= (1<<i);
1355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            }
1365460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        }
1375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
138f767be5432ccac097334be48698e48621d730190Shih-wei Liao    return mCoefDirtyBits == 0;
13967e37f1be98c926645219cfb47fab9e90d8c725cShih-wei Liao}
1405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1415460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process_bypass(const audio_sample_t * in,
1425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                       audio_sample_t * out,
1435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                       int frameCount) {
1445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    // The common case is in-place processing, because this is what the EQ does.
1455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (UNLIKELY(in != out)) {
1465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        memcpy(out, in, frameCount * mNumChannels * sizeof(audio_sample_t));
1475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
1485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process_normal_mono(const audio_sample_t * in,
1515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                            audio_sample_t * out,
1525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                            int frameCount) {
1535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    size_t nFrames = frameCount;
1545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    audio_sample_t x1 = mDelays[0][0];
1555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    audio_sample_t x2 = mDelays[0][1];
1565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    audio_sample_t y1 = mDelays[0][2];
1575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    audio_sample_t y2 = mDelays[0][3];
1585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t b0 = mCoefs[0];
1595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t b1 = mCoefs[1];
1605460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t b2 = mCoefs[2];
1615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t a1 = mCoefs[3];
1625460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t a2 = mCoefs[4];
1635460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    while (nFrames-- > 0) {
1645460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        audio_sample_t x0 = *(in++);
1655460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        audio_coef_sample_acc_t acc;
1665460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        acc = mul_coef_sample(b0, x0);
1675460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        acc = mac_coef_sample(b1, x1, acc);
1685460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        acc = mac_coef_sample(b2, x2, acc);
1695460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        acc = mac_coef_sample(a1, y1, acc);
1705460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        acc = mac_coef_sample(a2, y2, acc);
1715460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        audio_sample_t y0 = coef_sample_acc_to_sample(acc);
1725460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        y2 = y1;
1735460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        y1 = y0;
1745460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        x2 = x1;
1755460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        x1 = x0;
1765460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        (*out++) = y0;
1775460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
1785460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mDelays[0][0] = x1;
1795460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mDelays[0][1] = x2;
1805460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mDelays[0][2] = y1;
1815460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    mDelays[0][3] = y2;
1825460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1835460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1845460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process_transition_normal_mono(const audio_sample_t * in,
1855460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                       audio_sample_t * out,
1865460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                       int frameCount) {
1875460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (updateCoefs(mTargetCoefs, frameCount)) {
1885460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        setState(STATE_NORMAL);
1895460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
1905460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    process_normal_mono(in, out, frameCount);
1915460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
1925460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
1935460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process_transition_bypass_mono(const audio_sample_t * in,
1945460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                       audio_sample_t * out,
1955460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                       int frameCount)  {
1965460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  if (updateCoefs(IDENTITY_COEFS, frameCount)) {
1975460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao      setState(STATE_NORMAL);
1985460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  }
1995460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao  process_normal_mono(in, out, frameCount);
2005460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2015460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2025460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process_normal_multi(const audio_sample_t * in,
2035460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                             audio_sample_t * out,
2045460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                             int frameCount) {
2055460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t b0 = mCoefs[0];
2065460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t b1 = mCoefs[1];
2075460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t b2 = mCoefs[2];
2085460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t a1 = mCoefs[3];
2095460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    const audio_coef_t a2 = mCoefs[4];
2105460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    for (int ch = 0; ch < mNumChannels; ++ch) {
2115460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        size_t nFrames = frameCount;
2125460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        audio_sample_t x1 = mDelays[ch][0];
2135460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        audio_sample_t x2 = mDelays[ch][1];
2145460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        audio_sample_t y1 = mDelays[ch][2];
2155460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        audio_sample_t y2 = mDelays[ch][3];
2165460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        while (nFrames-- > 0) {
2175460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            audio_sample_t x0 = *in;
218f767be5432ccac097334be48698e48621d730190Shih-wei Liao            audio_coef_sample_acc_t acc;
2195460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            acc = mul_coef_sample(b0, x0);
2205460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            acc = mac_coef_sample(b1, x1, acc);
2215460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            acc = mac_coef_sample(b2, x2, acc);
2225460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            acc = mac_coef_sample(a1, y1, acc);
2235460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            acc = mac_coef_sample(a2, y2, acc);
2245460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            audio_sample_t y0 = coef_sample_acc_to_sample(acc);
2255460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            y2 = y1;
2265460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            y1 = y0;
227f767be5432ccac097334be48698e48621d730190Shih-wei Liao            x2 = x1;
2285460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            x1 = x0;
2295460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            *out = y0;
2305460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            in += mNumChannels;
2315460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao            out += mNumChannels;
2325460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        }
2335460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mDelays[ch][0] = x1;
2345460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mDelays[ch][1] = x2;
2355460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mDelays[ch][2] = y1;
2365460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        mDelays[ch][3] = y2;
2375460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        in -= frameCount * mNumChannels - 1;
2385460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        out -= frameCount * mNumChannels - 1;
2395460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
2405460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2415460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2425460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process_transition_normal_multi(const audio_sample_t * in,
2435460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                        audio_sample_t * out,
2445460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                        int frameCount) {
2455460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (updateCoefs(mTargetCoefs, frameCount)) {
2465460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        setState(STATE_NORMAL);
2475460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
2485460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    process_normal_multi(in, out, frameCount);
2495460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2505460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
2515460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liaovoid AudioBiquadFilter::process_transition_bypass_multi(const audio_sample_t * in,
2525460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                        audio_sample_t * out,
2535460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao                                                        int frameCount)  {
2545460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    if (updateCoefs(IDENTITY_COEFS, frameCount)) {
2555460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao        setState(STATE_NORMAL);
2565460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    }
2575460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao    process_normal_multi(in, out, frameCount);
2585460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao}
2595460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao
260f767be5432ccac097334be48698e48621d730190Shih-wei Liao}
2615460a1f25d9ddecb5c70667267d66d51af177a99Shih-wei Liao