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
32841920db8206cc6428ab460e5fa5b7a50edd06d0Henrik Smiding#include "AudioResamplerFirOps.h" // USE_NEON, USE_SSE and USE_INLINE_ASSEMBLY defined here
3386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerFirProcess.h"
3486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerFirProcessNeon.h"
35841920db8206cc6428ab460e5fa5b7a50edd06d0Henrik Smiding#include "AudioResamplerFirProcessSSE.h"
3686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerFirGen.h" // requires math.h
3786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerDyn.h"
3886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
3986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung//#define DEBUG_RESAMPLER
4086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
4186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungnamespace android {
4286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
4386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung/*
4486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * InBuffer is a type agnostic input buffer.
4586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
4686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * Layout of the state buffer for halfNumCoefs=8.
4786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
4886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * [rrrrrrppppppppnnnnnnnnrrrrrrrrrrrrrrrrrrr.... rrrrrrr]
4986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *  S            I                                R
5086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung *
5186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * S = mState
5286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * I = mImpulse
5386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * R = mRingFull
5486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * p = past samples, convoluted with the (p)ositive side of sinc()
5586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * n = future samples, convoluted with the (n)egative side of sinc()
5686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung * r = extra space for implementing the ring buffer
5786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung */
5886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
59771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
60771386e6e6e79697e2d839ef0f25a242946ba1e5Andy HungAudioResamplerDyn<TC, TI, TO>::InBuffer::InBuffer()
61771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateCount(0)
62771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
6386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
6486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
65771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
66771386e6e6e79697e2d839ef0f25a242946ba1e5Andy HungAudioResamplerDyn<TC, TI, TO>::InBuffer::~InBuffer()
67771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
6886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    init();
6986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
7086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
71771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
72771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::init()
73771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
7486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    free(mState);
7586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mState = NULL;
7686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mImpulse = NULL;
7786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mRingFull = NULL;
78771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mStateCount = 0;
7986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
8086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
8186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// resizes the state buffer to accommodate the appropriate filter length
82771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
83771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::resize(int CHANNELS, int halfNumCoefs)
84771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
8586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // calculate desired state size
86a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten    size_t stateCount = halfNumCoefs * CHANNELS * 2 * kStateSizeMultipleOfFilterLength;
8786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
8886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // check if buffer needs resizing
8986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mState
90771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung            && stateCount == mStateCount
91a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten            && mRingFull-mState == (ssize_t) (mStateCount-halfNumCoefs*CHANNELS)) {
9286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        return;
9386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
9486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
9586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // create new buffer
96a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten    TI* state = NULL;
97771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    (void)posix_memalign(reinterpret_cast<void**>(&state), 32, stateCount*sizeof(*state));
98771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    memset(state, 0, stateCount*sizeof(*state));
9986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
10086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // attempt to preserve state
10186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mState) {
10286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        TI* srcLo = mImpulse - halfNumCoefs*CHANNELS;
10386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        TI* srcHi = mImpulse + halfNumCoefs*CHANNELS;
10486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        TI* dst = state;
10586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
10686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        if (srcLo < mState) {
10786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            dst += mState-srcLo;
10886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            srcLo = mState;
10986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
110771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        if (srcHi > mState + mStateCount) {
111771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung            srcHi = mState + mStateCount;
11286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
11386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        memcpy(dst, srcLo, (srcHi - srcLo) * sizeof(*srcLo));
11486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        free(mState);
11586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
11686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
11786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // set class member vars
11886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mState = state;
119771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mStateCount = stateCount;
120771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mImpulse = state + halfNumCoefs*CHANNELS; // actually one sample greater than needed
121771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    mRingFull = state + mStateCount - halfNumCoefs*CHANNELS;
12286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
12386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
12486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// copy in the input data into the head (impulse+halfNumCoefs) of the buffer.
125771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
12686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungtemplate<int CHANNELS>
127771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::readAgain(TI*& impulse, const int halfNumCoefs,
128771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TI* const in, const size_t inputIndex)
129771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
130771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    TI* head = impulse + halfNumCoefs*CHANNELS;
13186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    for (size_t i=0 ; i<CHANNELS ; i++) {
13286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        head[i] = in[inputIndex*CHANNELS + i];
13386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
13486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
13586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
13686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// advance the impulse pointer, and load in data into the head (impulse+halfNumCoefs)
137771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
13886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungtemplate<int CHANNELS>
139771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::readAdvance(TI*& impulse, const int halfNumCoefs,
140771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TI* const in, const size_t inputIndex)
141771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
14286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    impulse += CHANNELS;
14386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
14486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (CC_UNLIKELY(impulse >= mRingFull)) {
14586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const size_t shiftDown = mRingFull - mState - halfNumCoefs*CHANNELS;
14686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        memcpy(mState, mState+shiftDown, halfNumCoefs*CHANNELS*2*sizeof(TI));
14786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        impulse -= shiftDown;
14886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
14986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
15086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
15186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
152771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
153bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huangvoid AudioResamplerDyn<TC, TI, TO>::InBuffer::reset()
154bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang{
155bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang    // clear resampler state
156bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang    if (mState != nullptr) {
157bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang        memset(mState, 0, mStateCount * sizeof(TI));
158bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang    }
159bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang}
160bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang
161bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huangtemplate<typename TC, typename TI, typename TO>
162771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::Constants::set(
16386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int L, int halfNumCoefs, int inSampleRate, int outSampleRate)
16486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
16586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int bits = 0;
16686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int lscale = inSampleRate/outSampleRate < 2 ? L - 1 :
16786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            static_cast<int>(static_cast<uint64_t>(L)*inSampleRate/outSampleRate);
16886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    for (int i=lscale; i; ++bits, i>>=1)
16986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        ;
17086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mL = L;
17186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mShift = kNumPhaseBits - bits;
17286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mHalfNumCoefs = halfNumCoefs;
17386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
17486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
175771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
1763348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResamplerDyn<TC, TI, TO>::AudioResamplerDyn(
17786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int inChannelCount, int32_t sampleRate, src_quality quality)
1783348e36c51e91e78020bcc6578eda83d97c31becAndy Hung    : AudioResampler(inChannelCount, sampleRate, quality),
179771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung      mResampleFunc(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
1806582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    mCoefBuffer(NULL)
18186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
18286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mVolumeSimd[0] = mVolumeSimd[1] = 0;
1831af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    // The AudioResampler base class assumes we are always ready for 1:1 resampling.
1841af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    // We reset mInSampleRate to 0, so setSampleRate() will calculate filters for
1851af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    // setSampleRate() for 1:1. (May be removed if precalculated filters are used.)
1861af34085e18c4d5ab297232f167a71e89ff7f65dAndy Hung    mInSampleRate = 0;
18786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
18886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
18986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
190771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
191771386e6e6e79697e2d839ef0f25a242946ba1e5Andy HungAudioResamplerDyn<TC, TI, TO>::~AudioResamplerDyn()
192771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
19386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    free(mCoefBuffer);
19486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
19586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
196771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
197771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::init()
198771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
19986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mFilterSampleRate = 0; // always trigger new filter generation
20086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInBuffer.init();
20186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
20286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
203771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
2045e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::setVolume(float left, float right)
205771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
20686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    AudioResampler::setVolume(left, right);
207771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    if (is_same<TO, float>::value || is_same<TO, double>::value) {
2085e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[0] = static_cast<TO>(left);
2095e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[1] = static_cast<TO>(right);
2105e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    } else {  // integer requires scaling to U4_28 (rounding down)
2115e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        // integer volumes are clamped to 0 to UNITY_GAIN so there
2125e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        // are no issues with signed overflow.
2135e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[0] = u4_28_from_float(clampFloatVol(left));
2145e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung        mVolumeSimd[1] = u4_28_from_float(clampFloatVol(right));
215771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    }
21686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
21786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
218771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename T> T max(T a, T b) {return a > b ? a : b;}
21986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
220771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
22186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
222771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
223771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::createKaiserFir(Constants &c,
224771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        double stopBandAtten, int inSampleRate, int outSampleRate, double tbwCheat)
225771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
226a4daf0b4f934b800a49f199fb8c09409391c8fc0Glenn Kasten    TC* buf = NULL;
22786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    static const double atten = 0.9998;   // to avoid ripple overflow
22886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double fcr;
22986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
23086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
231771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    (void)posix_memalign(reinterpret_cast<void**>(&buf), 32, (c.mL+1)*c.mHalfNumCoefs*sizeof(TC));
23286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (inSampleRate < outSampleRate) { // upsample
23386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
23486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    } else { // downsample
23586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        fcr = max(0.5*tbwCheat*outSampleRate/inSampleRate - tbw/2, tbw/2);
23686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
23786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // create and set filter
23886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
239771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    c.mFirCoefs = buf;
24086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mCoefBuffer) {
24186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        free(mCoefBuffer);
24286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
24386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mCoefBuffer = buf;
24486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#ifdef DEBUG_RESAMPLER
24586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // print basic filter stats
24686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    printf("L:%d  hnc:%d  stopBandAtten:%lf  fcr:%lf  atten:%lf  tbw:%lf\n",
24786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten, tbw);
24886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // test the filter and report results
24986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double fp = (fcr - tbw/2)/c.mL;
25086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    double fs = (fcr + tbw/2)/c.mL;
2516582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    double passMin, passMax, passRipple;
2526582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    double stopMax, stopRipple;
2536582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    testFir(buf, c.mL, c.mHalfNumCoefs, fp, fs, /*passSteps*/ 1000, /*stopSteps*/ 100000,
2546582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            passMin, passMax, passRipple, stopMax, stopRipple);
2556582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    printf("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
2566582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    printf("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
25786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#endif
25886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
25986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
2606582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung// recursive gcd. Using objdump, it appears the tail recursion is converted to a while loop.
261771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungstatic int gcd(int n, int m)
262771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
26386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (m == 0) {
26486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        return n;
26586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
26686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    return gcd(m, n % m);
26786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
26886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
2696582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hungstatic bool isClose(int32_t newSampleRate, int32_t prevSampleRate,
270771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        int32_t filterSampleRate, int32_t outSampleRate)
271771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
2726582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung
2736582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    // different upsampling ratios do not need a filter change.
2746582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    if (filterSampleRate != 0
2756582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            && filterSampleRate < outSampleRate
2766582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            && newSampleRate < outSampleRate)
2776582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        return true;
2786582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung
2796582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    // check design criteria again if downsampling is detected.
28086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int pdiff = absdiff(newSampleRate, prevSampleRate);
28186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int adiff = absdiff(newSampleRate, filterSampleRate);
28286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
28386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // allow up to 6% relative change increments.
28486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // allow up to 12% absolute change increments (from filter design)
28586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    return pdiff < prevSampleRate>>4 && adiff < filterSampleRate>>3;
28686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
28786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
288771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
289771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungvoid AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate)
290771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung{
29186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (mInSampleRate == inSampleRate) {
29286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        return;
29386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
29486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int32_t oldSampleRate = mInSampleRate;
29586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    uint32_t oldPhaseWrapLimit = mConstants.mL << mConstants.mShift;
29686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    bool useS32 = false;
29786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
29886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInSampleRate = inSampleRate;
29986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
30086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // TODO: Add precalculated Equiripple filters
30186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
3026582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung    if (mFilterQuality != getQuality() ||
3036582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            !isClose(inSampleRate, oldSampleRate, mFilterSampleRate, mSampleRate)) {
30486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        mFilterSampleRate = inSampleRate;
3056582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        mFilterQuality = getQuality();
30686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
30786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // Begin Kaiser Filter computation
30886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
30986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // The quantization floor for S16 is about 96db - 10*log_10(#length) + 3dB.
31086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // Keep the stop band attenuation no greater than 84-85dB for 32 length S16 filters
31186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
31286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // For s32 we keep the stop band attenuation at the same as 16b resolution, about
31386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // 96-98dB
31486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
31586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
31686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        double stopBandAtten;
31786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        double tbwCheat = 1.; // how much we "cheat" into aliasing
31886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int halfLength;
3196582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        if (mFilterQuality == DYN_HIGH_QUALITY) {
32086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // 32b coefficients, 64 length
32186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            useS32 = true;
32286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stopBandAtten = 98.;
323a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate >= mSampleRate * 4) {
324a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 48;
325a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else if (inSampleRate >= mSampleRate * 2) {
326a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 40;
327a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else {
328a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 32;
329a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            }
3306582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        } else if (mFilterQuality == DYN_LOW_QUALITY) {
33186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // 16b coefficients, 16-32 length
33286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            useS32 = false;
33386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stopBandAtten = 80.;
334a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate >= mSampleRate * 4) {
335a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung                halfLength = 24;
336a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else if (inSampleRate >= mSampleRate * 2) {
33786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 16;
33886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
33986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 8;
34086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
341a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate <= mSampleRate) {
34286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.05;
34386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
34486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.03;
34586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
3466582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        } else { // DYN_MED_QUALITY
34786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // 16b coefficients, 32-64 length
3486582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung            // note: > 64 length filters with 16b coefs can have quantization noise problems
34986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            useS32 = false;
35086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stopBandAtten = 84.;
351a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate >= mSampleRate * 4) {
35286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 32;
353a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            } else if (inSampleRate >= mSampleRate * 2) {
35486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 24;
35586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
35686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                halfLength = 16;
35786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
358a3bb9a3a25b58669d75da4f73764ac4c2bf34158Andy Hung            if (inSampleRate <= mSampleRate) {
35986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.03;
36086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            } else {
36186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                tbwCheat = 1.01;
36286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
36386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
36486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
36586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // determine the number of polyphases in the filterbank.
36686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // for 16b, it is desirable to have 2^(16/2) = 256 phases.
36786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // https://ccrma.stanford.edu/~jos/resample/Relation_Interpolation_Error_Quantization.html
36886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        //
36986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // We are a bit more lax on this.
37086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
37186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        int phases = mSampleRate / gcd(mSampleRate, inSampleRate);
37286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
3736582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // TODO: Once dynamic sample rate change is an option, the code below
3746582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // should be modified to execute only when dynamic sample rate change is enabled.
3756582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        //
3766582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // as above, #phases less than 63 is too few phases for accurate linear interpolation.
3776582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // we increase the phases to compensate, but more phases means more memory per
3786582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // filter and more time to compute the filter.
3796582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        //
3806582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // if we know that the filter will be used for dynamic sample rate changes,
3816582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        // that would allow us skip this part for fixed sample rate resamplers.
3826582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        //
3836582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung        while (phases<63) {
38486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            phases *= 2; // this code only needed to support dynamic rate changes
38586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
3866582f2b14a21e630654c5522ef9ad64e80d5058dAndy Hung
38786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        if (phases>=256) {  // too many phases, always interpolate
38886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            phases = 127;
38986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
39086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
39186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // create the filter
39286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
393771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        createKaiserFir(mConstants, stopBandAtten,
394771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                inSampleRate, mSampleRate, tbwCheat);
39586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    } // End Kaiser filter
39686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
39786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // update phase and state based on the new filter.
39886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const Constants& c(mConstants);
39986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInBuffer.resize(mChannelCount, c.mHalfNumCoefs);
40086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const uint32_t phaseWrapLimit = c.mL << c.mShift;
40186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // try to preserve as much of the phase fraction as possible for on-the-fly changes
40286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mPhaseFraction = static_cast<unsigned long long>(mPhaseFraction)
40386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            * phaseWrapLimit / oldPhaseWrapLimit;
40486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mPhaseFraction %= phaseWrapLimit; // should not do anything, but just in case.
405cd04484f4837b8ca0041d118286ab6a98e84fc75Andy Hung    mPhaseIncrement = static_cast<uint32_t>(static_cast<uint64_t>(phaseWrapLimit)
40686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            * inSampleRate / mSampleRate);
40786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
40886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // determine which resampler to use
40986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // check if locked phase (works only if mPhaseIncrement has no "fractional phase bits")
41086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    int locked = (mPhaseIncrement << (sizeof(mPhaseIncrement)*8 - c.mShift)) == 0;
41186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    if (locked) {
41286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
41386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
41483be2560d9396b3bd32919123bd67a783e6aaf7cAndy Hung
415075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // stride is the minimum number of filter coefficients processed per loop iteration.
416075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // We currently only allow a stride of 16 to match with SIMD processing.
417075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // This means that the filter length must be a multiple of 16,
418075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // or half the filter length (mHalfNumCoefs) must be a multiple of 8.
419075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    //
420075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // Note: A stride of 2 is achieved with non-SIMD processing.
421075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    int stride = ((c.mHalfNumCoefs & 7) == 0) ? 16 : 2;
422075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    LOG_ALWAYS_FATAL_IF(stride < 16, "Resampler stride must be 16 or more");
4235e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    LOG_ALWAYS_FATAL_IF(mChannelCount < 1 || mChannelCount > 8,
424075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            "Resampler channels(%d) must be between 1 to 8", mChannelCount);
425075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // stride 16 (falls back to stride 2 for machines that do not support NEON)
426075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    if (locked) {
427075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        switch (mChannelCount) {
428075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 1:
429075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
430075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
431075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 2:
432075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
433075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
434075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 3:
435075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, true, 16>;
436075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
437075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 4:
438075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, true, 16>;
439075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
440075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 5:
441075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, true, 16>;
442075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
443075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 6:
444075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, true, 16>;
445075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
446075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 7:
447075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, true, 16>;
448075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
449075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 8:
450075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, true, 16>;
451075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
452075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        }
453075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    } else {
454075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        switch (mChannelCount) {
455075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 1:
456075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
457075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
458075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 2:
459075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
460075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
461075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 3:
462075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, false, 16>;
463075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
464075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 4:
465075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, false, 16>;
466075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
467075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 5:
468075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, false, 16>;
469075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
470075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 6:
471075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, false, 16>;
472075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
473075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 7:
474075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, false, 16>;
475075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
476075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        case 8:
477075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, false, 16>;
478075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            break;
479075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung        }
480075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    }
48186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#ifdef DEBUG_RESAMPLER
48286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
48386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            mChannelCount, locked ? "locked" : "interpolated",
48486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            stride, useS32 ? "S32" : "S16", 2*c.mHalfNumCoefs, c.mShift);
48586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#endif
48686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
48786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
488771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
4896b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount,
49086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            AudioBufferProvider* provider)
49186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
4926b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung    return (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider);
493771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung}
49486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
495771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<typename TC, typename TI, typename TO>
496771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate<int CHANNELS, bool LOCKED, int STRIDE>
4976b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
498771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        AudioBufferProvider* provider)
49986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung{
500075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    // TODO Mono -> Mono is not supported. OUTPUT_CHANNELS reflects minimum of stereo out.
501075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    const int OUTPUT_CHANNELS = (CHANNELS < 2) ? 2 : CHANNELS;
50286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const Constants& c(mConstants);
503771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    const TC* const coefs = mConstants.mFirCoefs;
504771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung    TI* impulse = mInBuffer.getImpulse();
505411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung    size_t inputIndex = 0;
50686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    uint32_t phaseFraction = mPhaseFraction;
50786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const uint32_t phaseIncrement = mPhaseIncrement;
50886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    size_t outputIndex = 0;
509075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung    size_t outputSampleCount = outFrameCount * OUTPUT_CHANNELS;
51086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    const uint32_t phaseWrapLimit = c.mL << c.mShift;
511717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    size_t inFrameCount = (phaseIncrement * (uint64_t)outFrameCount + phaseFraction)
512717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            / phaseWrapLimit;
513717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // sanity check that inFrameCount is in signed 32 bit integer range.
514717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    ALOG_ASSERT(0 <= inFrameCount && inFrameCount < (1U << 31));
515717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung
516717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    //ALOGV("inFrameCount:%d  outFrameCount:%d"
517717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    //        "  phaseIncrement:%u  phaseFraction:%u  phaseWrapLimit:%u",
518717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    //        inFrameCount, outFrameCount, phaseIncrement, phaseFraction, phaseWrapLimit);
51986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
52086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // NOTE: be very careful when modifying the code here. register
52186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // pressure is very high and a small change might cause the compiler
52286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // to generate far less efficient code.
52386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // Always sanity check the result with objdump or test-resample.
52486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
52586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // the following logic is a bit convoluted to keep the main processing loop
52686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    // as tight as possible with register allocation.
52786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    while (outputIndex < outputSampleCount) {
528717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        //ALOGV("LOOP: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
529717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        //        "  phaseFraction:%u  phaseWrapLimit:%u",
530717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
531717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung
532717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // check inputIndex overflow
5334348921d6168f301e28069478956ddaa7ef06f8bTobias Melin        ALOG_ASSERT(inputIndex <= mBuffer.frameCount, "inputIndex%zu > frameCount%zu",
534717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                inputIndex, mBuffer.frameCount);
535717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // Buffer is empty, fetch a new one if necessary (inFrameCount > 0).
536717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // We may not fetch a new buffer if the existing data is sufficient.
537717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        while (mBuffer.frameCount == 0 && inFrameCount > 0) {
53886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            mBuffer.frameCount = inFrameCount;
539d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten            provider->getNextBuffer(&mBuffer);
54086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            if (mBuffer.raw == NULL) {
541bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang                // We are either at the end of playback or in an underrun situation.
542bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang                // Reset buffer to prevent pop noise at the next buffer.
543bd179d1adb974f86b60240acceb70d86fdf58d1cHochi Huang                mInBuffer.reset();
54486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                goto resample_exit;
54586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
546411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung            inFrameCount -= mBuffer.frameCount;
54786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            if (phaseFraction >= phaseWrapLimit) { // read in data
548771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                mInBuffer.template readAdvance<CHANNELS>(
549771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                        impulse, c.mHalfNumCoefs,
550771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                        reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
551717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                inputIndex++;
55286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                phaseFraction -= phaseWrapLimit;
55386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                while (phaseFraction >= phaseWrapLimit) {
55486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    if (inputIndex >= mBuffer.frameCount) {
555411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung                        inputIndex = 0;
55686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                        provider->releaseBuffer(&mBuffer);
55786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                        break;
55886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    }
559771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                    mInBuffer.template readAdvance<CHANNELS>(
560771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                            impulse, c.mHalfNumCoefs,
561771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                            reinterpret_cast<TI*>(mBuffer.raw), inputIndex);
562717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                    inputIndex++;
56386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    phaseFraction -= phaseWrapLimit;
56486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                }
56586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
56686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
567771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TI* const in = reinterpret_cast<const TI*>(mBuffer.raw);
56886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const size_t frameCount = mBuffer.frameCount;
56986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const int coefShift = c.mShift;
57086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        const int halfNumCoefs = c.mHalfNumCoefs;
571771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung        const TO* const volumeSimd = mVolumeSimd;
57286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
57386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        // main processing loop
57486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        while (CC_LIKELY(outputIndex < outputSampleCount)) {
57586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // caution: fir() is inlined and may be large.
57686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // output will be loaded with the appropriate values
57786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            //
57886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // from the input samples in impulse[-halfNumCoefs+1]... impulse[halfNumCoefs]
57986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            // from the polyphase filter of (phaseFraction / phaseWrapLimit) in coefs.
58086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            //
581717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            //ALOGV("LOOP2: inFrameCount:%d  outputIndex:%d  outFrameCount:%d"
582717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            //        "  phaseFraction:%u  phaseWrapLimit:%u",
583717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            //        inFrameCount, outputIndex, outFrameCount, phaseFraction, phaseWrapLimit);
584717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            ALOG_ASSERT(phaseFraction < phaseWrapLimit);
58586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            fir<CHANNELS, LOCKED, STRIDE>(
58686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    &out[outputIndex],
58786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    phaseFraction, phaseWrapLimit,
58886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    coefShift, halfNumCoefs, coefs,
58986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    impulse, volumeSimd);
590075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung
591075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung            outputIndex += OUTPUT_CHANNELS;
59286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
59386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            phaseFraction += phaseIncrement;
59486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            while (phaseFraction >= phaseWrapLimit) {
59586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                if (inputIndex >= frameCount) {
59686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                    goto done;  // need a new buffer
59786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                }
598771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung                mInBuffer.template readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
599717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                inputIndex++;
60086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung                phaseFraction -= phaseWrapLimit;
60186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            }
60286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
60386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungdone:
604717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // We arrive here when we're finished or when the input buffer runs out.
605717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        // Regardless we need to release the input buffer if we've acquired it.
606717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung        if (inputIndex > 0) {  // we've acquired a buffer (alternatively could check frameCount)
6074348921d6168f301e28069478956ddaa7ef06f8bTobias Melin            ALOG_ASSERT(inputIndex == frameCount, "inputIndex(%zu) != frameCount(%zu)",
608717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung                    inputIndex, frameCount);  // must have been fully read.
609411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung            inputIndex = 0;
61086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung            provider->releaseBuffer(&mBuffer);
611411cb8e45442d16d983a38722c7c7bce487bde6bAndy Hung            ALOG_ASSERT(mBuffer.frameCount == 0);
61286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung        }
61386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    }
61486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
61586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hungresample_exit:
616717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // inputIndex must be zero in all three cases:
617717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // (1) the buffer never was been acquired; (2) the buffer was
618717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    // released at "done:"; or (3) getNextBuffer() failed.
6194348921d6168f301e28069478956ddaa7ef06f8bTobias Melin    ALOG_ASSERT(inputIndex == 0, "Releasing: inputindex:%zu frameCount:%zu  phaseFraction:%u",
620717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung            inputIndex, mBuffer.frameCount, phaseFraction);
621717007429a50c02d2acc704a8c1ebbe6760a2c22Andy Hung    ALOG_ASSERT(mBuffer.frameCount == 0); // there must be no frames in the buffer
62286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mInBuffer.setImpulse(impulse);
62386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung    mPhaseFraction = phaseFraction;
6246b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung    return outputIndex / OUTPUT_CHANNELS;
62586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung}
62686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung
627771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung/* instantiate templates used by AudioResampler::create */
628771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate class AudioResamplerDyn<float, float, float>;
629771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate class AudioResamplerDyn<int16_t, int16_t, int32_t>;
630771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hungtemplate class AudioResamplerDyn<int32_t, int16_t, int32_t>;
631771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung
63286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung// ----------------------------------------------------------------------------
63363238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android
634