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