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