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 <audio_utils/primitives.h> 26 #include "AudioResampler.h" 27 #include "AudioResamplerSinc.h" 28 #include "AudioResamplerCubic.h" 29 #include "AudioResamplerDyn.h" 30 31 #ifdef __arm__ 32 // bug 13102576 33 //#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 34 #endif 35 36 namespace android { 37 38 // ---------------------------------------------------------------------------- 39 40 class AudioResamplerOrder1 : public AudioResampler { 41 public: 42 AudioResamplerOrder1(int inChannelCount, int32_t sampleRate) : 43 AudioResampler(inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { 44 } 45 virtual size_t resample(int32_t* out, size_t outFrameCount, 46 AudioBufferProvider* provider); 47 private: 48 // number of bits used in interpolation multiply - 15 bits avoids overflow 49 static const int kNumInterpBits = 15; 50 51 // bits to shift the phase fraction down to avoid overflow 52 static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; 53 54 void init() {} 55 size_t resampleMono16(int32_t* out, size_t outFrameCount, 56 AudioBufferProvider* provider); 57 size_t resampleStereo16(int32_t* out, size_t outFrameCount, 58 AudioBufferProvider* provider); 59 #ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 60 void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 61 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 62 uint32_t &phaseFraction, uint32_t phaseIncrement); 63 void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 64 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 65 uint32_t &phaseFraction, uint32_t phaseIncrement); 66 #endif // ASM_ARM_RESAMP1 67 68 static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) { 69 return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits); 70 } 71 static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) { 72 *frac += inc; 73 *index += (size_t)(*frac >> kNumPhaseBits); 74 *frac &= kPhaseMask; 75 } 76 int mX0L; 77 int mX0R; 78 }; 79 80 /*static*/ 81 const double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits; 82 83 bool AudioResampler::qualityIsSupported(src_quality quality) 84 { 85 switch (quality) { 86 case DEFAULT_QUALITY: 87 case LOW_QUALITY: 88 case MED_QUALITY: 89 case HIGH_QUALITY: 90 case VERY_HIGH_QUALITY: 91 case DYN_LOW_QUALITY: 92 case DYN_MED_QUALITY: 93 case DYN_HIGH_QUALITY: 94 return true; 95 default: 96 return false; 97 } 98 } 99 100 // ---------------------------------------------------------------------------- 101 102 static pthread_once_t once_control = PTHREAD_ONCE_INIT; 103 static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY; 104 105 void AudioResampler::init_routine() 106 { 107 char value[PROPERTY_VALUE_MAX]; 108 if (property_get("af.resampler.quality", value, NULL) > 0) { 109 char *endptr; 110 unsigned long l = strtoul(value, &endptr, 0); 111 if (*endptr == '\0') { 112 defaultQuality = (src_quality) l; 113 ALOGD("forcing AudioResampler quality to %d", defaultQuality); 114 if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) { 115 defaultQuality = DEFAULT_QUALITY; 116 } 117 } 118 } 119 } 120 121 uint32_t AudioResampler::qualityMHz(src_quality quality) 122 { 123 switch (quality) { 124 default: 125 case DEFAULT_QUALITY: 126 case LOW_QUALITY: 127 return 3; 128 case MED_QUALITY: 129 return 6; 130 case HIGH_QUALITY: 131 return 20; 132 case VERY_HIGH_QUALITY: 133 return 34; 134 case DYN_LOW_QUALITY: 135 return 4; 136 case DYN_MED_QUALITY: 137 return 6; 138 case DYN_HIGH_QUALITY: 139 return 12; 140 } 141 } 142 143 static const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable 144 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 145 static uint32_t currentMHz = 0; 146 147 AudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount, 148 int32_t sampleRate, src_quality quality) { 149 150 bool atFinalQuality; 151 if (quality == DEFAULT_QUALITY) { 152 // read the resampler default quality property the first time it is needed 153 int ok = pthread_once(&once_control, init_routine); 154 if (ok != 0) { 155 ALOGE("%s pthread_once failed: %d", __func__, ok); 156 } 157 quality = defaultQuality; 158 atFinalQuality = false; 159 } else { 160 atFinalQuality = true; 161 } 162 163 /* if the caller requests DEFAULT_QUALITY and af.resampler.property 164 * has not been set, the target resampler quality is set to DYN_MED_QUALITY, 165 * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary 166 * due to estimated CPU load of having too many active resamplers 167 * (the code below the if). 168 */ 169 if (quality == DEFAULT_QUALITY) { 170 quality = DYN_MED_QUALITY; 171 } 172 173 // naive implementation of CPU load throttling doesn't account for whether resampler is active 174 pthread_mutex_lock(&mutex); 175 for (;;) { 176 uint32_t deltaMHz = qualityMHz(quality); 177 uint32_t newMHz = currentMHz + deltaMHz; 178 if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { 179 ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", 180 currentMHz, newMHz, deltaMHz, quality); 181 currentMHz = newMHz; 182 break; 183 } 184 // not enough CPU available for proposed quality level, so try next lowest level 185 switch (quality) { 186 default: 187 case LOW_QUALITY: 188 atFinalQuality = true; 189 break; 190 case MED_QUALITY: 191 quality = LOW_QUALITY; 192 break; 193 case HIGH_QUALITY: 194 quality = MED_QUALITY; 195 break; 196 case VERY_HIGH_QUALITY: 197 quality = HIGH_QUALITY; 198 break; 199 case DYN_LOW_QUALITY: 200 atFinalQuality = true; 201 break; 202 case DYN_MED_QUALITY: 203 quality = DYN_LOW_QUALITY; 204 break; 205 case DYN_HIGH_QUALITY: 206 quality = DYN_MED_QUALITY; 207 break; 208 } 209 } 210 pthread_mutex_unlock(&mutex); 211 212 AudioResampler* resampler; 213 214 switch (quality) { 215 default: 216 case LOW_QUALITY: 217 ALOGV("Create linear Resampler"); 218 LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 219 resampler = new AudioResamplerOrder1(inChannelCount, sampleRate); 220 break; 221 case MED_QUALITY: 222 ALOGV("Create cubic Resampler"); 223 LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 224 resampler = new AudioResamplerCubic(inChannelCount, sampleRate); 225 break; 226 case HIGH_QUALITY: 227 ALOGV("Create HIGH_QUALITY sinc Resampler"); 228 LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 229 resampler = new AudioResamplerSinc(inChannelCount, sampleRate); 230 break; 231 case VERY_HIGH_QUALITY: 232 ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); 233 LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 234 resampler = new AudioResamplerSinc(inChannelCount, sampleRate, quality); 235 break; 236 case DYN_LOW_QUALITY: 237 case DYN_MED_QUALITY: 238 case DYN_HIGH_QUALITY: 239 ALOGV("Create dynamic Resampler = %d", quality); 240 if (format == AUDIO_FORMAT_PCM_FLOAT) { 241 resampler = new AudioResamplerDyn<float, float, float>(inChannelCount, 242 sampleRate, quality); 243 } else { 244 LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 245 if (quality == DYN_HIGH_QUALITY) { 246 resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(inChannelCount, 247 sampleRate, quality); 248 } else { 249 resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(inChannelCount, 250 sampleRate, quality); 251 } 252 } 253 break; 254 } 255 256 // initialize resampler 257 resampler->init(); 258 return resampler; 259 } 260 261 AudioResampler::AudioResampler(int inChannelCount, 262 int32_t sampleRate, src_quality quality) : 263 mChannelCount(inChannelCount), 264 mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), 265 mPhaseFraction(0), 266 mQuality(quality) { 267 268 const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8; 269 if (inChannelCount < 1 270 || inChannelCount > maxChannels) { 271 LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels", 272 quality, inChannelCount); 273 } 274 if (sampleRate <= 0) { 275 LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate); 276 } 277 278 // initialize common members 279 mVolume[0] = mVolume[1] = 0; 280 mBuffer.frameCount = 0; 281 } 282 283 AudioResampler::~AudioResampler() { 284 pthread_mutex_lock(&mutex); 285 src_quality quality = getQuality(); 286 uint32_t deltaMHz = qualityMHz(quality); 287 int32_t newMHz = currentMHz - deltaMHz; 288 ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", 289 currentMHz, newMHz, deltaMHz, quality); 290 LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); 291 currentMHz = newMHz; 292 pthread_mutex_unlock(&mutex); 293 } 294 295 void AudioResampler::setSampleRate(int32_t inSampleRate) { 296 mInSampleRate = inSampleRate; 297 mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); 298 } 299 300 void AudioResampler::setVolume(float left, float right) { 301 // TODO: Implement anti-zipper filter 302 // convert to U4.12 for internal integer use (round down) 303 // integer volume values are clamped to 0 to UNITY_GAIN. 304 mVolume[0] = u4_12_from_float(clampFloatVol(left)); 305 mVolume[1] = u4_12_from_float(clampFloatVol(right)); 306 } 307 308 void AudioResampler::reset() { 309 mInputIndex = 0; 310 mPhaseFraction = 0; 311 mBuffer.frameCount = 0; 312 } 313 314 // ---------------------------------------------------------------------------- 315 316 size_t 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 return resampleMono16(out, outFrameCount, provider); 326 case 2: 327 return resampleStereo16(out, outFrameCount, provider); 328 default: 329 LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); 330 return 0; 331 } 332 } 333 334 size_t AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, 335 AudioBufferProvider* provider) { 336 337 int32_t vl = mVolume[0]; 338 int32_t vr = mVolume[1]; 339 340 size_t inputIndex = mInputIndex; 341 uint32_t phaseFraction = mPhaseFraction; 342 uint32_t phaseIncrement = mPhaseIncrement; 343 size_t outputIndex = 0; 344 size_t outputSampleCount = outFrameCount * 2; 345 size_t inFrameCount = getInFrameCountRequired(outFrameCount); 346 347 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 348 // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 349 350 while (outputIndex < outputSampleCount) { 351 352 // buffer is empty, fetch a new one 353 while (mBuffer.frameCount == 0) { 354 mBuffer.frameCount = inFrameCount; 355 provider->getNextBuffer(&mBuffer); 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 425 resampleStereo16_exit: 426 // save state 427 mInputIndex = inputIndex; 428 mPhaseFraction = phaseFraction; 429 return outputIndex / 2 /* channels for stereo */; 430 } 431 432 size_t AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, 433 AudioBufferProvider* provider) { 434 435 int32_t vl = mVolume[0]; 436 int32_t vr = mVolume[1]; 437 438 size_t inputIndex = mInputIndex; 439 uint32_t phaseFraction = mPhaseFraction; 440 uint32_t phaseIncrement = mPhaseIncrement; 441 size_t outputIndex = 0; 442 size_t outputSampleCount = outFrameCount * 2; 443 size_t inFrameCount = getInFrameCountRequired(outFrameCount); 444 445 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 446 // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 447 while (outputIndex < outputSampleCount) { 448 // buffer is empty, fetch a new one 449 while (mBuffer.frameCount == 0) { 450 mBuffer.frameCount = inFrameCount; 451 provider->getNextBuffer(&mBuffer); 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 521 resampleMono16_exit: 522 // save state 523 mInputIndex = inputIndex; 524 mPhaseFraction = phaseFraction; 525 return outputIndex; 526 } 527 528 #ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 529 530 /******************************************************************* 531 * 532 * AsmMono16Loop 533 * asm optimized monotonic loop version; one loop is 2 frames 534 * Input: 535 * in : pointer on input samples 536 * maxOutPt : pointer on first not filled 537 * maxInIdx : index on first not used 538 * outputIndex : pointer on current output index 539 * out : pointer on output buffer 540 * inputIndex : pointer on current input index 541 * vl, vr : left and right gain 542 * phaseFraction : pointer on current phase fraction 543 * phaseIncrement 544 * Ouput: 545 * outputIndex : 546 * out : updated buffer 547 * inputIndex : index of next to use 548 * phaseFraction : phase fraction for next interpolation 549 * 550 *******************************************************************/ 551 __attribute__((noinline)) 552 void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 553 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 554 uint32_t &phaseFraction, uint32_t phaseIncrement) 555 { 556 (void)maxOutPt; // remove unused parameter warnings 557 (void)maxInIdx; 558 (void)outputIndex; 559 (void)out; 560 (void)inputIndex; 561 (void)vl; 562 (void)vr; 563 (void)phaseFraction; 564 (void)phaseIncrement; 565 (void)in; 566 #define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) 567 568 asm( 569 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" 570 // get parameters 571 " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 572 " ldr r6, [r6]\n" // phaseFraction 573 " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 574 " ldr r7, [r7]\n" // inputIndex 575 " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out 576 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 577 " ldr r0, [r0]\n" // outputIndex 578 " add r8, r8, r0, asl #2\n" // curOut 579 " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement 580 " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl 581 " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr 582 583 // r0 pin, x0, Samp 584 585 // r1 in 586 // r2 maxOutPt 587 // r3 maxInIdx 588 589 // r4 x1, i1, i3, Out1 590 // r5 out0 591 592 // r6 frac 593 // r7 inputIndex 594 // r8 curOut 595 596 // r9 inc 597 // r10 vl 598 // r11 vr 599 600 // r12 601 // r13 sp 602 // r14 603 604 // the following loop works on 2 frames 605 606 "1:\n" 607 " cmp r8, r2\n" // curOut - maxCurOut 608 " bcs 2f\n" 609 610 #define MO_ONE_FRAME \ 611 " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ 612 " ldrsh r4, [r0]\n" /* in[inputIndex] */\ 613 " ldr r5, [r8]\n" /* out[outputIndex] */\ 614 " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ 615 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 616 " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ 617 " mov r4, r4, lsl #2\n" /* <<2 */\ 618 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 619 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 620 " add r0, r0, r4\n" /* x0 - (..) */\ 621 " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ 622 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 623 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 624 " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ 625 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ 626 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ 627 628 MO_ONE_FRAME // frame 1 629 MO_ONE_FRAME // frame 2 630 631 " cmp r7, r3\n" // inputIndex - maxInIdx 632 " bcc 1b\n" 633 "2:\n" 634 635 " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 636 // save modified values 637 " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 638 " str r6, [r0]\n" // phaseFraction 639 " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 640 " str r7, [r0]\n" // inputIndex 641 " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out 642 " sub r8, r0\n" // curOut - out 643 " asr r8, #2\n" // new outputIndex 644 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 645 " str r8, [r0]\n" // save outputIndex 646 647 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" 648 ); 649 } 650 651 /******************************************************************* 652 * 653 * AsmStereo16Loop 654 * asm optimized stereo loop version; one loop is 2 frames 655 * Input: 656 * in : pointer on input samples 657 * maxOutPt : pointer on first not filled 658 * maxInIdx : index on first not used 659 * outputIndex : pointer on current output index 660 * out : pointer on output buffer 661 * inputIndex : pointer on current input index 662 * vl, vr : left and right gain 663 * phaseFraction : pointer on current phase fraction 664 * phaseIncrement 665 * Ouput: 666 * outputIndex : 667 * out : updated buffer 668 * inputIndex : index of next to use 669 * phaseFraction : phase fraction for next interpolation 670 * 671 *******************************************************************/ 672 __attribute__((noinline)) 673 void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 674 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 675 uint32_t &phaseFraction, uint32_t phaseIncrement) 676 { 677 (void)maxOutPt; // remove unused parameter warnings 678 (void)maxInIdx; 679 (void)outputIndex; 680 (void)out; 681 (void)inputIndex; 682 (void)vl; 683 (void)vr; 684 (void)phaseFraction; 685 (void)phaseIncrement; 686 (void)in; 687 #define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) 688 asm( 689 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" 690 // get parameters 691 " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 692 " ldr r6, [r6]\n" // phaseFraction 693 " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 694 " ldr r7, [r7]\n" // inputIndex 695 " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out 696 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 697 " ldr r0, [r0]\n" // outputIndex 698 " add r8, r8, r0, asl #2\n" // curOut 699 " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement 700 " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl 701 " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr 702 703 // r0 pin, x0, Samp 704 705 // r1 in 706 // r2 maxOutPt 707 // r3 maxInIdx 708 709 // r4 x1, i1, i3, out1 710 // r5 out0 711 712 // r6 frac 713 // r7 inputIndex 714 // r8 curOut 715 716 // r9 inc 717 // r10 vl 718 // r11 vr 719 720 // r12 temporary 721 // r13 sp 722 // r14 723 724 "3:\n" 725 " cmp r8, r2\n" // curOut - maxCurOut 726 " bcs 4f\n" 727 728 #define ST_ONE_FRAME \ 729 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 730 \ 731 " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ 732 \ 733 " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ 734 " ldr r5, [r8]\n" /* out[outputIndex] */\ 735 " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ 736 " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 737 " mov r4, r4, lsl #2\n" /* <<2 */\ 738 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 739 " add r12, r12, r4\n" /* x0 - (..) */\ 740 " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ 741 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 742 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 743 \ 744 " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ 745 " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ 746 " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 747 " mov r12, r12, lsl #2\n" /* <<2 */\ 748 " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ 749 " add r12, r0, r12\n" /* x0 - (..) */\ 750 " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ 751 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ 752 \ 753 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 754 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ 755 756 ST_ONE_FRAME // frame 1 757 ST_ONE_FRAME // frame 1 758 759 " cmp r7, r3\n" // inputIndex - maxInIdx 760 " bcc 3b\n" 761 "4:\n" 762 763 " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 764 // save modified values 765 " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 766 " str r6, [r0]\n" // phaseFraction 767 " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 768 " str r7, [r0]\n" // inputIndex 769 " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out 770 " sub r8, r0\n" // curOut - out 771 " asr r8, #2\n" // new outputIndex 772 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 773 " str r8, [r0]\n" // save outputIndex 774 775 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" 776 ); 777 } 778 779 #endif // ASM_ARM_RESAMP1 780 781 782 // ---------------------------------------------------------------------------- 783 784 } // namespace android 785