186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung/*
286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * Copyright (C) 2013 The Android Open Source Project
386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * Licensed under the Apache License, Version 2.0 (the "License");
586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * you may not use this file except in compliance with the License.
686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * You may obtain a copy of the License at
786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *      http://www.apache.org/licenses/LICENSE-2.0
986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
1086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * Unless required by applicable law or agreed to in writing, software
1186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * distributed under the License is distributed on an "AS IS" BASIS,
1286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * See the License for the specific language governing permissions and
1486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * limitations under the License.
1586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung */
1686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
1786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#define LOG_TAG "AudioResamplerDyn"
1886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung//#define LOG_NDEBUG 0
1986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
2086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <malloc.h>
2186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <string.h>
2286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <stdlib.h>
2386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <dlfcn.h>
2486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <math.h>
2586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
2686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <cutils/compiler.h>
2786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <cutils/properties.h>
28d549139155b20d7cbf6a4326133e06def465ef54Andy Hung#include <utils/Debug.h>
2986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include <utils/Log.h>
305e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung#include <audio_utils/primitives.h>
3186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
3286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerFirOps.h" // USE_NEON and USE_INLINE_ASSEMBLY defined here
3386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerFirProcess.h"
3486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerFirProcessNeon.h"
3586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerFirGen.h" // requires math.h
3686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerDyn.h"
3786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
3886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung//#define DEBUG_RESAMPLER
3986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
4086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungnamespace android {
4186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
4286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung/*
4386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * InBuffer is a type agnostic input buffer.
4486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
4586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * Layout of the state buffer for halfNumCoefs=8.
4686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
4786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * [rrrrrrppppppppnnnnnnnnrrrrrrrrrrrrrrrrrrr.... rrrrrrr]
4886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *  S            I                                R
4986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
5086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * S = mState
5186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * I = mImpulse
5286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * R = mRingFull
5386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * p = past samples, convoluted with the (p)ositive side of sinc()
5486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * n = future samples, convoluted with the (n)egative side of sinc()
5586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * r = extra space for implementing the ring buffer
5686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung */
5786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
58771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
59771386e6e6e79697e2d839ef0f25a242946ba1e5Andy HungAudioResamplerDyn<TC, TI, TO>::InBuffer::InBuffer()
60771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateCount(0)
61771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
6286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
6386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
64771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
65771386e6e6e79697e2d839ef0f25a242946ba1e5Andy HungAudioResamplerDyn<TC, TI, TO>::InBuffer::~InBuffer()
66771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
6786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    init();
6886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
6986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
70771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
71771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::init()
72771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
7386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    free(mState);
7486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mState = NULL;
7586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mImpulse = NULL;
7686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mRingFull = NULL;
77771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mStateCount = 0;
7886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
7986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
8086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// resizes the state buffer to accommodate the appropriate filter length
81771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
82771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::resize(int CHANNELS, int halfNumCoefs)
83771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
8486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // calculate desired state size
85a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten    size_t stateCount = halfNumCoefs * CHANNELS * 2 * kStateSizeMultipleOfFilterLength;
8686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
8786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // check if buffer needs resizing
8886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mState
89771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung            && stateCount == mStateCount
90a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten            && mRingFull-mState == (ssize_t) (mStateCount-halfNumCoefs*CHANNELS)) {
9186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        return;
9286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
9386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
9486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // create new buffer
95a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten    TI* state = NULL;
96771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state));
97771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    memset(state, 0, stateCount*sizeof(*state));
9886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
9986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // attempt to preserve state
10086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mState) {
10186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        TI* srcLo = mImpulse - halfNumCoefs*CHANNELS;
10286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        TI* srcHi = mImpulse + halfNumCoefs*CHANNELS;
10386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        TI* dst = state;
10486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
10586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        if (srcLo < mState) {
10686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            dst += mState-srcLo;
10786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            srcLo = mState;
10886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
109771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        if (srcHi > mState + mStateCount) {
110771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung            srcHi = mState + mStateCount;
11186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
11286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        memcpy(dst, srcLo, (srcHi - srcLo) * sizeof(*srcLo));
11386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        free(mState);
11486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
11586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
11686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // set class member vars
11786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mState = state;
118771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mStateCount = stateCount;
119771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mImpulse = state + halfNumCoefs*CHANNELS; // actually one sample greater than needed
120771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mRingFull = state + mStateCount - halfNumCoefs*CHANNELS;
12186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
12286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
12386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// copy in the input data into the head (impulse+halfNumCoefs) of the buffer.
124771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
12586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungtemplate<int CHANNELS>
126771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::readAgain(TI*& impulse, const int halfNumCoefs,
127771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TI* const in, const size_t inputIndex)
128771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
129771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    TI* head = impulse + halfNumCoefs*CHANNELS;
13086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    for (size_t i=0 ; i<CHANNELS ; i++) {
13186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        head[i] = in[inputIndex*CHANNELS + i];
13286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
13386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
13486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
13586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// advance the impulse pointer, and load in data into the head (impulse+halfNumCoefs)
136771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
13786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungtemplate<int CHANNELS>
138771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::readAdvance(TI*& impulse, const int halfNumCoefs,
139771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TI* const in, const size_t inputIndex)
140771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
14186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    impulse += CHANNELS;
14286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
14386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (CC_UNLIKELY(impulse >= mRingFull)) {
14486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const size_t shiftDown = mRingFull - mState - halfNumCoefs*CHANNELS;
14586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        memcpy(mState, mState+shiftDown, halfNumCoefs*CHANNELS*2*sizeof(TI));
14686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        impulse -= shiftDown;
14786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
14886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
14986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
15086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
151771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
152771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::Constants::set(
15386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int L, int halfNumCoefs, int inSampleRate, int outSampleRate)
15486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
15586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int bits = 0;
15686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int lscale = inSampleRate/outSampleRate < 2 ? L - 1 :
15786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            static_cast<int>(static_cast<uint64_t>(L)*inSampleRate/outSampleRate);
15886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    for (int i=lscale; i; ++bits, i>>=1)
15986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        ;
16086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mL = L;
16186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mShift = kNumPhaseBits - bits;
16286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mHalfNumCoefs = halfNumCoefs;
16386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
16486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
165771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
1663348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResamplerDyn<TC, TI, TO>::AudioResamplerDyn(
16786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int inChannelCount, int32_t sampleRate, src_quality quality)
1683348e36c51e91e78020bcc6578eda83d97c31becAndy Hung    : AudioResampler(inChannelCount, sampleRate, quality),
169771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung      mResampleFunc(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
1706582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    mCoefBuffer(NULL)
17186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
17286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mVolumeSimd[0] = mVolumeSimd[1] = 0;
1731af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    // The AudioResampler base class assumes we are always ready for 1:1 resampling.
1741af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    // We reset mInSampleRate to 0, so setSampleRate() will calculate filters for
1751af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    // setSampleRate() for 1:1. (May be removed if precalculated filters are used.)
1761af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    mInSampleRate = 0;
17786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
17886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
17986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
180771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
181771386e6e6e79697e2d839ef0f25a242946ba1e5Andy HungAudioResamplerDyn<TC, TI, TO>::~AudioResamplerDyn()
182771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
18386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    free(mCoefBuffer);
18486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
18586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
186771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
187771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::init()
188771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
18986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mFilterSampleRate = 0; // always trigger new filter generation
19086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInBuffer.init();
19186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
19286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
193771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
1945e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::setVolume(float left, float right)
195771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
19686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    AudioResampler::setVolume(left, right);
197771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    if (is_same<TO, float>::value || is_same<TO, double>::value) {
1985e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[0] = static_cast<TO>(left);
1995e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[1] = static_cast<TO>(right);
2005e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    } else {  // integer requires scaling to U4_28 (rounding down)
2015e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        // integer volumes are clamped to 0 to UNITY_GAIN so there
2025e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        // are no issues with signed overflow.
2035e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[0] = u4_28_from_float(clampFloatVol(left));
2045e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[1] = u4_28_from_float(clampFloatVol(right));
205771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    }
20686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
20786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
208771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename T> T max(T a, T b) {return a > b ? a : b;}
20986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
210771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
21186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
212771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
213771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
214771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat)
215771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
216a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten    TC* buf = NULL;
21786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    static const double atten = 0.9998;   // to avoid ripple overflow
21886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double fcr;
21986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
22086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
221771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC));
22286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (inSampleRate < outSampleRate) { // upsample
22386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
22486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    } else { // downsample
22586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        fcr = max(0.5*tbwCheat*outSampleRate/inSampleRate - tbw/2, tbw/2);
22686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
22786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // create and set filter
22886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
229771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    c.mFirCoefs = buf;
23086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mCoefBuffer) {
23186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        free(mCoefBuffer);
23286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
23386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mCoefBuffer = buf;
23486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#ifdef DEBUG_RESAMPLER
23586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // print basic filter stats
23686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    printf("L:%d  hnc:%d  stopBandAtten:%lf  fcr:%lf  atten:%lf  tbw:%lf\n",
23786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten, tbw);
23886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // test the filter and report results
23986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double fp = (fcr - tbw/2)/c.mL;
24086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double fs = (fcr + tbw/2)/c.mL;
2416582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    double passMin, passMax, passRipple;
2426582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    double stopMax, stopRipple;
2436582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    testFir(buf, c.mL, c.mHalfNumCoefs, fp, fs, /*passSteps*/ 1000, /*stopSteps*/ 100000,
2446582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            passMin, passMax, passRipple, stopMax, stopRipple);
2456582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    printf("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
2466582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    printf("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
24786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#endif
24886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
24986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
2506582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung// recursive gcd. Using objdump, it appears the tail recursion is converted to a while loop.
251771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungstatic int gcd(int n, int m)
252771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
25386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (m == 0) {
25486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        return n;
25586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
25686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    return gcd(m, n % m);
25786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
25886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
2596582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hungstatic bool isClose(int32_t newSampleRate, int32_t prevSampleRate,
260771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        int32_t filterSampleRate, int32_t outSampleRate)
261771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
2626582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung
2636582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    // different upsampling ratios do not need a filter change.
2646582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    if (filterSampleRate != 0
2656582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            && filterSampleRate < outSampleRate
2666582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            && newSampleRate < outSampleRate)
2676582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        return true;
2686582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung
2696582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    // check design criteria again if downsampling is detected.
27086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int pdiff = absdiff(newSampleRate, prevSampleRate);
27186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int adiff = absdiff(newSampleRate, filterSampleRate);
27286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
27386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // allow up to 6% relative change increments.
27486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // allow up to 12% absolute change increments (from filter design)
27586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    return pdiff < prevSampleRate>>4 && adiff < filterSampleRate>>3;
27686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
27786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
278771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
279771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate)
280771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
28186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mInSampleRate == inSampleRate) {
28286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        return;
28386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
28486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int32_t oldSampleRate = mInSampleRate;
28586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    uint32_t oldPhaseWrapLimit = mConstants.mL << mConstants.mShift;
28686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    bool useS32 = false;
28786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
28886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInSampleRate = inSampleRate;
28986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
29086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // TODO: Add precalculated Equiripple filters
29186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
2926582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    if (mFilterQuality != getQuality() ||
2936582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            !isClose(inSampleRate, oldSampleRate, mFilterSampleRate, mSampleRate)) {
29486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        mFilterSampleRate = inSampleRate;
2956582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        mFilterQuality = getQuality();
29686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
29786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // Begin Kaiser Filter computation
29886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
29986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // The quantization floor for S16 is about 96db - 10*log_10(#length) + 3dB.
30086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // Keep the stop band attenuation no greater than 84-85dB for 32 length S16 filters
30186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
30286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // For s32 we keep the stop band attenuation at the same as 16b resolution, about
30386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // 96-98dB
30486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
30586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
30686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        double stopBandAtten;
30786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        double tbwCheat = 1.; // how much we "cheat" into aliasing
30886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int halfLength;
3096582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        if (mFilterQuality == DYN_HIGH_QUALITY) {
31086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // 32b coefficients, 64 length
31186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            useS32 = true;
31286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stopBandAtten = 98.;
313a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate >= mSampleRate * 4) {
314a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 48;
315a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else if (inSampleRate >= mSampleRate * 2) {
316a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 40;
317a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else {
318a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 32;
319a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            }
3206582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        } else if (mFilterQuality == DYN_LOW_QUALITY) {
32186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // 16b coefficients, 16-32 length
32286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            useS32 = false;
32386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stopBandAtten = 80.;
324a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate >= mSampleRate * 4) {
325a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 24;
326a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else if (inSampleRate >= mSampleRate * 2) {
32786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 16;
32886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
32986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 8;
33086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
331a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate <= mSampleRate) {
33286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.05;
33386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
33486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.03;
33586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
3366582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        } else { // DYN_MED_QUALITY
33786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // 16b coefficients, 32-64 length
3386582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            // note: > 64 length filters with 16b coefs can have quantization noise problems
33986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            useS32 = false;
34086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stopBandAtten = 84.;
341a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate >= mSampleRate * 4) {
34286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 32;
343a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else if (inSampleRate >= mSampleRate * 2) {
34486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 24;
34586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
34686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 16;
34786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
348a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate <= mSampleRate) {
34986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.03;
35086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
35186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.01;
35286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
35386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
35486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
35586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // determine the number of polyphases in the filterbank.
35686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // for 16b, it is desirable to have 2^(16/2) = 256 phases.
35786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // https://ccrma.stanford.edu/~jos/resample/Relation_Interpolation_Error_Quantization.html
35886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
35986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // We are a bit more lax on this.
36086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
36186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int phases = mSampleRate / gcd(mSampleRate, inSampleRate);
36286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
3636582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // TODO: Once dynamic sample rate change is an option, the code below
3646582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // should be modified to execute only when dynamic sample rate change is enabled.
3656582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        //
3666582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // as above, #phases less than 63 is too few phases for accurate linear interpolation.
3676582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // we increase the phases to compensate, but more phases means more memory per
3686582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // filter and more time to compute the filter.
3696582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        //
3706582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // if we know that the filter will be used for dynamic sample rate changes,
3716582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // that would allow us skip this part for fixed sample rate resamplers.
3726582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        //
3736582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        while (phases<63) {
37486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            phases *= 2; // this code only needed to support dynamic rate changes
37586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
3766582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung
37786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        if (phases>=256) {  // too many phases, always interpolate
37886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            phases = 127;
37986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
38086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
38186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // create the filter
38286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
383771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        createKaiserFir(mConstants, stopBandAtten,
384771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                inSampleRate, mSampleRate, tbwCheat);
38586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    } // End Kaiser filter
38686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
38786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // update phase and state based on the new filter.
38886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const Constants& c(mConstants);
38986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInBuffer.resize(mChannelCount, c.mHalfNumCoefs);
39086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const uint32_t phaseWrapLimit = c.mL << c.mShift;
39186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // try to preserve as much of the phase fraction as possible for on-the-fly changes
39286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mPhaseFraction = static_cast<unsigned long long>(mPhaseFraction)
39386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            * phaseWrapLimit / oldPhaseWrapLimit;
39486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mPhaseFraction %= phaseWrapLimit; // should not do anything, but just in case.
395cd04484f4837b8ca0041d118286ab6a98e84fc75Andy Hung    mPhaseIncrement = static_cast<uint32_t>(static_cast<uint64_t>(phaseWrapLimit)
39686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            * inSampleRate / mSampleRate);
39786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
39886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // determine which resampler to use
39986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // check if locked phase (works only if mPhaseIncrement has no "fractional phase bits")
40086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int locked = (mPhaseIncrement << (sizeof(mPhaseIncrement)*8 - c.mShift)) == 0;
40186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (locked) {
40286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
40386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
40483be2560d9396b3bd32919123bd67a783e6aaf7cAndy Hung
405075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // stride is the minimum number of filter coefficients processed per loop iteration.
406075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // We currently only allow a stride of 16 to match with SIMD processing.
407075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // This means that the filter length must be a multiple of 16,
408075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // or half the filter length (mHalfNumCoefs) must be a multiple of 8.
409075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    //
410075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // Note: A stride of 2 is achieved with non-SIMD processing.
411075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    int stride = ((c.mHalfNumCoefs & 7) == 0) ? 16 : 2;
412075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    LOG_ALWAYS_FATAL_IF(stride < 16, "Resampler stride must be 16 or more");
4135e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL_IF(mChannelCount < 1 || mChannelCount > 8,
414075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            "Resampler channels(%d) must be between 1 to 8", mChannelCount);
415075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // stride 16 (falls back to stride 2 for machines that do not support NEON)
416075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    if (locked) {
417075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        switch (mChannelCount) {
418075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 1:
419075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
420075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
421075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 2:
422075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
423075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
424075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 3:
425075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, true, 16>;
426075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
427075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 4:
428075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, true, 16>;
429075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
430075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 5:
431075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, true, 16>;
432075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
433075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 6:
434075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, true, 16>;
435075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
436075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 7:
437075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, true, 16>;
438075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
439075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 8:
440075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, true, 16>;
441075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
442075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        }
443075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    } else {
444075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        switch (mChannelCount) {
445075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 1:
446075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
447075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
448075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 2:
449075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
450075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
451075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 3:
452075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, false, 16>;
453075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
454075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 4:
455075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, false, 16>;
456075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
457075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 5:
458075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, false, 16>;
459075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
460075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 6:
461075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, false, 16>;
462075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
463075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 7:
464075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, false, 16>;
465075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
466075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 8:
467075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, false, 16>;
468075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
469075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        }
470075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    }
47186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#ifdef DEBUG_RESAMPLER
47286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
47386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            mChannelCount, locked ? "locked" : "interpolated",
47486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stride, useS32 ? "S32" : "S16", 2*c.mHalfNumCoefs, c.mShift);
47586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#endif
47686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
47786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
478771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
4796b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount,
48086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            AudioBufferProvider* provider)
48186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
4826b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung    return (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider);
483771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung}
48486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
485771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
486771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<int CHANNELS, bool LOCKED, int STRIDE>
4876b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
488771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        AudioBufferProvider* provider)
48986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
490075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // TODO Mono -> Mono is not supported. OUTPUT_CHANNELS reflects minimum of stereo out.
491075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    const int OUTPUT_CHANNELS = (CHANNELS < 2) ? 2 : CHANNELS;
49286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const Constants& c(mConstants);
493771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    const TC* const coefs = mConstants.mFirCoefs;
494771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    TI* impulse = mInBuffer.getImpulse();
495411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung    size_t inputIndex = 0;
49686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    uint32_t phaseFraction = mPhaseFraction;
49786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const uint32_t phaseIncrement = mPhaseIncrement;
49886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    size_t outputIndex = 0;
499075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    size_t outputSampleCount = outFrameCount * OUTPUT_CHANNELS;
50086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const uint32_t phaseWrapLimit = c.mL << c.mShift;
501717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    size_t inFrameCount = (phaseIncrement * (uint64_t)outFrameCount + phaseFraction)
502717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            / phaseWrapLimit;
503717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // sanity check that inFrameCount is in signed 32 bit integer range.
504717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    ALOG_ASSERT(0 <= inFrameCount && inFrameCount < (1U << 31));
505717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung
506717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    //ALOGV("inFrameCount:%d  outFrameCount:%d"
507717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    //        "  phaseIncrement:%u  phaseFraction:%u  phaseWrapLimit:%u",
508717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    //        inFrameCount, outFrameCount, phaseIncrement, phaseFraction, phaseWrapLimit);
50986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
51086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // NOTE: be very careful when modifying the code here. register
51186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // pressure is very high and a small change might cause the compiler
51286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // to generate far less efficient code.
51386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // Always sanity check the result with objdump or test-resample.
51486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
51586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // the following logic is a bit convoluted to keep the main processing loop
51686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // as tight as possible with register allocation.
51786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    while (outputIndex < outputSampleCount) {
518717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        //ALOGV("LOOP: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
519717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        //        "  phaseFraction:%u  phaseWrapLimit:%u",
520717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
521717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung
522717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // check inputIndex overflow
523717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        ALOG_ASSERT(inputIndex <= mBuffer.frameCount, "inputIndex%d > frameCount%d",
524717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                inputIndex, mBuffer.frameCount);
525717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // Buffer is empty, fetch a new one if necessary (inFrameCount > 0).
526717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // We may not fetch a new buffer if the existing data is sufficient.
527717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        while (mBuffer.frameCount == 0 && inFrameCount > 0) {
52886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            mBuffer.frameCount = inFrameCount;
529d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten            provider->getNextBuffer(&mBuffer);
53086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            if (mBuffer.raw == NULL) {
53186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                goto resample_exit;
53286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
533411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung            inFrameCount -= mBuffer.frameCount;
53486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            if (phaseFraction >= phaseWrapLimit) { // read in data
535771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                mInBuffer.template readAdvance<CHANNELS>(
536771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                        impulse, c.mHalfNumCoefs,
537771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                        reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
538717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                inputIndex++;
53986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                phaseFraction -= phaseWrapLimit;
54086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                while (phaseFraction >= phaseWrapLimit) {
54186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    if (inputIndex >= mBuffer.frameCount) {
542411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung                        inputIndex = 0;
54386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                        provider->releaseBuffer(&mBuffer);
54486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                        break;
54586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    }
546771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                    mInBuffer.template readAdvance<CHANNELS>(
547771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                            impulse, c.mHalfNumCoefs,
548771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                            reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
549717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                    inputIndex++;
55086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    phaseFraction -= phaseWrapLimit;
55186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                }
55286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
55386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
554771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TI* const in = reinterpret_cast<const TI*>(mBuffer.raw);
55586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const size_t frameCount = mBuffer.frameCount;
55686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const int coefShift = c.mShift;
55786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const int halfNumCoefs = c.mHalfNumCoefs;
558771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TO* const volumeSimd = mVolumeSimd;
55986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
56086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // main processing loop
56186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        while (CC_LIKELY(outputIndex < outputSampleCount)) {
56286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // caution: fir() is inlined and may be large.
56386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // output will be loaded with the appropriate values
56486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            //
56586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // from the input samples in impulse[-halfNumCoefs+1]... impulse[halfNumCoefs]
56686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // from the polyphase filter of (phaseFraction / phaseWrapLimit) in coefs.
56786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            //
568717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            //ALOGV("LOOP2: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
569717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            //        "  phaseFraction:%u  phaseWrapLimit:%u",
570717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
571717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            ALOG_ASSERT(phaseFraction < phaseWrapLimit);
57286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            fir<CHANNELS, LOCKED, STRIDE>(
57386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    &out[outputIndex],
57486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    phaseFraction, phaseWrapLimit,
57586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    coefShift, halfNumCoefs, coefs,
57686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    impulse, volumeSimd);
577075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung
578075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            outputIndex += OUTPUT_CHANNELS;
57986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
58086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            phaseFraction += phaseIncrement;
58186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            while (phaseFraction >= phaseWrapLimit) {
58286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                if (inputIndex >= frameCount) {
58386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    goto done;  // need a new buffer
58486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                }
585771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                mInBuffer.template readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
586717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                inputIndex++;
58786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                phaseFraction -= phaseWrapLimit;
58886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
58986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
59086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungdone:
591717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // We arrive here when we're finished or when the input buffer runs out.
592717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // Regardless we need to release the input buffer if we've acquired it.
593717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        if (inputIndex > 0) {  // we've acquired a buffer (alternatively could check frameCount)
594717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            ALOG_ASSERT(inputIndex == frameCount, "inputIndex(%d) != frameCount(%d)",
595717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                    inputIndex, frameCount);  // must have been fully read.
596411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung            inputIndex = 0;
59786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            provider->releaseBuffer(&mBuffer);
598411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung            ALOG_ASSERT(mBuffer.frameCount == 0);
59986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
60086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
60186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
60286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungresample_exit:
603717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // inputIndex must be zero in all three cases:
604717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // (1) the buffer never was been acquired; (2) the buffer was
605717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // released at "done:"; or (3) getNextBuffer() failed.
606717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    ALOG_ASSERT(inputIndex == 0, "Releasing: inputindex:%d frameCount:%d  phaseFraction:%u",
607717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            inputIndex, mBuffer.frameCount, phaseFraction);
608717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    ALOG_ASSERT(mBuffer.frameCount == 0); // there must be no frames in the buffer
60986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInBuffer.setImpulse(impulse);
61086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mPhaseFraction = phaseFraction;
6116b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung    return outputIndex / OUTPUT_CHANNELS;
61286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
61386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
614771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung/* instantiate templates used by AudioResampler::create */
615771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate class AudioResamplerDyn<float, float, float>;
616771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate class AudioResamplerDyn<int16_t, int16_t, int32_t>;
617771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate class AudioResamplerDyn<int32_t, int16_t, int32_t>;
618771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung
61986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// ----------------------------------------------------------------------------
62063238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android
621