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