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