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