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