1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "AudioResampler"
18//#define LOG_NDEBUG 0
19
20#include <stdint.h>
21#include <stdlib.h>
22#include <sys/types.h>
23#include <cutils/log.h>
24#include <cutils/properties.h>
25#include "AudioResampler.h"
26#include "AudioResamplerSinc.h"
27#include "AudioResamplerCubic.h"
28
29#ifdef __arm__
30#include <machine/cpu-features.h>
31#endif
32
33namespace android {
34
35#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
36    #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
37#endif // __ARM_HAVE_HALFWORD_MULTIPLY
38// ----------------------------------------------------------------------------
39
40class AudioResamplerOrder1 : public AudioResampler {
41public:
42    AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
43        AudioResampler(bitDepth, inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) {
44    }
45    virtual void resample(int32_t* out, size_t outFrameCount,
46            AudioBufferProvider* provider);
47private:
48    // number of bits used in interpolation multiply - 15 bits avoids overflow
49    static const int kNumInterpBits = 15;
50
51    // bits to shift the phase fraction down to avoid overflow
52    static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
53
54    void init() {}
55    void resampleMono16(int32_t* out, size_t outFrameCount,
56            AudioBufferProvider* provider);
57    void resampleStereo16(int32_t* out, size_t outFrameCount,
58            AudioBufferProvider* provider);
59#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
60    void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
61            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
62            uint32_t &phaseFraction, uint32_t phaseIncrement);
63    void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
64            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
65            uint32_t &phaseFraction, uint32_t phaseIncrement);
66#endif  // ASM_ARM_RESAMP1
67
68    static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
69        return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
70    }
71    static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
72        *frac += inc;
73        *index += (size_t)(*frac >> kNumPhaseBits);
74        *frac &= kPhaseMask;
75    }
76    int mX0L;
77    int mX0R;
78};
79
80bool AudioResampler::qualityIsSupported(src_quality quality)
81{
82    switch (quality) {
83    case DEFAULT_QUALITY:
84    case LOW_QUALITY:
85#if 0   // these have not been qualified recently so are not supported unless explicitly requested
86    case MED_QUALITY:
87    case HIGH_QUALITY:
88#endif
89    case VERY_HIGH_QUALITY:
90        return true;
91    default:
92        return false;
93    }
94}
95
96// ----------------------------------------------------------------------------
97
98static pthread_once_t once_control = PTHREAD_ONCE_INIT;
99static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY;
100
101void AudioResampler::init_routine()
102{
103    char value[PROPERTY_VALUE_MAX];
104    if (property_get("af.resampler.quality", value, NULL) > 0) {
105        char *endptr;
106        unsigned long l = strtoul(value, &endptr, 0);
107        if (*endptr == '\0') {
108            defaultQuality = (src_quality) l;
109            ALOGD("forcing AudioResampler quality to %d", defaultQuality);
110            if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) {
111                defaultQuality = DEFAULT_QUALITY;
112            }
113        }
114    }
115}
116
117uint32_t AudioResampler::qualityMHz(src_quality quality)
118{
119    switch (quality) {
120    default:
121    case DEFAULT_QUALITY:
122    case LOW_QUALITY:
123        return 3;
124    case MED_QUALITY:
125        return 6;
126    case HIGH_QUALITY:
127        return 20;
128    case VERY_HIGH_QUALITY:
129        return 34;
130    }
131}
132
133static const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable
134static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
135static uint32_t currentMHz = 0;
136
137AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
138        int32_t sampleRate, src_quality quality) {
139
140    bool atFinalQuality;
141    if (quality == DEFAULT_QUALITY) {
142        // read the resampler default quality property the first time it is needed
143        int ok = pthread_once(&once_control, init_routine);
144        if (ok != 0) {
145            ALOGE("%s pthread_once failed: %d", __func__, ok);
146        }
147        quality = defaultQuality;
148        atFinalQuality = false;
149    } else {
150        atFinalQuality = true;
151    }
152
153    // naive implementation of CPU load throttling doesn't account for whether resampler is active
154    pthread_mutex_lock(&mutex);
155    for (;;) {
156        uint32_t deltaMHz = qualityMHz(quality);
157        uint32_t newMHz = currentMHz + deltaMHz;
158        if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) {
159            ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d",
160                    currentMHz, newMHz, deltaMHz, quality);
161            currentMHz = newMHz;
162            break;
163        }
164        // not enough CPU available for proposed quality level, so try next lowest level
165        switch (quality) {
166        default:
167        case DEFAULT_QUALITY:
168        case LOW_QUALITY:
169            atFinalQuality = true;
170            break;
171        case MED_QUALITY:
172            quality = LOW_QUALITY;
173            break;
174        case HIGH_QUALITY:
175            quality = MED_QUALITY;
176            break;
177        case VERY_HIGH_QUALITY:
178            quality = HIGH_QUALITY;
179            break;
180        }
181    }
182    pthread_mutex_unlock(&mutex);
183
184    AudioResampler* resampler;
185
186    switch (quality) {
187    default:
188    case DEFAULT_QUALITY:
189    case LOW_QUALITY:
190        ALOGV("Create linear Resampler");
191        resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
192        break;
193#if 0   // disabled because it has not been qualified recently, if requested will use default:
194    case MED_QUALITY:
195        ALOGV("Create cubic Resampler");
196        resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
197        break;
198#endif
199    case HIGH_QUALITY:
200        ALOGV("Create HIGH_QUALITY sinc Resampler");
201        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
202        break;
203    case VERY_HIGH_QUALITY:
204        ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality);
205        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality);
206        break;
207    }
208
209    // initialize resampler
210    resampler->init();
211    return resampler;
212}
213
214AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
215        int32_t sampleRate, src_quality quality) :
216    mBitDepth(bitDepth), mChannelCount(inChannelCount),
217            mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
218            mPhaseFraction(0), mLocalTimeFreq(0),
219            mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
220    // sanity check on format
221    if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
222        ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
223                inChannelCount);
224        // ALOG_ASSERT(0);
225    }
226    if (sampleRate <= 0) {
227        ALOGE("Unsupported sample rate %d Hz", sampleRate);
228    }
229
230    // initialize common members
231    mVolume[0] = mVolume[1] = 0;
232    mBuffer.frameCount = 0;
233
234}
235
236AudioResampler::~AudioResampler() {
237    pthread_mutex_lock(&mutex);
238    src_quality quality = getQuality();
239    uint32_t deltaMHz = qualityMHz(quality);
240    int32_t newMHz = currentMHz - deltaMHz;
241    ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d",
242            currentMHz, newMHz, deltaMHz, quality);
243    LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz);
244    currentMHz = newMHz;
245    pthread_mutex_unlock(&mutex);
246}
247
248void AudioResampler::setSampleRate(int32_t inSampleRate) {
249    mInSampleRate = inSampleRate;
250    mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
251}
252
253void AudioResampler::setVolume(int16_t left, int16_t right) {
254    // TODO: Implement anti-zipper filter
255    mVolume[0] = left;
256    mVolume[1] = right;
257}
258
259void AudioResampler::setLocalTimeFreq(uint64_t freq) {
260    mLocalTimeFreq = freq;
261}
262
263void AudioResampler::setPTS(int64_t pts) {
264    mPTS = pts;
265}
266
267int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
268
269    if (mPTS == AudioBufferProvider::kInvalidPTS) {
270        return AudioBufferProvider::kInvalidPTS;
271    } else {
272        return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
273    }
274}
275
276void AudioResampler::reset() {
277    mInputIndex = 0;
278    mPhaseFraction = 0;
279    mBuffer.frameCount = 0;
280}
281
282// ----------------------------------------------------------------------------
283
284void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
285        AudioBufferProvider* provider) {
286
287    // should never happen, but we overflow if it does
288    // ALOG_ASSERT(outFrameCount < 32767);
289
290    // select the appropriate resampler
291    switch (mChannelCount) {
292    case 1:
293        resampleMono16(out, outFrameCount, provider);
294        break;
295    case 2:
296        resampleStereo16(out, outFrameCount, provider);
297        break;
298    }
299}
300
301void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
302        AudioBufferProvider* provider) {
303
304    int32_t vl = mVolume[0];
305    int32_t vr = mVolume[1];
306
307    size_t inputIndex = mInputIndex;
308    uint32_t phaseFraction = mPhaseFraction;
309    uint32_t phaseIncrement = mPhaseIncrement;
310    size_t outputIndex = 0;
311    size_t outputSampleCount = outFrameCount * 2;
312    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
313
314    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
315    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
316
317    while (outputIndex < outputSampleCount) {
318
319        // buffer is empty, fetch a new one
320        while (mBuffer.frameCount == 0) {
321            mBuffer.frameCount = inFrameCount;
322            provider->getNextBuffer(&mBuffer,
323                                    calculateOutputPTS(outputIndex / 2));
324            if (mBuffer.raw == NULL) {
325                goto resampleStereo16_exit;
326            }
327
328            // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
329            if (mBuffer.frameCount > inputIndex) break;
330
331            inputIndex -= mBuffer.frameCount;
332            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
333            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
334            provider->releaseBuffer(&mBuffer);
335            // mBuffer.frameCount == 0 now so we reload a new buffer
336        }
337
338        int16_t *in = mBuffer.i16;
339
340        // handle boundary case
341        while (inputIndex == 0) {
342            // ALOGE("boundary case");
343            out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
344            out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
345            Advance(&inputIndex, &phaseFraction, phaseIncrement);
346            if (outputIndex == outputSampleCount)
347                break;
348        }
349
350        // process input samples
351        // ALOGE("general case");
352
353#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
354        if (inputIndex + 2 < mBuffer.frameCount) {
355            int32_t* maxOutPt;
356            int32_t maxInIdx;
357
358            maxOutPt = out + (outputSampleCount - 2);   // 2 because 2 frames per loop
359            maxInIdx = mBuffer.frameCount - 2;
360            AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
361                    phaseFraction, phaseIncrement);
362        }
363#endif  // ASM_ARM_RESAMP1
364
365        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
366            out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
367                    in[inputIndex*2], phaseFraction);
368            out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
369                    in[inputIndex*2+1], phaseFraction);
370            Advance(&inputIndex, &phaseFraction, phaseIncrement);
371        }
372
373        // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
374
375        // if done with buffer, save samples
376        if (inputIndex >= mBuffer.frameCount) {
377            inputIndex -= mBuffer.frameCount;
378
379            // ALOGE("buffer done, new input index %d", inputIndex);
380
381            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
382            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
383            provider->releaseBuffer(&mBuffer);
384
385            // verify that the releaseBuffer resets the buffer frameCount
386            // ALOG_ASSERT(mBuffer.frameCount == 0);
387        }
388    }
389
390    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
391
392resampleStereo16_exit:
393    // save state
394    mInputIndex = inputIndex;
395    mPhaseFraction = phaseFraction;
396}
397
398void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
399        AudioBufferProvider* provider) {
400
401    int32_t vl = mVolume[0];
402    int32_t vr = mVolume[1];
403
404    size_t inputIndex = mInputIndex;
405    uint32_t phaseFraction = mPhaseFraction;
406    uint32_t phaseIncrement = mPhaseIncrement;
407    size_t outputIndex = 0;
408    size_t outputSampleCount = outFrameCount * 2;
409    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
410
411    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
412    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
413    while (outputIndex < outputSampleCount) {
414        // buffer is empty, fetch a new one
415        while (mBuffer.frameCount == 0) {
416            mBuffer.frameCount = inFrameCount;
417            provider->getNextBuffer(&mBuffer,
418                                    calculateOutputPTS(outputIndex / 2));
419            if (mBuffer.raw == NULL) {
420                mInputIndex = inputIndex;
421                mPhaseFraction = phaseFraction;
422                goto resampleMono16_exit;
423            }
424            // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
425            if (mBuffer.frameCount >  inputIndex) break;
426
427            inputIndex -= mBuffer.frameCount;
428            mX0L = mBuffer.i16[mBuffer.frameCount-1];
429            provider->releaseBuffer(&mBuffer);
430            // mBuffer.frameCount == 0 now so we reload a new buffer
431        }
432        int16_t *in = mBuffer.i16;
433
434        // handle boundary case
435        while (inputIndex == 0) {
436            // ALOGE("boundary case");
437            int32_t sample = Interp(mX0L, in[0], phaseFraction);
438            out[outputIndex++] += vl * sample;
439            out[outputIndex++] += vr * sample;
440            Advance(&inputIndex, &phaseFraction, phaseIncrement);
441            if (outputIndex == outputSampleCount)
442                break;
443        }
444
445        // process input samples
446        // ALOGE("general case");
447
448#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
449        if (inputIndex + 2 < mBuffer.frameCount) {
450            int32_t* maxOutPt;
451            int32_t maxInIdx;
452
453            maxOutPt = out + (outputSampleCount - 2);
454            maxInIdx = (int32_t)mBuffer.frameCount - 2;
455                AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
456                        phaseFraction, phaseIncrement);
457        }
458#endif  // ASM_ARM_RESAMP1
459
460        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
461            int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
462                    phaseFraction);
463            out[outputIndex++] += vl * sample;
464            out[outputIndex++] += vr * sample;
465            Advance(&inputIndex, &phaseFraction, phaseIncrement);
466        }
467
468
469        // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
470
471        // if done with buffer, save samples
472        if (inputIndex >= mBuffer.frameCount) {
473            inputIndex -= mBuffer.frameCount;
474
475            // ALOGE("buffer done, new input index %d", inputIndex);
476
477            mX0L = mBuffer.i16[mBuffer.frameCount-1];
478            provider->releaseBuffer(&mBuffer);
479
480            // verify that the releaseBuffer resets the buffer frameCount
481            // ALOG_ASSERT(mBuffer.frameCount == 0);
482        }
483    }
484
485    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
486
487resampleMono16_exit:
488    // save state
489    mInputIndex = inputIndex;
490    mPhaseFraction = phaseFraction;
491}
492
493#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
494
495/*******************************************************************
496*
497*   AsmMono16Loop
498*   asm optimized monotonic loop version; one loop is 2 frames
499*   Input:
500*       in : pointer on input samples
501*       maxOutPt : pointer on first not filled
502*       maxInIdx : index on first not used
503*       outputIndex : pointer on current output index
504*       out : pointer on output buffer
505*       inputIndex : pointer on current input index
506*       vl, vr : left and right gain
507*       phaseFraction : pointer on current phase fraction
508*       phaseIncrement
509*   Ouput:
510*       outputIndex :
511*       out : updated buffer
512*       inputIndex : index of next to use
513*       phaseFraction : phase fraction for next interpolation
514*
515*******************************************************************/
516__attribute__((noinline))
517void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
518            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
519            uint32_t &phaseFraction, uint32_t phaseIncrement)
520{
521#define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
522
523    asm(
524        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
525        // get parameters
526        "   ldr r6, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
527        "   ldr r6, [r6]\n"                         // phaseFraction
528        "   ldr r7, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
529        "   ldr r7, [r7]\n"                         // inputIndex
530        "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
531        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
532        "   ldr r0, [r0]\n"                         // outputIndex
533        "   add r8, r0, asl #2\n"                   // curOut
534        "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
535        "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
536        "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
537
538        // r0 pin, x0, Samp
539
540        // r1 in
541        // r2 maxOutPt
542        // r3 maxInIdx
543
544        // r4 x1, i1, i3, Out1
545        // r5 out0
546
547        // r6 frac
548        // r7 inputIndex
549        // r8 curOut
550
551        // r9 inc
552        // r10 vl
553        // r11 vr
554
555        // r12
556        // r13 sp
557        // r14
558
559        // the following loop works on 2 frames
560
561        "1:\n"
562        "   cmp r8, r2\n"                   // curOut - maxCurOut
563        "   bcs 2f\n"
564
565#define MO_ONE_FRAME \
566    "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
567    "   ldrsh r4, [r0]\n"               /* in[inputIndex] */\
568    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
569    "   ldrsh r0, [r0, #-2]\n"          /* in[inputIndex-1] */\
570    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
571    "   sub r4, r4, r0\n"               /* in[inputIndex] - in[inputIndex-1] */\
572    "   mov r4, r4, lsl #2\n"           /* <<2 */\
573    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
574    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
575    "   add r0, r0, r4\n"               /* x0 - (..) */\
576    "   mla r5, r0, r10, r5\n"          /* vl*interp + out[] */\
577    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
578    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
579    "   mla r4, r0, r11, r4\n"          /* vr*interp + out[] */\
580    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */\
581    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */
582
583        MO_ONE_FRAME    // frame 1
584        MO_ONE_FRAME    // frame 2
585
586        "   cmp r7, r3\n"                   // inputIndex - maxInIdx
587        "   bcc 1b\n"
588        "2:\n"
589
590        "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
591        // save modified values
592        "   ldr r0, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
593        "   str r6, [r0]\n"                         // phaseFraction
594        "   ldr r0, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
595        "   str r7, [r0]\n"                         // inputIndex
596        "   ldr r0, [sp, #" MO_PARAM5 " + 4]\n"     // out
597        "   sub r8, r0\n"                           // curOut - out
598        "   asr r8, #2\n"                           // new outputIndex
599        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
600        "   str r8, [r0]\n"                         // save outputIndex
601
602        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
603    );
604}
605
606/*******************************************************************
607*
608*   AsmStereo16Loop
609*   asm optimized stereo loop version; one loop is 2 frames
610*   Input:
611*       in : pointer on input samples
612*       maxOutPt : pointer on first not filled
613*       maxInIdx : index on first not used
614*       outputIndex : pointer on current output index
615*       out : pointer on output buffer
616*       inputIndex : pointer on current input index
617*       vl, vr : left and right gain
618*       phaseFraction : pointer on current phase fraction
619*       phaseIncrement
620*   Ouput:
621*       outputIndex :
622*       out : updated buffer
623*       inputIndex : index of next to use
624*       phaseFraction : phase fraction for next interpolation
625*
626*******************************************************************/
627__attribute__((noinline))
628void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
629            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
630            uint32_t &phaseFraction, uint32_t phaseIncrement)
631{
632#define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
633    asm(
634        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
635        // get parameters
636        "   ldr r6, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
637        "   ldr r6, [r6]\n"                         // phaseFraction
638        "   ldr r7, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
639        "   ldr r7, [r7]\n"                         // inputIndex
640        "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
641        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
642        "   ldr r0, [r0]\n"                         // outputIndex
643        "   add r8, r0, asl #2\n"                   // curOut
644        "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
645        "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
646        "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
647
648        // r0 pin, x0, Samp
649
650        // r1 in
651        // r2 maxOutPt
652        // r3 maxInIdx
653
654        // r4 x1, i1, i3, out1
655        // r5 out0
656
657        // r6 frac
658        // r7 inputIndex
659        // r8 curOut
660
661        // r9 inc
662        // r10 vl
663        // r11 vr
664
665        // r12 temporary
666        // r13 sp
667        // r14
668
669        "3:\n"
670        "   cmp r8, r2\n"                   // curOut - maxCurOut
671        "   bcs 4f\n"
672
673#define ST_ONE_FRAME \
674    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
675\
676    "   add r0, r1, r7, asl #2\n"       /* in + 2*inputIndex */\
677\
678    "   ldrsh r4, [r0]\n"               /* in[2*inputIndex] */\
679    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
680    "   ldrsh r12, [r0, #-4]\n"         /* in[2*inputIndex-2] */\
681    "   sub r4, r4, r12\n"              /* in[2*InputIndex] - in[2*InputIndex-2] */\
682    "   mov r4, r4, lsl #2\n"           /* <<2 */\
683    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
684    "   add r12, r12, r4\n"             /* x0 - (..) */\
685    "   mla r5, r12, r10, r5\n"         /* vl*interp + out[] */\
686    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
687    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
688\
689    "   ldrsh r12, [r0, #+2]\n"         /* in[2*inputIndex+1] */\
690    "   ldrsh r0, [r0, #-2]\n"          /* in[2*inputIndex-1] */\
691    "   sub r12, r12, r0\n"             /* in[2*InputIndex] - in[2*InputIndex-2] */\
692    "   mov r12, r12, lsl #2\n"         /* <<2 */\
693    "   smulwt r12, r12, r6\n"          /* (x1-x0)*.. */\
694    "   add r12, r0, r12\n"             /* x0 - (..) */\
695    "   mla r4, r12, r11, r4\n"         /* vr*interp + out[] */\
696    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */\
697\
698    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
699    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */
700
701    ST_ONE_FRAME    // frame 1
702    ST_ONE_FRAME    // frame 1
703
704        "   cmp r7, r3\n"                       // inputIndex - maxInIdx
705        "   bcc 3b\n"
706        "4:\n"
707
708        "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
709        // save modified values
710        "   ldr r0, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
711        "   str r6, [r0]\n"                         // phaseFraction
712        "   ldr r0, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
713        "   str r7, [r0]\n"                         // inputIndex
714        "   ldr r0, [sp, #" ST_PARAM5 " + 4]\n"     // out
715        "   sub r8, r0\n"                           // curOut - out
716        "   asr r8, #2\n"                           // new outputIndex
717        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
718        "   str r8, [r0]\n"                         // save outputIndex
719
720        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
721    );
722}
723
724#endif  // ASM_ARM_RESAMP1
725
726
727// ----------------------------------------------------------------------------
728
729} // namespace android
730