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