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: 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 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 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 } 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 // ---------------------------------------------------------------------------- 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 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 137 AudioResampler::~AudioResampler() { 138 } 139 140 void AudioResampler::setSampleRate(int32_t inSampleRate) { 141 mInSampleRate = inSampleRate; 142 mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); 143 } 144 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 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 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 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 *******************************************************************/ 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 *******************************************************************/ 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