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 #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 
     98 static pthread_once_t once_control = PTHREAD_ONCE_INIT;
     99 static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY;
    100 
    101 void 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 
    117 uint32_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 
    133 static const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable
    134 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
    135 static uint32_t currentMHz = 0;
    136 
    137 AudioResampler* 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 
    214 AudioResampler::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 
    236 AudioResampler::~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 
    248 void AudioResampler::setSampleRate(int32_t inSampleRate) {
    249     mInSampleRate = inSampleRate;
    250     mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
    251 }
    252 
    253 void AudioResampler::setVolume(int16_t left, int16_t right) {
    254     // TODO: Implement anti-zipper filter
    255     mVolume[0] = left;
    256     mVolume[1] = right;
    257 }
    258 
    259 void AudioResampler::setLocalTimeFreq(uint64_t freq) {
    260     mLocalTimeFreq = freq;
    261 }
    262 
    263 void AudioResampler::setPTS(int64_t pts) {
    264     mPTS = pts;
    265 }
    266 
    267 int64_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 
    276 void AudioResampler::reset() {
    277     mInputIndex = 0;
    278     mPhaseFraction = 0;
    279     mBuffer.frameCount = 0;
    280 }
    281 
    282 // ----------------------------------------------------------------------------
    283 
    284 void 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 
    301 void 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 
    392 resampleStereo16_exit:
    393     // save state
    394     mInputIndex = inputIndex;
    395     mPhaseFraction = phaseFraction;
    396 }
    397 
    398 void 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 
    487 resampleMono16_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))
    517 void 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))
    628 void 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