Home | History | Annotate | Download | only in audioflinger
      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 namespace android {
     30 
     31 #ifdef __ARM_ARCH_5E__  // optimized asm option
     32     #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
     33 #endif // __ARM_ARCH_5E__
     34 // ----------------------------------------------------------------------------
     35 
     36 class AudioResamplerOrder1 : public AudioResampler {
     37 public:
     38     AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
     39         AudioResampler(bitDepth, inChannelCount, sampleRate), mX0L(0), mX0R(0) {
     40     }
     41     virtual void resample(int32_t* out, size_t outFrameCount,
     42             AudioBufferProvider* provider);
     43 private:
     44     // number of bits used in interpolation multiply - 15 bits avoids overflow
     45     static const int kNumInterpBits = 15;
     46 
     47     // bits to shift the phase fraction down to avoid overflow
     48     static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
     49 
     50     void init() {}
     51     void resampleMono16(int32_t* out, size_t outFrameCount,
     52             AudioBufferProvider* provider);
     53     void resampleStereo16(int32_t* out, size_t outFrameCount,
     54             AudioBufferProvider* provider);
     55 #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
     56     void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
     57             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
     58             uint32_t &phaseFraction, uint32_t phaseIncrement);
     59     void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
     60             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
     61             uint32_t &phaseFraction, uint32_t phaseIncrement);
     62 #endif  // ASM_ARM_RESAMP1
     63 
     64     static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
     65         return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
     66     }
     67     static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
     68         *frac += inc;
     69         *index += (size_t)(*frac >> kNumPhaseBits);
     70         *frac &= kPhaseMask;
     71     }
     72     int mX0L;
     73     int mX0R;
     74 };
     75 
     76 // ----------------------------------------------------------------------------
     77 AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
     78         int32_t sampleRate, int quality) {
     79 
     80     // can only create low quality resample now
     81     AudioResampler* resampler;
     82 
     83     char value[PROPERTY_VALUE_MAX];
     84     if (property_get("af.resampler.quality", value, 0)) {
     85         quality = atoi(value);
     86         LOGD("forcing AudioResampler quality to %d", quality);
     87     }
     88 
     89     if (quality == DEFAULT)
     90         quality = LOW_QUALITY;
     91 
     92     switch (quality) {
     93     default:
     94     case LOW_QUALITY:
     95         LOGV("Create linear Resampler");
     96         resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
     97         break;
     98     case MED_QUALITY:
     99         LOGV("Create cubic Resampler");
    100         resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
    101         break;
    102     case HIGH_QUALITY:
    103         LOGV("Create sinc Resampler");
    104         resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
    105         break;
    106     }
    107 
    108     // initialize resampler
    109     resampler->init();
    110     return resampler;
    111 }
    112 
    113 AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
    114         int32_t sampleRate) :
    115     mBitDepth(bitDepth), mChannelCount(inChannelCount),
    116             mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
    117             mPhaseFraction(0) {
    118     // sanity check on format
    119     if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
    120         LOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
    121                 inChannelCount);
    122         // LOG_ASSERT(0);
    123     }
    124 
    125     // initialize common members
    126     mVolume[0] = mVolume[1] = 0;
    127     mBuffer.frameCount = 0;
    128 
    129     // save format for quick lookup
    130     if (inChannelCount == 1) {
    131         mFormat = MONO_16_BIT;
    132     } else {
    133         mFormat = STEREO_16_BIT;
    134     }
    135 }
    136 
    137 AudioResampler::~AudioResampler() {
    138 }
    139 
    140 void AudioResampler::setSampleRate(int32_t inSampleRate) {
    141     mInSampleRate = inSampleRate;
    142     mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
    143 }
    144 
    145 void AudioResampler::setVolume(int16_t left, int16_t right) {
    146     // TODO: Implement anti-zipper filter
    147     mVolume[0] = left;
    148     mVolume[1] = right;
    149 }
    150 
    151 // ----------------------------------------------------------------------------
    152 
    153 void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
    154         AudioBufferProvider* provider) {
    155 
    156     // should never happen, but we overflow if it does
    157     // LOG_ASSERT(outFrameCount < 32767);
    158 
    159     // select the appropriate resampler
    160     switch (mChannelCount) {
    161     case 1:
    162         resampleMono16(out, outFrameCount, provider);
    163         break;
    164     case 2:
    165         resampleStereo16(out, outFrameCount, provider);
    166         break;
    167     }
    168 }
    169 
    170 void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
    171         AudioBufferProvider* provider) {
    172 
    173     int32_t vl = mVolume[0];
    174     int32_t vr = mVolume[1];
    175 
    176     size_t inputIndex = mInputIndex;
    177     uint32_t phaseFraction = mPhaseFraction;
    178     uint32_t phaseIncrement = mPhaseIncrement;
    179     size_t outputIndex = 0;
    180     size_t outputSampleCount = outFrameCount * 2;
    181     size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
    182 
    183     // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
    184     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
    185 
    186     while (outputIndex < outputSampleCount) {
    187 
    188         // buffer is empty, fetch a new one
    189         while (mBuffer.frameCount == 0) {
    190             mBuffer.frameCount = inFrameCount;
    191             provider->getNextBuffer(&mBuffer);
    192             if (mBuffer.raw == NULL) {
    193                 goto resampleStereo16_exit;
    194             }
    195 
    196             // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
    197             if (mBuffer.frameCount > inputIndex) break;
    198 
    199             inputIndex -= mBuffer.frameCount;
    200             mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
    201             mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
    202             provider->releaseBuffer(&mBuffer);
    203              // mBuffer.frameCount == 0 now so we reload a new buffer
    204         }
    205 
    206         int16_t *in = mBuffer.i16;
    207 
    208         // handle boundary case
    209         while (inputIndex == 0) {
    210             // LOGE("boundary case\n");
    211             out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
    212             out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
    213             Advance(&inputIndex, &phaseFraction, phaseIncrement);
    214             if (outputIndex == outputSampleCount)
    215                 break;
    216         }
    217 
    218         // process input samples
    219         // LOGE("general case\n");
    220 
    221 #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
    222         if (inputIndex + 2 < mBuffer.frameCount) {
    223             int32_t* maxOutPt;
    224             int32_t maxInIdx;
    225 
    226             maxOutPt = out + (outputSampleCount - 2);   // 2 because 2 frames per loop
    227             maxInIdx = mBuffer.frameCount - 2;
    228             AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
    229                     phaseFraction, phaseIncrement);
    230         }
    231 #endif  // ASM_ARM_RESAMP1
    232 
    233         while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
    234             out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
    235                     in[inputIndex*2], phaseFraction);
    236             out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
    237                     in[inputIndex*2+1], phaseFraction);
    238             Advance(&inputIndex, &phaseFraction, phaseIncrement);
    239         }
    240 
    241         // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
    242 
    243         // if done with buffer, save samples
    244         if (inputIndex >= mBuffer.frameCount) {
    245             inputIndex -= mBuffer.frameCount;
    246 
    247             // LOGE("buffer done, new input index %d", inputIndex);
    248 
    249             mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
    250             mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
    251             provider->releaseBuffer(&mBuffer);
    252 
    253             // verify that the releaseBuffer resets the buffer frameCount
    254             // LOG_ASSERT(mBuffer.frameCount == 0);
    255         }
    256     }
    257 
    258     // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
    259 
    260 resampleStereo16_exit:
    261     // save state
    262     mInputIndex = inputIndex;
    263     mPhaseFraction = phaseFraction;
    264 }
    265 
    266 void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
    267         AudioBufferProvider* provider) {
    268 
    269     int32_t vl = mVolume[0];
    270     int32_t vr = mVolume[1];
    271 
    272     size_t inputIndex = mInputIndex;
    273     uint32_t phaseFraction = mPhaseFraction;
    274     uint32_t phaseIncrement = mPhaseIncrement;
    275     size_t outputIndex = 0;
    276     size_t outputSampleCount = outFrameCount * 2;
    277     size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
    278 
    279     // LOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d\n",
    280     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
    281     while (outputIndex < outputSampleCount) {
    282         // buffer is empty, fetch a new one
    283         while (mBuffer.frameCount == 0) {
    284             mBuffer.frameCount = inFrameCount;
    285             provider->getNextBuffer(&mBuffer);
    286             if (mBuffer.raw == NULL) {
    287                 mInputIndex = inputIndex;
    288                 mPhaseFraction = phaseFraction;
    289                 goto resampleMono16_exit;
    290             }
    291             // LOGE("New buffer fetched: %d frames\n", mBuffer.frameCount);
    292             if (mBuffer.frameCount >  inputIndex) break;
    293 
    294             inputIndex -= mBuffer.frameCount;
    295             mX0L = mBuffer.i16[mBuffer.frameCount-1];
    296             provider->releaseBuffer(&mBuffer);
    297             // mBuffer.frameCount == 0 now so we reload a new buffer
    298         }
    299         int16_t *in = mBuffer.i16;
    300 
    301         // handle boundary case
    302         while (inputIndex == 0) {
    303             // LOGE("boundary case\n");
    304             int32_t sample = Interp(mX0L, in[0], phaseFraction);
    305             out[outputIndex++] += vl * sample;
    306             out[outputIndex++] += vr * sample;
    307             Advance(&inputIndex, &phaseFraction, phaseIncrement);
    308             if (outputIndex == outputSampleCount)
    309                 break;
    310         }
    311 
    312         // process input samples
    313         // LOGE("general case\n");
    314 
    315 #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
    316         if (inputIndex + 2 < mBuffer.frameCount) {
    317             int32_t* maxOutPt;
    318             int32_t maxInIdx;
    319 
    320             maxOutPt = out + (outputSampleCount - 2);
    321             maxInIdx = (int32_t)mBuffer.frameCount - 2;
    322                 AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
    323                         phaseFraction, phaseIncrement);
    324         }
    325 #endif  // ASM_ARM_RESAMP1
    326 
    327         while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
    328             int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
    329                     phaseFraction);
    330             out[outputIndex++] += vl * sample;
    331             out[outputIndex++] += vr * sample;
    332             Advance(&inputIndex, &phaseFraction, phaseIncrement);
    333         }
    334 
    335 
    336         // LOGE("loop done - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
    337 
    338         // if done with buffer, save samples
    339         if (inputIndex >= mBuffer.frameCount) {
    340             inputIndex -= mBuffer.frameCount;
    341 
    342             // LOGE("buffer done, new input index %d", inputIndex);
    343 
    344             mX0L = mBuffer.i16[mBuffer.frameCount-1];
    345             provider->releaseBuffer(&mBuffer);
    346 
    347             // verify that the releaseBuffer resets the buffer frameCount
    348             // LOG_ASSERT(mBuffer.frameCount == 0);
    349         }
    350     }
    351 
    352     // LOGE("output buffer full - outputIndex=%d, inputIndex=%d\n", outputIndex, inputIndex);
    353 
    354 resampleMono16_exit:
    355     // save state
    356     mInputIndex = inputIndex;
    357     mPhaseFraction = phaseFraction;
    358 }
    359 
    360 #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
    361 
    362 /*******************************************************************
    363 *
    364 *   AsmMono16Loop
    365 *   asm optimized monotonic loop version; one loop is 2 frames
    366 *   Input:
    367 *       in : pointer on input samples
    368 *       maxOutPt : pointer on first not filled
    369 *       maxInIdx : index on first not used
    370 *       outputIndex : pointer on current output index
    371 *       out : pointer on output buffer
    372 *       inputIndex : pointer on current input index
    373 *       vl, vr : left and right gain
    374 *       phaseFraction : pointer on current phase fraction
    375 *       phaseIncrement
    376 *   Ouput:
    377 *       outputIndex :
    378 *       out : updated buffer
    379 *       inputIndex : index of next to use
    380 *       phaseFraction : phase fraction for next interpolation
    381 *
    382 *******************************************************************/
    383 void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
    384             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
    385             uint32_t &phaseFraction, uint32_t phaseIncrement)
    386 {
    387 #define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
    388 
    389     asm(
    390         "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
    391         // get parameters
    392         "   ldr r6, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
    393         "   ldr r6, [r6]\n"                         // phaseFraction
    394         "   ldr r7, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
    395         "   ldr r7, [r7]\n"                         // inputIndex
    396         "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
    397         "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
    398         "   ldr r0, [r0]\n"                         // outputIndex
    399         "   add r8, r0, asl #2\n"                   // curOut
    400         "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
    401         "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
    402         "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
    403 
    404         // r0 pin, x0, Samp
    405 
    406         // r1 in
    407         // r2 maxOutPt
    408         // r3 maxInIdx
    409 
    410         // r4 x1, i1, i3, Out1
    411         // r5 out0
    412 
    413         // r6 frac
    414         // r7 inputIndex
    415         // r8 curOut
    416 
    417         // r9 inc
    418         // r10 vl
    419         // r11 vr
    420 
    421         // r12
    422         // r13 sp
    423         // r14
    424 
    425         // the following loop works on 2 frames
    426 
    427         ".Y4L01:\n"
    428         "   cmp r8, r2\n"                   // curOut - maxCurOut
    429         "   bcs .Y4L02\n"
    430 
    431 #define MO_ONE_FRAME \
    432     "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
    433     "   ldrsh r4, [r0]\n"               /* in[inputIndex] */\
    434     "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
    435     "   ldrsh r0, [r0, #-2]\n"          /* in[inputIndex-1] */\
    436     "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
    437     "   sub r4, r4, r0\n"               /* in[inputIndex] - in[inputIndex-1] */\
    438     "   mov r4, r4, lsl #2\n"           /* <<2 */\
    439     "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
    440     "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
    441     "   add r0, r0, r4\n"               /* x0 - (..) */\
    442     "   mla r5, r0, r10, r5\n"          /* vl*interp + out[] */\
    443     "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
    444     "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
    445     "   mla r4, r0, r11, r4\n"          /* vr*interp + out[] */\
    446     "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */\
    447     "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */
    448 
    449         MO_ONE_FRAME    // frame 1
    450         MO_ONE_FRAME    // frame 2
    451 
    452         "   cmp r7, r3\n"                   // inputIndex - maxInIdx
    453         "   bcc .Y4L01\n"
    454         ".Y4L02:\n"
    455 
    456         "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
    457         // save modified values
    458         "   ldr r0, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
    459         "   str r6, [r0]\n"                         // phaseFraction
    460         "   ldr r0, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
    461         "   str r7, [r0]\n"                         // inputIndex
    462         "   ldr r0, [sp, #" MO_PARAM5 " + 4]\n"     // out
    463         "   sub r8, r0\n"                           // curOut - out
    464         "   asr r8, #2\n"                           // new outputIndex
    465         "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
    466         "   str r8, [r0]\n"                         // save outputIndex
    467 
    468         "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
    469     );
    470 }
    471 
    472 /*******************************************************************
    473 *
    474 *   AsmStereo16Loop
    475 *   asm optimized stereo loop version; one loop is 2 frames
    476 *   Input:
    477 *       in : pointer on input samples
    478 *       maxOutPt : pointer on first not filled
    479 *       maxInIdx : index on first not used
    480 *       outputIndex : pointer on current output index
    481 *       out : pointer on output buffer
    482 *       inputIndex : pointer on current input index
    483 *       vl, vr : left and right gain
    484 *       phaseFraction : pointer on current phase fraction
    485 *       phaseIncrement
    486 *   Ouput:
    487 *       outputIndex :
    488 *       out : updated buffer
    489 *       inputIndex : index of next to use
    490 *       phaseFraction : phase fraction for next interpolation
    491 *
    492 *******************************************************************/
    493 void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
    494             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
    495             uint32_t &phaseFraction, uint32_t phaseIncrement)
    496 {
    497 #define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
    498     asm(
    499         "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
    500         // get parameters
    501         "   ldr r6, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
    502         "   ldr r6, [r6]\n"                         // phaseFraction
    503         "   ldr r7, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
    504         "   ldr r7, [r7]\n"                         // inputIndex
    505         "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
    506         "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
    507         "   ldr r0, [r0]\n"                         // outputIndex
    508         "   add r8, r0, asl #2\n"                   // curOut
    509         "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
    510         "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
    511         "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
    512 
    513         // r0 pin, x0, Samp
    514 
    515         // r1 in
    516         // r2 maxOutPt
    517         // r3 maxInIdx
    518 
    519         // r4 x1, i1, i3, out1
    520         // r5 out0
    521 
    522         // r6 frac
    523         // r7 inputIndex
    524         // r8 curOut
    525 
    526         // r9 inc
    527         // r10 vl
    528         // r11 vr
    529 
    530         // r12 temporary
    531         // r13 sp
    532         // r14
    533 
    534         ".Y5L01:\n"
    535         "   cmp r8, r2\n"                   // curOut - maxCurOut
    536         "   bcs .Y5L02\n"
    537 
    538 #define ST_ONE_FRAME \
    539     "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
    540 \
    541     "   add r0, r1, r7, asl #2\n"       /* in + 2*inputIndex */\
    542 \
    543     "   ldrsh r4, [r0]\n"               /* in[2*inputIndex] */\
    544     "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
    545     "   ldrsh r12, [r0, #-4]\n"         /* in[2*inputIndex-2] */\
    546     "   sub r4, r4, r12\n"              /* in[2*InputIndex] - in[2*InputIndex-2] */\
    547     "   mov r4, r4, lsl #2\n"           /* <<2 */\
    548     "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
    549     "   add r12, r12, r4\n"             /* x0 - (..) */\
    550     "   mla r5, r12, r10, r5\n"         /* vl*interp + out[] */\
    551     "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
    552     "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
    553 \
    554     "   ldrsh r12, [r0, #+2]\n"         /* in[2*inputIndex+1] */\
    555     "   ldrsh r0, [r0, #-2]\n"          /* in[2*inputIndex-1] */\
    556     "   sub r12, r12, r0\n"             /* in[2*InputIndex] - in[2*InputIndex-2] */\
    557     "   mov r12, r12, lsl #2\n"         /* <<2 */\
    558     "   smulwt r12, r12, r6\n"          /* (x1-x0)*.. */\
    559     "   add r12, r0, r12\n"             /* x0 - (..) */\
    560     "   mla r4, r12, r11, r4\n"         /* vr*interp + out[] */\
    561     "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */\
    562 \
    563     "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
    564     "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */
    565 
    566     ST_ONE_FRAME    // frame 1
    567     ST_ONE_FRAME    // frame 1
    568 
    569         "   cmp r7, r3\n"                       // inputIndex - maxInIdx
    570         "   bcc .Y5L01\n"
    571         ".Y5L02:\n"
    572 
    573         "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
    574         // save modified values
    575         "   ldr r0, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
    576         "   str r6, [r0]\n"                         // phaseFraction
    577         "   ldr r0, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
    578         "   str r7, [r0]\n"                         // inputIndex
    579         "   ldr r0, [sp, #" ST_PARAM5 " + 4]\n"     // out
    580         "   sub r8, r0\n"                           // curOut - out
    581         "   asr r8, #2\n"                           // new outputIndex
    582         "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
    583         "   str r8, [r0]\n"                         // save outputIndex
    584 
    585         "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
    586     );
    587 }
    588 
    589 #endif  // ASM_ARM_RESAMP1
    590 
    591 
    592 // ----------------------------------------------------------------------------
    593 }
    594 ; // namespace android
    595 
    596