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