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