• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
AudioResamplerOrder1(int bitDepth,int inChannelCount,int32_t sampleRate)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 
init()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 
Interp(int32_t x0,int32_t x1,uint32_t f)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     }
Advance(size_t * index,uint32_t * frac,uint32_t inc)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 
qualityIsSupported(src_quality quality)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 
init_routine()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 
qualityMHz(src_quality quality)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 
create(int bitDepth,int inChannelCount,int32_t sampleRate,src_quality quality)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 
AudioResampler(int bitDepth,int inChannelCount,int32_t sampleRate,src_quality quality)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 
~AudioResampler()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 
setSampleRate(int32_t inSampleRate)244 void AudioResampler::setSampleRate(int32_t inSampleRate) {
245     mInSampleRate = inSampleRate;
246     mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
247 }
248 
setVolume(int16_t left,int16_t right)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 
setLocalTimeFreq(uint64_t freq)255 void AudioResampler::setLocalTimeFreq(uint64_t freq) {
256     mLocalTimeFreq = freq;
257 }
258 
setPTS(int64_t pts)259 void AudioResampler::setPTS(int64_t pts) {
260     mPTS = pts;
261 }
262 
calculateOutputPTS(int outputFrameIndex)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 
reset()272 void AudioResampler::reset() {
273     mInputIndex = 0;
274     mPhaseFraction = 0;
275     mBuffer.frameCount = 0;
276 }
277 
278 // ----------------------------------------------------------------------------
279 
resample(int32_t * out,size_t outFrameCount,AudioBufferProvider * provider)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 
resampleStereo16(int32_t * out,size_t outFrameCount,AudioBufferProvider * provider)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 
resampleMono16(int32_t * out,size_t outFrameCount,AudioBufferProvider * provider)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))
AsmMono16Loop(int16_t * in,int32_t * maxOutPt,int32_t maxInIdx,size_t & outputIndex,int32_t * out,size_t & inputIndex,int32_t vl,int32_t vr,uint32_t & phaseFraction,uint32_t phaseIncrement)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))
AsmStereo16Loop(int16_t * in,int32_t * maxOutPt,int32_t maxInIdx,size_t & outputIndex,int32_t * out,size_t & inputIndex,int32_t vl,int32_t vr,uint32_t & phaseFraction,uint32_t phaseIncrement)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