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