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