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