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