AudioResamplerDyn.cpp revision d549139155b20d7cbf6a4326133e06def465ef54
1bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea/*
2bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * Copyright (C) 2013 The Android Open Source Project
3bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea *
4bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * Licensed under the Apache License, Version 2.0 (the "License");
5bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * you may not use this file except in compliance with the License.
6bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * You may obtain a copy of the License at
7bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea *
8bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea *      http://www.apache.org/licenses/LICENSE-2.0
9bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea *
10bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * Unless required by applicable law or agreed to in writing, software
11bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * distributed under the License is distributed on an "AS IS" BASIS,
12bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * See the License for the specific language governing permissions and
14bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea * limitations under the License.
15bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea */
16bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea
17bdcd07921b76d3df2cc7e6563718dde79876b0adDaniel Malea#define LOG_TAG "AudioResamplerDyn"
18//#define LOG_NDEBUG 0
19
20#include <malloc.h>
21#include <string.h>
22#include <stdlib.h>
23#include <dlfcn.h>
24#include <math.h>
25
26#include <cutils/compiler.h>
27#include <cutils/properties.h>
28#include <utils/Debug.h>
29#include <utils/Log.h>
30
31#include "AudioResamplerFirOps.h" // USE_NEON and USE_INLINE_ASSEMBLY defined here
32#include "AudioResamplerFirProcess.h"
33#include "AudioResamplerFirProcessNeon.h"
34#include "AudioResamplerFirGen.h" // requires math.h
35#include "AudioResamplerDyn.h"
36
37//#define DEBUG_RESAMPLER
38
39namespace android {
40
41// generate a unique resample type compile-time constant (constexpr)
42#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE, COEFTYPE) \
43    ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 | (COEFTYPE)<<2 \
44    | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<3)
45
46/*
47 * InBuffer is a type agnostic input buffer.
48 *
49 * Layout of the state buffer for halfNumCoefs=8.
50 *
51 * [rrrrrrppppppppnnnnnnnnrrrrrrrrrrrrrrrrrrr.... rrrrrrr]
52 *  S            I                                R
53 *
54 * S = mState
55 * I = mImpulse
56 * R = mRingFull
57 * p = past samples, convoluted with the (p)ositive side of sinc()
58 * n = future samples, convoluted with the (n)egative side of sinc()
59 * r = extra space for implementing the ring buffer
60 */
61
62template<typename TI>
63AudioResamplerDyn::InBuffer<TI>::InBuffer()
64    : mState(NULL), mImpulse(NULL), mRingFull(NULL), mStateSize(0) {
65}
66
67template<typename TI>
68AudioResamplerDyn::InBuffer<TI>::~InBuffer() {
69    init();
70}
71
72template<typename TI>
73void AudioResamplerDyn::InBuffer<TI>::init() {
74    free(mState);
75    mState = NULL;
76    mImpulse = NULL;
77    mRingFull = NULL;
78    mStateSize = 0;
79}
80
81// resizes the state buffer to accommodate the appropriate filter length
82template<typename TI>
83void AudioResamplerDyn::InBuffer<TI>::resize(int CHANNELS, int halfNumCoefs) {
84    // calculate desired state size
85    int stateSize = halfNumCoefs * CHANNELS * 2
86            * kStateSizeMultipleOfFilterLength;
87
88    // check if buffer needs resizing
89    if (mState
90            && stateSize == mStateSize
91            && mRingFull-mState == mStateSize-halfNumCoefs*CHANNELS) {
92        return;
93    }
94
95    // create new buffer
96    TI* state = (int16_t*)memalign(32, stateSize*sizeof(*state));
97    memset(state, 0, stateSize*sizeof(*state));
98
99    // attempt to preserve state
100    if (mState) {
101        TI* srcLo = mImpulse - halfNumCoefs*CHANNELS;
102        TI* srcHi = mImpulse + halfNumCoefs*CHANNELS;
103        TI* dst = state;
104
105        if (srcLo < mState) {
106            dst += mState-srcLo;
107            srcLo = mState;
108        }
109        if (srcHi > mState + mStateSize) {
110            srcHi = mState + mStateSize;
111        }
112        memcpy(dst, srcLo, (srcHi - srcLo) * sizeof(*srcLo));
113        free(mState);
114    }
115
116    // set class member vars
117    mState = state;
118    mStateSize = stateSize;
119    mImpulse = mState + halfNumCoefs*CHANNELS; // actually one sample greater than needed
120    mRingFull = mState + mStateSize - halfNumCoefs*CHANNELS;
121}
122
123// copy in the input data into the head (impulse+halfNumCoefs) of the buffer.
124template<typename TI>
125template<int CHANNELS>
126void AudioResamplerDyn::InBuffer<TI>::readAgain(TI*& impulse, const int halfNumCoefs,
127        const TI* const in, const size_t inputIndex) {
128    int16_t* head = impulse + halfNumCoefs*CHANNELS;
129    for (size_t i=0 ; i<CHANNELS ; i++) {
130        head[i] = in[inputIndex*CHANNELS + i];
131    }
132}
133
134// advance the impulse pointer, and load in data into the head (impulse+halfNumCoefs)
135template<typename TI>
136template<int CHANNELS>
137void AudioResamplerDyn::InBuffer<TI>::readAdvance(TI*& impulse, const int halfNumCoefs,
138        const TI* const in, const size_t inputIndex) {
139    impulse += CHANNELS;
140
141    if (CC_UNLIKELY(impulse >= mRingFull)) {
142        const size_t shiftDown = mRingFull - mState - halfNumCoefs*CHANNELS;
143        memcpy(mState, mState+shiftDown, halfNumCoefs*CHANNELS*2*sizeof(TI));
144        impulse -= shiftDown;
145    }
146    readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
147}
148
149void AudioResamplerDyn::Constants::set(
150        int L, int halfNumCoefs, int inSampleRate, int outSampleRate)
151{
152    int bits = 0;
153    int lscale = inSampleRate/outSampleRate < 2 ? L - 1 :
154            static_cast<int>(static_cast<uint64_t>(L)*inSampleRate/outSampleRate);
155    for (int i=lscale; i; ++bits, i>>=1)
156        ;
157    mL = L;
158    mShift = kNumPhaseBits - bits;
159    mHalfNumCoefs = halfNumCoefs;
160}
161
162AudioResamplerDyn::AudioResamplerDyn(int bitDepth,
163        int inChannelCount, int32_t sampleRate, src_quality quality)
164    : AudioResampler(bitDepth, inChannelCount, sampleRate, quality),
165    mResampleType(0), mFilterSampleRate(0), mFilterQuality(DEFAULT_QUALITY),
166    mCoefBuffer(NULL)
167{
168    mVolumeSimd[0] = mVolumeSimd[1] = 0;
169    // The AudioResampler base class assumes we are always ready for 1:1 resampling.
170    // We reset mInSampleRate to 0, so setSampleRate() will calculate filters for
171    // setSampleRate() for 1:1. (May be removed if precalculated filters are used.)
172    mInSampleRate = 0;
173    mConstants.set(128, 8, mSampleRate, mSampleRate); // TODO: set better
174}
175
176AudioResamplerDyn::~AudioResamplerDyn() {
177    free(mCoefBuffer);
178}
179
180void AudioResamplerDyn::init() {
181    mFilterSampleRate = 0; // always trigger new filter generation
182    mInBuffer.init();
183}
184
185void AudioResamplerDyn::setVolume(int16_t left, int16_t right) {
186    AudioResampler::setVolume(left, right);
187    mVolumeSimd[0] = static_cast<int32_t>(left)<<16;
188    mVolumeSimd[1] = static_cast<int32_t>(right)<<16;
189}
190
191template <typename T> T max(T a, T b) {return a > b ? a : b;}
192
193template <typename T> T absdiff(T a, T b) {return a > b ? a - b : b - a;}
194
195template<typename T>
196void AudioResamplerDyn::createKaiserFir(Constants &c, double stopBandAtten,
197        int inSampleRate, int outSampleRate, double tbwCheat) {
198    T* buf = reinterpret_cast<T*>(memalign(32, (c.mL+1)*c.mHalfNumCoefs*sizeof(T)));
199    static const double atten = 0.9998;   // to avoid ripple overflow
200    double fcr;
201    double tbw = firKaiserTbw(c.mHalfNumCoefs, stopBandAtten);
202
203    if (inSampleRate < outSampleRate) { // upsample
204        fcr = max(0.5*tbwCheat - tbw/2, tbw/2);
205    } else { // downsample
206        fcr = max(0.5*tbwCheat*outSampleRate/inSampleRate - tbw/2, tbw/2);
207    }
208    // create and set filter
209    firKaiserGen(buf, c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten);
210    c.setBuf(buf);
211    if (mCoefBuffer) {
212        free(mCoefBuffer);
213    }
214    mCoefBuffer = buf;
215#ifdef DEBUG_RESAMPLER
216    // print basic filter stats
217    printf("L:%d  hnc:%d  stopBandAtten:%lf  fcr:%lf  atten:%lf  tbw:%lf\n",
218            c.mL, c.mHalfNumCoefs, stopBandAtten, fcr, atten, tbw);
219    // test the filter and report results
220    double fp = (fcr - tbw/2)/c.mL;
221    double fs = (fcr + tbw/2)/c.mL;
222    double passMin, passMax, passRipple;
223    double stopMax, stopRipple;
224    testFir(buf, c.mL, c.mHalfNumCoefs, fp, fs, /*passSteps*/ 1000, /*stopSteps*/ 100000,
225            passMin, passMax, passRipple, stopMax, stopRipple);
226    printf("passband(%lf, %lf): %.8lf %.8lf %.8lf\n", 0., fp, passMin, passMax, passRipple);
227    printf("stopband(%lf, %lf): %.8lf %.3lf\n", fs, 0.5, stopMax, stopRipple);
228#endif
229}
230
231// recursive gcd. Using objdump, it appears the tail recursion is converted to a while loop.
232static int gcd(int n, int m) {
233    if (m == 0) {
234        return n;
235    }
236    return gcd(m, n % m);
237}
238
239static bool isClose(int32_t newSampleRate, int32_t prevSampleRate,
240        int32_t filterSampleRate, int32_t outSampleRate) {
241
242    // different upsampling ratios do not need a filter change.
243    if (filterSampleRate != 0
244            && filterSampleRate < outSampleRate
245            && newSampleRate < outSampleRate)
246        return true;
247
248    // check design criteria again if downsampling is detected.
249    int pdiff = absdiff(newSampleRate, prevSampleRate);
250    int adiff = absdiff(newSampleRate, filterSampleRate);
251
252    // allow up to 6% relative change increments.
253    // allow up to 12% absolute change increments (from filter design)
254    return pdiff < prevSampleRate>>4 && adiff < filterSampleRate>>3;
255}
256
257void AudioResamplerDyn::setSampleRate(int32_t inSampleRate) {
258    if (mInSampleRate == inSampleRate) {
259        return;
260    }
261    int32_t oldSampleRate = mInSampleRate;
262    int32_t oldHalfNumCoefs = mConstants.mHalfNumCoefs;
263    uint32_t oldPhaseWrapLimit = mConstants.mL << mConstants.mShift;
264    bool useS32 = false;
265
266    mInSampleRate = inSampleRate;
267
268    // TODO: Add precalculated Equiripple filters
269
270    if (mFilterQuality != getQuality() ||
271            !isClose(inSampleRate, oldSampleRate, mFilterSampleRate, mSampleRate)) {
272        mFilterSampleRate = inSampleRate;
273        mFilterQuality = getQuality();
274
275        // Begin Kaiser Filter computation
276        //
277        // The quantization floor for S16 is about 96db - 10*log_10(#length) + 3dB.
278        // Keep the stop band attenuation no greater than 84-85dB for 32 length S16 filters
279        //
280        // For s32 we keep the stop band attenuation at the same as 16b resolution, about
281        // 96-98dB
282        //
283
284        double stopBandAtten;
285        double tbwCheat = 1.; // how much we "cheat" into aliasing
286        int halfLength;
287        if (mFilterQuality == DYN_HIGH_QUALITY) {
288            // 32b coefficients, 64 length
289            useS32 = true;
290            stopBandAtten = 98.;
291            if (inSampleRate >= mSampleRate * 4) {
292                halfLength = 48;
293            } else if (inSampleRate >= mSampleRate * 2) {
294                halfLength = 40;
295            } else {
296                halfLength = 32;
297            }
298        } else if (mFilterQuality == DYN_LOW_QUALITY) {
299            // 16b coefficients, 16-32 length
300            useS32 = false;
301            stopBandAtten = 80.;
302            if (inSampleRate >= mSampleRate * 4) {
303                halfLength = 24;
304            } else if (inSampleRate >= mSampleRate * 2) {
305                halfLength = 16;
306            } else {
307                halfLength = 8;
308            }
309            if (inSampleRate <= mSampleRate) {
310                tbwCheat = 1.05;
311            } else {
312                tbwCheat = 1.03;
313            }
314        } else { // DYN_MED_QUALITY
315            // 16b coefficients, 32-64 length
316            // note: > 64 length filters with 16b coefs can have quantization noise problems
317            useS32 = false;
318            stopBandAtten = 84.;
319            if (inSampleRate >= mSampleRate * 4) {
320                halfLength = 32;
321            } else if (inSampleRate >= mSampleRate * 2) {
322                halfLength = 24;
323            } else {
324                halfLength = 16;
325            }
326            if (inSampleRate <= mSampleRate) {
327                tbwCheat = 1.03;
328            } else {
329                tbwCheat = 1.01;
330            }
331        }
332
333        // determine the number of polyphases in the filterbank.
334        // for 16b, it is desirable to have 2^(16/2) = 256 phases.
335        // https://ccrma.stanford.edu/~jos/resample/Relation_Interpolation_Error_Quantization.html
336        //
337        // We are a bit more lax on this.
338
339        int phases = mSampleRate / gcd(mSampleRate, inSampleRate);
340
341        // TODO: Once dynamic sample rate change is an option, the code below
342        // should be modified to execute only when dynamic sample rate change is enabled.
343        //
344        // as above, #phases less than 63 is too few phases for accurate linear interpolation.
345        // we increase the phases to compensate, but more phases means more memory per
346        // filter and more time to compute the filter.
347        //
348        // if we know that the filter will be used for dynamic sample rate changes,
349        // that would allow us skip this part for fixed sample rate resamplers.
350        //
351        while (phases<63) {
352            phases *= 2; // this code only needed to support dynamic rate changes
353        }
354
355        if (phases>=256) {  // too many phases, always interpolate
356            phases = 127;
357        }
358
359        // create the filter
360        mConstants.set(phases, halfLength, inSampleRate, mSampleRate);
361        if (useS32) {
362            createKaiserFir<int32_t>(mConstants, stopBandAtten,
363                    inSampleRate, mSampleRate, tbwCheat);
364        } else {
365            createKaiserFir<int16_t>(mConstants, stopBandAtten,
366                    inSampleRate, mSampleRate, tbwCheat);
367        }
368    } // End Kaiser filter
369
370    // update phase and state based on the new filter.
371    const Constants& c(mConstants);
372    mInBuffer.resize(mChannelCount, c.mHalfNumCoefs);
373    const uint32_t phaseWrapLimit = c.mL << c.mShift;
374    // try to preserve as much of the phase fraction as possible for on-the-fly changes
375    mPhaseFraction = static_cast<unsigned long long>(mPhaseFraction)
376            * phaseWrapLimit / oldPhaseWrapLimit;
377    mPhaseFraction %= phaseWrapLimit; // should not do anything, but just in case.
378    mPhaseIncrement = static_cast<uint32_t>(static_cast<double>(phaseWrapLimit)
379            * inSampleRate / mSampleRate);
380
381    // determine which resampler to use
382    // check if locked phase (works only if mPhaseIncrement has no "fractional phase bits")
383    int locked = (mPhaseIncrement << (sizeof(mPhaseIncrement)*8 - c.mShift)) == 0;
384    int stride = (c.mHalfNumCoefs&7)==0 ? 16 : (c.mHalfNumCoefs&3)==0 ? 8 : 2;
385    if (locked) {
386        mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
387    }
388
389    mResampleType = RESAMPLETYPE(mChannelCount, locked, stride, !!useS32);
390#ifdef DEBUG_RESAMPLER
391    printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
392            mChannelCount, locked ? "locked" : "interpolated",
393            stride, useS32 ? "S32" : "S16", 2*c.mHalfNumCoefs, c.mShift);
394#endif
395}
396
397void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
398            AudioBufferProvider* provider)
399{
400    // TODO:
401    // 24 cases - this perhaps can be reduced later, as testing might take too long
402    switch (mResampleType) {
403
404    // stride 16 (falls back to stride 2 for machines that do not support NEON)
405    case RESAMPLETYPE(1, true, 16, 0):
406        return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
407    case RESAMPLETYPE(2, true, 16, 0):
408        return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
409    case RESAMPLETYPE(1, false, 16, 0):
410        return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
411    case RESAMPLETYPE(2, false, 16, 0):
412        return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
413    case RESAMPLETYPE(1, true, 16, 1):
414        return resample<1, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
415    case RESAMPLETYPE(2, true, 16, 1):
416        return resample<2, true, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
417    case RESAMPLETYPE(1, false, 16, 1):
418        return resample<1, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
419    case RESAMPLETYPE(2, false, 16, 1):
420        return resample<2, false, 16>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
421#if 0
422    // TODO: Remove these?
423    // stride 8
424    case RESAMPLETYPE(1, true, 8, 0):
425        return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
426    case RESAMPLETYPE(2, true, 8, 0):
427        return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
428    case RESAMPLETYPE(1, false, 8, 0):
429        return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
430    case RESAMPLETYPE(2, false, 8, 0):
431        return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
432    case RESAMPLETYPE(1, true, 8, 1):
433        return resample<1, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
434    case RESAMPLETYPE(2, true, 8, 1):
435        return resample<2, true, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
436    case RESAMPLETYPE(1, false, 8, 1):
437        return resample<1, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
438    case RESAMPLETYPE(2, false, 8, 1):
439        return resample<2, false, 8>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
440    // stride 2 (can handle any filter length)
441    case RESAMPLETYPE(1, true, 2, 0):
442        return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
443    case RESAMPLETYPE(2, true, 2, 0):
444        return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
445    case RESAMPLETYPE(1, false, 2, 0):
446        return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
447    case RESAMPLETYPE(2, false, 2, 0):
448        return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS16, provider);
449    case RESAMPLETYPE(1, true, 2, 1):
450        return resample<1, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
451    case RESAMPLETYPE(2, true, 2, 1):
452        return resample<2, true, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
453    case RESAMPLETYPE(1, false, 2, 1):
454        return resample<1, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
455    case RESAMPLETYPE(2, false, 2, 1):
456        return resample<2, false, 2>(out, outFrameCount, mConstants.mFirCoefsS32, provider);
457#endif
458    default:
459        ; // error
460    }
461}
462
463template<int CHANNELS, bool LOCKED, int STRIDE, typename TC>
464void AudioResamplerDyn::resample(int32_t* out, size_t outFrameCount,
465        const TC* const coefs,  AudioBufferProvider* provider)
466{
467    const Constants& c(mConstants);
468    int16_t* impulse = mInBuffer.getImpulse();
469    size_t inputIndex = mInputIndex;
470    uint32_t phaseFraction = mPhaseFraction;
471    const uint32_t phaseIncrement = mPhaseIncrement;
472    size_t outputIndex = 0;
473    size_t outputSampleCount = outFrameCount * 2;   // stereo output
474    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
475    const uint32_t phaseWrapLimit = c.mL << c.mShift;
476
477    // NOTE: be very careful when modifying the code here. register
478    // pressure is very high and a small change might cause the compiler
479    // to generate far less efficient code.
480    // Always sanity check the result with objdump or test-resample.
481
482    // the following logic is a bit convoluted to keep the main processing loop
483    // as tight as possible with register allocation.
484    while (outputIndex < outputSampleCount) {
485        // buffer is empty, fetch a new one
486        while (mBuffer.frameCount == 0) {
487            mBuffer.frameCount = inFrameCount;
488            provider->getNextBuffer(&mBuffer,
489                    calculateOutputPTS(outputIndex / 2));
490            if (mBuffer.raw == NULL) {
491                goto resample_exit;
492            }
493            if (phaseFraction >= phaseWrapLimit) { // read in data
494                mInBuffer.readAdvance<CHANNELS>(
495                        impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
496                phaseFraction -= phaseWrapLimit;
497                while (phaseFraction >= phaseWrapLimit) {
498                    inputIndex++;
499                    if (inputIndex >= mBuffer.frameCount) {
500                        inputIndex -= mBuffer.frameCount;
501                        provider->releaseBuffer(&mBuffer);
502                        break;
503                    }
504                    mInBuffer.readAdvance<CHANNELS>(
505                            impulse, c.mHalfNumCoefs, mBuffer.i16, inputIndex);
506                    phaseFraction -= phaseWrapLimit;
507                }
508            }
509        }
510        const int16_t* const in = mBuffer.i16;
511        const size_t frameCount = mBuffer.frameCount;
512        const int coefShift = c.mShift;
513        const int halfNumCoefs = c.mHalfNumCoefs;
514        const int32_t* const volumeSimd = mVolumeSimd;
515
516        // reread the last input in.
517        mInBuffer.readAgain<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
518
519        // main processing loop
520        while (CC_LIKELY(outputIndex < outputSampleCount)) {
521            // caution: fir() is inlined and may be large.
522            // output will be loaded with the appropriate values
523            //
524            // from the input samples in impulse[-halfNumCoefs+1]... impulse[halfNumCoefs]
525            // from the polyphase filter of (phaseFraction / phaseWrapLimit) in coefs.
526            //
527            fir<CHANNELS, LOCKED, STRIDE>(
528                    &out[outputIndex],
529                    phaseFraction, phaseWrapLimit,
530                    coefShift, halfNumCoefs, coefs,
531                    impulse, volumeSimd);
532            outputIndex += 2;
533
534            phaseFraction += phaseIncrement;
535            while (phaseFraction >= phaseWrapLimit) {
536                inputIndex++;
537                if (inputIndex >= frameCount) {
538                    goto done;  // need a new buffer
539                }
540                mInBuffer.readAdvance<CHANNELS>(impulse, halfNumCoefs, in, inputIndex);
541                phaseFraction -= phaseWrapLimit;
542            }
543        }
544done:
545        // often arrives here when input buffer runs out
546        if (inputIndex >= frameCount) {
547            inputIndex -= frameCount;
548            provider->releaseBuffer(&mBuffer);
549            // mBuffer.frameCount MUST be zero here.
550        }
551    }
552
553resample_exit:
554    mInBuffer.setImpulse(impulse);
555    mInputIndex = inputIndex;
556    mPhaseFraction = phaseFraction;
557}
558
559// ----------------------------------------------------------------------------
560}; // namespace android
561