AudioResampler.cpp revision 9e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5
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 /* if the caller requests DEFAULT_QUALITY and af.resampler.property 162 * has not been set, the target resampler quality is set to DYN_MED_QUALITY, 163 * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary 164 * due to estimated CPU load of having too many active resamplers 165 * (the code below the if). 166 */ 167 if (quality == DEFAULT_QUALITY) { 168 quality = DYN_MED_QUALITY; 169 } 170 171 // naive implementation of CPU load throttling doesn't account for whether resampler is active 172 pthread_mutex_lock(&mutex); 173 for (;;) { 174 uint32_t deltaMHz = qualityMHz(quality); 175 uint32_t newMHz = currentMHz + deltaMHz; 176 if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { 177 ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", 178 currentMHz, newMHz, deltaMHz, quality); 179 currentMHz = newMHz; 180 break; 181 } 182 // not enough CPU available for proposed quality level, so try next lowest level 183 switch (quality) { 184 default: 185 case LOW_QUALITY: 186 atFinalQuality = true; 187 break; 188 case MED_QUALITY: 189 quality = LOW_QUALITY; 190 break; 191 case HIGH_QUALITY: 192 quality = MED_QUALITY; 193 break; 194 case VERY_HIGH_QUALITY: 195 quality = HIGH_QUALITY; 196 break; 197 case DYN_LOW_QUALITY: 198 atFinalQuality = true; 199 break; 200 case DYN_MED_QUALITY: 201 quality = DYN_LOW_QUALITY; 202 break; 203 case DYN_HIGH_QUALITY: 204 quality = DYN_MED_QUALITY; 205 break; 206 } 207 } 208 pthread_mutex_unlock(&mutex); 209 210 AudioResampler* resampler; 211 212 switch (quality) { 213 default: 214 case LOW_QUALITY: 215 ALOGV("Create linear Resampler"); 216 resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate); 217 break; 218 case MED_QUALITY: 219 ALOGV("Create cubic Resampler"); 220 resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate); 221 break; 222 case HIGH_QUALITY: 223 ALOGV("Create HIGH_QUALITY sinc Resampler"); 224 resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate); 225 break; 226 case VERY_HIGH_QUALITY: 227 ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); 228 resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality); 229 break; 230 case DYN_LOW_QUALITY: 231 case DYN_MED_QUALITY: 232 case DYN_HIGH_QUALITY: 233 ALOGV("Create dynamic Resampler = %d", quality); 234 resampler = new AudioResamplerDyn(bitDepth, inChannelCount, sampleRate, quality); 235 break; 236 } 237 238 // initialize resampler 239 resampler->init(); 240 return resampler; 241} 242 243AudioResampler::AudioResampler(int bitDepth, int inChannelCount, 244 int32_t sampleRate, src_quality quality) : 245 mBitDepth(bitDepth), mChannelCount(inChannelCount), 246 mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), 247 mPhaseFraction(0), mLocalTimeFreq(0), 248 mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) { 249 // sanity check on format 250 if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) { 251 ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth, 252 inChannelCount); 253 // ALOG_ASSERT(0); 254 } 255 if (sampleRate <= 0) { 256 ALOGE("Unsupported sample rate %d Hz", sampleRate); 257 } 258 259 // initialize common members 260 mVolume[0] = mVolume[1] = 0; 261 mBuffer.frameCount = 0; 262 263} 264 265AudioResampler::~AudioResampler() { 266 pthread_mutex_lock(&mutex); 267 src_quality quality = getQuality(); 268 uint32_t deltaMHz = qualityMHz(quality); 269 int32_t newMHz = currentMHz - deltaMHz; 270 ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", 271 currentMHz, newMHz, deltaMHz, quality); 272 LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); 273 currentMHz = newMHz; 274 pthread_mutex_unlock(&mutex); 275} 276 277void AudioResampler::setSampleRate(int32_t inSampleRate) { 278 mInSampleRate = inSampleRate; 279 mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); 280} 281 282void AudioResampler::setVolume(int16_t left, int16_t right) { 283 // TODO: Implement anti-zipper filter 284 mVolume[0] = left; 285 mVolume[1] = right; 286} 287 288void AudioResampler::setLocalTimeFreq(uint64_t freq) { 289 mLocalTimeFreq = freq; 290} 291 292void AudioResampler::setPTS(int64_t pts) { 293 mPTS = pts; 294} 295 296int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) { 297 298 if (mPTS == AudioBufferProvider::kInvalidPTS) { 299 return AudioBufferProvider::kInvalidPTS; 300 } else { 301 return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate); 302 } 303} 304 305void AudioResampler::reset() { 306 mInputIndex = 0; 307 mPhaseFraction = 0; 308 mBuffer.frameCount = 0; 309} 310 311// ---------------------------------------------------------------------------- 312 313void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, 314 AudioBufferProvider* provider) { 315 316 // should never happen, but we overflow if it does 317 // ALOG_ASSERT(outFrameCount < 32767); 318 319 // select the appropriate resampler 320 switch (mChannelCount) { 321 case 1: 322 resampleMono16(out, outFrameCount, provider); 323 break; 324 case 2: 325 resampleStereo16(out, outFrameCount, provider); 326 break; 327 } 328} 329 330void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, 331 AudioBufferProvider* provider) { 332 333 int32_t vl = mVolume[0]; 334 int32_t vr = mVolume[1]; 335 336 size_t inputIndex = mInputIndex; 337 uint32_t phaseFraction = mPhaseFraction; 338 uint32_t phaseIncrement = mPhaseIncrement; 339 size_t outputIndex = 0; 340 size_t outputSampleCount = outFrameCount * 2; 341 size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; 342 343 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 344 // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 345 346 while (outputIndex < outputSampleCount) { 347 348 // buffer is empty, fetch a new one 349 while (mBuffer.frameCount == 0) { 350 mBuffer.frameCount = inFrameCount; 351 provider->getNextBuffer(&mBuffer, 352 calculateOutputPTS(outputIndex / 2)); 353 if (mBuffer.raw == NULL) { 354 goto resampleStereo16_exit; 355 } 356 357 // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 358 if (mBuffer.frameCount > inputIndex) break; 359 360 inputIndex -= mBuffer.frameCount; 361 mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 362 mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 363 provider->releaseBuffer(&mBuffer); 364 // mBuffer.frameCount == 0 now so we reload a new buffer 365 } 366 367 int16_t *in = mBuffer.i16; 368 369 // handle boundary case 370 while (inputIndex == 0) { 371 // ALOGE("boundary case"); 372 out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction); 373 out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction); 374 Advance(&inputIndex, &phaseFraction, phaseIncrement); 375 if (outputIndex == outputSampleCount) { 376 break; 377 } 378 } 379 380 // process input samples 381 // ALOGE("general case"); 382 383#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 384 if (inputIndex + 2 < mBuffer.frameCount) { 385 int32_t* maxOutPt; 386 int32_t maxInIdx; 387 388 maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop 389 maxInIdx = mBuffer.frameCount - 2; 390 AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 391 phaseFraction, phaseIncrement); 392 } 393#endif // ASM_ARM_RESAMP1 394 395 while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 396 out[outputIndex++] += vl * Interp(in[inputIndex*2-2], 397 in[inputIndex*2], phaseFraction); 398 out[outputIndex++] += vr * Interp(in[inputIndex*2-1], 399 in[inputIndex*2+1], phaseFraction); 400 Advance(&inputIndex, &phaseFraction, phaseIncrement); 401 } 402 403 // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 404 405 // if done with buffer, save samples 406 if (inputIndex >= mBuffer.frameCount) { 407 inputIndex -= mBuffer.frameCount; 408 409 // ALOGE("buffer done, new input index %d", inputIndex); 410 411 mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 412 mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 413 provider->releaseBuffer(&mBuffer); 414 415 // verify that the releaseBuffer resets the buffer frameCount 416 // ALOG_ASSERT(mBuffer.frameCount == 0); 417 } 418 } 419 420 // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 421 422resampleStereo16_exit: 423 // save state 424 mInputIndex = inputIndex; 425 mPhaseFraction = phaseFraction; 426} 427 428void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, 429 AudioBufferProvider* provider) { 430 431 int32_t vl = mVolume[0]; 432 int32_t vr = mVolume[1]; 433 434 size_t inputIndex = mInputIndex; 435 uint32_t phaseFraction = mPhaseFraction; 436 uint32_t phaseIncrement = mPhaseIncrement; 437 size_t outputIndex = 0; 438 size_t outputSampleCount = outFrameCount * 2; 439 size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; 440 441 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 442 // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 443 while (outputIndex < outputSampleCount) { 444 // buffer is empty, fetch a new one 445 while (mBuffer.frameCount == 0) { 446 mBuffer.frameCount = inFrameCount; 447 provider->getNextBuffer(&mBuffer, 448 calculateOutputPTS(outputIndex / 2)); 449 if (mBuffer.raw == NULL) { 450 mInputIndex = inputIndex; 451 mPhaseFraction = phaseFraction; 452 goto resampleMono16_exit; 453 } 454 // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 455 if (mBuffer.frameCount > inputIndex) break; 456 457 inputIndex -= mBuffer.frameCount; 458 mX0L = mBuffer.i16[mBuffer.frameCount-1]; 459 provider->releaseBuffer(&mBuffer); 460 // mBuffer.frameCount == 0 now so we reload a new buffer 461 } 462 int16_t *in = mBuffer.i16; 463 464 // handle boundary case 465 while (inputIndex == 0) { 466 // ALOGE("boundary case"); 467 int32_t sample = Interp(mX0L, in[0], phaseFraction); 468 out[outputIndex++] += vl * sample; 469 out[outputIndex++] += vr * sample; 470 Advance(&inputIndex, &phaseFraction, phaseIncrement); 471 if (outputIndex == outputSampleCount) { 472 break; 473 } 474 } 475 476 // process input samples 477 // ALOGE("general case"); 478 479#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 480 if (inputIndex + 2 < mBuffer.frameCount) { 481 int32_t* maxOutPt; 482 int32_t maxInIdx; 483 484 maxOutPt = out + (outputSampleCount - 2); 485 maxInIdx = (int32_t)mBuffer.frameCount - 2; 486 AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 487 phaseFraction, phaseIncrement); 488 } 489#endif // ASM_ARM_RESAMP1 490 491 while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 492 int32_t sample = Interp(in[inputIndex-1], in[inputIndex], 493 phaseFraction); 494 out[outputIndex++] += vl * sample; 495 out[outputIndex++] += vr * sample; 496 Advance(&inputIndex, &phaseFraction, phaseIncrement); 497 } 498 499 500 // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 501 502 // if done with buffer, save samples 503 if (inputIndex >= mBuffer.frameCount) { 504 inputIndex -= mBuffer.frameCount; 505 506 // ALOGE("buffer done, new input index %d", inputIndex); 507 508 mX0L = mBuffer.i16[mBuffer.frameCount-1]; 509 provider->releaseBuffer(&mBuffer); 510 511 // verify that the releaseBuffer resets the buffer frameCount 512 // ALOG_ASSERT(mBuffer.frameCount == 0); 513 } 514 } 515 516 // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 517 518resampleMono16_exit: 519 // save state 520 mInputIndex = inputIndex; 521 mPhaseFraction = phaseFraction; 522} 523 524#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 525 526/******************************************************************* 527* 528* AsmMono16Loop 529* asm optimized monotonic loop version; one loop is 2 frames 530* Input: 531* in : pointer on input samples 532* maxOutPt : pointer on first not filled 533* maxInIdx : index on first not used 534* outputIndex : pointer on current output index 535* out : pointer on output buffer 536* inputIndex : pointer on current input index 537* vl, vr : left and right gain 538* phaseFraction : pointer on current phase fraction 539* phaseIncrement 540* Ouput: 541* outputIndex : 542* out : updated buffer 543* inputIndex : index of next to use 544* phaseFraction : phase fraction for next interpolation 545* 546*******************************************************************/ 547__attribute__((noinline)) 548void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 549 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 550 uint32_t &phaseFraction, uint32_t phaseIncrement) 551{ 552 (void)maxOutPt; // remove unused parameter warnings 553 (void)maxInIdx; 554 (void)outputIndex; 555 (void)out; 556 (void)inputIndex; 557 (void)vl; 558 (void)vr; 559 (void)phaseFraction; 560 (void)phaseIncrement; 561 (void)in; 562#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) 563 564 asm( 565 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" 566 // get parameters 567 " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 568 " ldr r6, [r6]\n" // phaseFraction 569 " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 570 " ldr r7, [r7]\n" // inputIndex 571 " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out 572 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 573 " ldr r0, [r0]\n" // outputIndex 574 " add r8, r0, asl #2\n" // curOut 575 " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement 576 " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl 577 " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr 578 579 // r0 pin, x0, Samp 580 581 // r1 in 582 // r2 maxOutPt 583 // r3 maxInIdx 584 585 // r4 x1, i1, i3, Out1 586 // r5 out0 587 588 // r6 frac 589 // r7 inputIndex 590 // r8 curOut 591 592 // r9 inc 593 // r10 vl 594 // r11 vr 595 596 // r12 597 // r13 sp 598 // r14 599 600 // the following loop works on 2 frames 601 602 "1:\n" 603 " cmp r8, r2\n" // curOut - maxCurOut 604 " bcs 2f\n" 605 606#define MO_ONE_FRAME \ 607 " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ 608 " ldrsh r4, [r0]\n" /* in[inputIndex] */\ 609 " ldr r5, [r8]\n" /* out[outputIndex] */\ 610 " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ 611 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 612 " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ 613 " mov r4, r4, lsl #2\n" /* <<2 */\ 614 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 615 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 616 " add r0, r0, r4\n" /* x0 - (..) */\ 617 " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ 618 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 619 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 620 " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ 621 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ 622 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ 623 624 MO_ONE_FRAME // frame 1 625 MO_ONE_FRAME // frame 2 626 627 " cmp r7, r3\n" // inputIndex - maxInIdx 628 " bcc 1b\n" 629 "2:\n" 630 631 " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 632 // save modified values 633 " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 634 " str r6, [r0]\n" // phaseFraction 635 " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 636 " str r7, [r0]\n" // inputIndex 637 " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out 638 " sub r8, r0\n" // curOut - out 639 " asr r8, #2\n" // new outputIndex 640 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 641 " str r8, [r0]\n" // save outputIndex 642 643 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" 644 ); 645} 646 647/******************************************************************* 648* 649* AsmStereo16Loop 650* asm optimized stereo loop version; one loop is 2 frames 651* Input: 652* in : pointer on input samples 653* maxOutPt : pointer on first not filled 654* maxInIdx : index on first not used 655* outputIndex : pointer on current output index 656* out : pointer on output buffer 657* inputIndex : pointer on current input index 658* vl, vr : left and right gain 659* phaseFraction : pointer on current phase fraction 660* phaseIncrement 661* Ouput: 662* outputIndex : 663* out : updated buffer 664* inputIndex : index of next to use 665* phaseFraction : phase fraction for next interpolation 666* 667*******************************************************************/ 668__attribute__((noinline)) 669void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 670 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 671 uint32_t &phaseFraction, uint32_t phaseIncrement) 672{ 673 (void)maxOutPt; // remove unused parameter warnings 674 (void)maxInIdx; 675 (void)outputIndex; 676 (void)out; 677 (void)inputIndex; 678 (void)vl; 679 (void)vr; 680 (void)phaseFraction; 681 (void)phaseIncrement; 682 (void)in; 683#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) 684 asm( 685 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" 686 // get parameters 687 " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 688 " ldr r6, [r6]\n" // phaseFraction 689 " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 690 " ldr r7, [r7]\n" // inputIndex 691 " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out 692 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 693 " ldr r0, [r0]\n" // outputIndex 694 " add r8, r0, asl #2\n" // curOut 695 " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement 696 " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl 697 " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr 698 699 // r0 pin, x0, Samp 700 701 // r1 in 702 // r2 maxOutPt 703 // r3 maxInIdx 704 705 // r4 x1, i1, i3, out1 706 // r5 out0 707 708 // r6 frac 709 // r7 inputIndex 710 // r8 curOut 711 712 // r9 inc 713 // r10 vl 714 // r11 vr 715 716 // r12 temporary 717 // r13 sp 718 // r14 719 720 "3:\n" 721 " cmp r8, r2\n" // curOut - maxCurOut 722 " bcs 4f\n" 723 724#define ST_ONE_FRAME \ 725 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 726\ 727 " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ 728\ 729 " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ 730 " ldr r5, [r8]\n" /* out[outputIndex] */\ 731 " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ 732 " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 733 " mov r4, r4, lsl #2\n" /* <<2 */\ 734 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 735 " add r12, r12, r4\n" /* x0 - (..) */\ 736 " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ 737 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 738 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 739\ 740 " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ 741 " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ 742 " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 743 " mov r12, r12, lsl #2\n" /* <<2 */\ 744 " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ 745 " add r12, r0, r12\n" /* x0 - (..) */\ 746 " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ 747 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ 748\ 749 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 750 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ 751 752 ST_ONE_FRAME // frame 1 753 ST_ONE_FRAME // frame 1 754 755 " cmp r7, r3\n" // inputIndex - maxInIdx 756 " bcc 3b\n" 757 "4:\n" 758 759 " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 760 // save modified values 761 " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 762 " str r6, [r0]\n" // phaseFraction 763 " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 764 " str r7, [r0]\n" // inputIndex 765 " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out 766 " sub r8, r0\n" // curOut - out 767 " asr r8, #2\n" // new outputIndex 768 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 769 " str r8, [r0]\n" // save outputIndex 770 771 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" 772 ); 773} 774 775#endif // ASM_ARM_RESAMP1 776 777 778// ---------------------------------------------------------------------------- 779 780} // namespace android 781