blob: 5c1c9056b8169749e314220fafd7f2ec2283ff5b [file] [log] [blame]
Mathias Agopian65ab4712010-07-14 17:59:35 -07001/*
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"
SathishKumar Mani76b11162012-01-17 10:49:47 -080027#if 0
Mathias Agopian65ab4712010-07-14 17:59:35 -070028#include "AudioResamplerCubic.h"
Glenn Kastencdf21582012-02-02 14:01:58 -080029#endif
Mathias Agopian65ab4712010-07-14 17:59:35 -070030
Jim Huang0c0a1c02011-04-06 14:19:29 +080031#ifdef __arm__
32#include <machine/cpu-features.h>
33#endif
34
Mathias Agopian65ab4712010-07-14 17:59:35 -070035namespace android {
36
Jim Huang0c0a1c02011-04-06 14:19:29 +080037#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
Glenn Kastenc23e2f22011-11-17 13:27:22 -080038 #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
Jim Huang0c0a1c02011-04-06 14:19:29 +080039#endif // __ARM_HAVE_HALFWORD_MULTIPLY
Mathias Agopian65ab4712010-07-14 17:59:35 -070040// ----------------------------------------------------------------------------
41
42class AudioResamplerOrder1 : public AudioResampler {
43public:
44 AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
45 AudioResampler(bitDepth, inChannelCount, sampleRate), 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// ----------------------------------------------------------------------------
83AudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
84 int32_t sampleRate, int quality) {
85
86 // can only create low quality resample now
87 AudioResampler* resampler;
88
89 char value[PROPERTY_VALUE_MAX];
90 if (property_get("af.resampler.quality", value, 0)) {
91 quality = atoi(value);
Steve Blockb8a80522011-12-20 16:23:08 +000092 ALOGD("forcing AudioResampler quality to %d", quality);
Mathias Agopian65ab4712010-07-14 17:59:35 -070093 }
94
95 if (quality == DEFAULT)
96 quality = LOW_QUALITY;
97
98 switch (quality) {
99 default:
100 case LOW_QUALITY:
Steve Block3856b092011-10-20 11:56:00 +0100101 ALOGV("Create linear Resampler");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700102 resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
103 break;
Glenn Kastencdf21582012-02-02 14:01:58 -0800104#if 0
Mathias Agopian65ab4712010-07-14 17:59:35 -0700105 case MED_QUALITY:
Steve Block3856b092011-10-20 11:56:00 +0100106 ALOGV("Create cubic Resampler");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700107 resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
108 break;
Glenn Kastencdf21582012-02-02 14:01:58 -0800109#endif
SathishKumar Mani76b11162012-01-17 10:49:47 -0800110 case HIGH_QUALITY:
111 ALOGV("Create HIGH_QUALITY sinc Resampler");
112 resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
113 case VERY_HIGH_QUALITY:
114 ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d",quality);
115 resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality);
116 break;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700117 }
118
119 // initialize resampler
120 resampler->init();
121 return resampler;
122}
123
124AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
125 int32_t sampleRate) :
126 mBitDepth(bitDepth), mChannelCount(inChannelCount),
127 mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
John Grossman4ff14ba2012-02-08 16:37:41 -0800128 mPhaseFraction(0), mLocalTimeFreq(0),
129 mPTS(AudioBufferProvider::kInvalidPTS) {
Mathias Agopian65ab4712010-07-14 17:59:35 -0700130 // sanity check on format
131 if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
Steve Block29357bc2012-01-06 19:20:56 +0000132 ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
Mathias Agopian65ab4712010-07-14 17:59:35 -0700133 inChannelCount);
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000134 // ALOG_ASSERT(0);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700135 }
136
137 // initialize common members
138 mVolume[0] = mVolume[1] = 0;
139 mBuffer.frameCount = 0;
140
Mathias Agopian65ab4712010-07-14 17:59:35 -0700141}
142
143AudioResampler::~AudioResampler() {
144}
145
146void AudioResampler::setSampleRate(int32_t inSampleRate) {
147 mInSampleRate = inSampleRate;
148 mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
149}
150
151void AudioResampler::setVolume(int16_t left, int16_t right) {
152 // TODO: Implement anti-zipper filter
153 mVolume[0] = left;
154 mVolume[1] = right;
155}
156
John Grossman4ff14ba2012-02-08 16:37:41 -0800157void AudioResampler::setLocalTimeFreq(uint64_t freq) {
158 mLocalTimeFreq = freq;
159}
160
161void AudioResampler::setPTS(int64_t pts) {
162 mPTS = pts;
163}
164
165int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
166
167 if (mPTS == AudioBufferProvider::kInvalidPTS) {
168 return AudioBufferProvider::kInvalidPTS;
169 } else {
170 return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
171 }
172}
173
Eric Laurent243f5f92011-02-28 16:52:51 -0800174void AudioResampler::reset() {
175 mInputIndex = 0;
176 mPhaseFraction = 0;
177 mBuffer.frameCount = 0;
178}
179
Mathias Agopian65ab4712010-07-14 17:59:35 -0700180// ----------------------------------------------------------------------------
181
182void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
183 AudioBufferProvider* provider) {
184
185 // should never happen, but we overflow if it does
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000186 // ALOG_ASSERT(outFrameCount < 32767);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700187
188 // select the appropriate resampler
189 switch (mChannelCount) {
190 case 1:
191 resampleMono16(out, outFrameCount, provider);
192 break;
193 case 2:
194 resampleStereo16(out, outFrameCount, provider);
195 break;
196 }
197}
198
199void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
200 AudioBufferProvider* provider) {
201
202 int32_t vl = mVolume[0];
203 int32_t vr = mVolume[1];
204
205 size_t inputIndex = mInputIndex;
206 uint32_t phaseFraction = mPhaseFraction;
207 uint32_t phaseIncrement = mPhaseIncrement;
208 size_t outputIndex = 0;
209 size_t outputSampleCount = outFrameCount * 2;
210 size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
211
Glenn Kasten90bebef2012-01-27 15:24:38 -0800212 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
Mathias Agopian65ab4712010-07-14 17:59:35 -0700213 // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
214
215 while (outputIndex < outputSampleCount) {
216
217 // buffer is empty, fetch a new one
218 while (mBuffer.frameCount == 0) {
219 mBuffer.frameCount = inFrameCount;
John Grossman4ff14ba2012-02-08 16:37:41 -0800220 provider->getNextBuffer(&mBuffer,
221 calculateOutputPTS(outputIndex / 2));
Mathias Agopian65ab4712010-07-14 17:59:35 -0700222 if (mBuffer.raw == NULL) {
223 goto resampleStereo16_exit;
224 }
225
Glenn Kasten90bebef2012-01-27 15:24:38 -0800226 // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700227 if (mBuffer.frameCount > inputIndex) break;
228
229 inputIndex -= mBuffer.frameCount;
230 mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
231 mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
232 provider->releaseBuffer(&mBuffer);
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700233 // mBuffer.frameCount == 0 now so we reload a new buffer
Mathias Agopian65ab4712010-07-14 17:59:35 -0700234 }
235
236 int16_t *in = mBuffer.i16;
237
238 // handle boundary case
239 while (inputIndex == 0) {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800240 // ALOGE("boundary case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700241 out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
242 out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
243 Advance(&inputIndex, &phaseFraction, phaseIncrement);
244 if (outputIndex == outputSampleCount)
245 break;
246 }
247
248 // process input samples
Glenn Kasten90bebef2012-01-27 15:24:38 -0800249 // ALOGE("general case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700250
251#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
252 if (inputIndex + 2 < mBuffer.frameCount) {
253 int32_t* maxOutPt;
254 int32_t maxInIdx;
255
256 maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop
257 maxInIdx = mBuffer.frameCount - 2;
258 AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
259 phaseFraction, phaseIncrement);
260 }
261#endif // ASM_ARM_RESAMP1
262
263 while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
264 out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
265 in[inputIndex*2], phaseFraction);
266 out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
267 in[inputIndex*2+1], phaseFraction);
268 Advance(&inputIndex, &phaseFraction, phaseIncrement);
269 }
270
Glenn Kasten90bebef2012-01-27 15:24:38 -0800271 // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700272
273 // if done with buffer, save samples
274 if (inputIndex >= mBuffer.frameCount) {
275 inputIndex -= mBuffer.frameCount;
276
Steve Block29357bc2012-01-06 19:20:56 +0000277 // ALOGE("buffer done, new input index %d", inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700278
279 mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
280 mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
281 provider->releaseBuffer(&mBuffer);
282
283 // verify that the releaseBuffer resets the buffer frameCount
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000284 // ALOG_ASSERT(mBuffer.frameCount == 0);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700285 }
286 }
287
Glenn Kasten90bebef2012-01-27 15:24:38 -0800288 // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700289
290resampleStereo16_exit:
291 // save state
292 mInputIndex = inputIndex;
293 mPhaseFraction = phaseFraction;
294}
295
296void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
297 AudioBufferProvider* provider) {
298
299 int32_t vl = mVolume[0];
300 int32_t vr = mVolume[1];
301
302 size_t inputIndex = mInputIndex;
303 uint32_t phaseFraction = mPhaseFraction;
304 uint32_t phaseIncrement = mPhaseIncrement;
305 size_t outputIndex = 0;
306 size_t outputSampleCount = outFrameCount * 2;
307 size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
308
Glenn Kasten90bebef2012-01-27 15:24:38 -0800309 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
Mathias Agopian65ab4712010-07-14 17:59:35 -0700310 // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
311 while (outputIndex < outputSampleCount) {
312 // buffer is empty, fetch a new one
313 while (mBuffer.frameCount == 0) {
314 mBuffer.frameCount = inFrameCount;
John Grossman4ff14ba2012-02-08 16:37:41 -0800315 provider->getNextBuffer(&mBuffer,
316 calculateOutputPTS(outputIndex / 2));
Mathias Agopian65ab4712010-07-14 17:59:35 -0700317 if (mBuffer.raw == NULL) {
318 mInputIndex = inputIndex;
319 mPhaseFraction = phaseFraction;
320 goto resampleMono16_exit;
321 }
Glenn Kasten90bebef2012-01-27 15:24:38 -0800322 // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700323 if (mBuffer.frameCount > inputIndex) break;
324
325 inputIndex -= mBuffer.frameCount;
326 mX0L = mBuffer.i16[mBuffer.frameCount-1];
327 provider->releaseBuffer(&mBuffer);
328 // mBuffer.frameCount == 0 now so we reload a new buffer
329 }
330 int16_t *in = mBuffer.i16;
331
332 // handle boundary case
333 while (inputIndex == 0) {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800334 // ALOGE("boundary case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700335 int32_t sample = Interp(mX0L, in[0], phaseFraction);
336 out[outputIndex++] += vl * sample;
337 out[outputIndex++] += vr * sample;
338 Advance(&inputIndex, &phaseFraction, phaseIncrement);
339 if (outputIndex == outputSampleCount)
340 break;
341 }
342
343 // process input samples
Glenn Kasten90bebef2012-01-27 15:24:38 -0800344 // ALOGE("general case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700345
346#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
347 if (inputIndex + 2 < mBuffer.frameCount) {
348 int32_t* maxOutPt;
349 int32_t maxInIdx;
350
351 maxOutPt = out + (outputSampleCount - 2);
352 maxInIdx = (int32_t)mBuffer.frameCount - 2;
353 AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
354 phaseFraction, phaseIncrement);
355 }
356#endif // ASM_ARM_RESAMP1
357
358 while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
359 int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
360 phaseFraction);
361 out[outputIndex++] += vl * sample;
362 out[outputIndex++] += vr * sample;
363 Advance(&inputIndex, &phaseFraction, phaseIncrement);
364 }
365
366
Glenn Kasten90bebef2012-01-27 15:24:38 -0800367 // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700368
369 // if done with buffer, save samples
370 if (inputIndex >= mBuffer.frameCount) {
371 inputIndex -= mBuffer.frameCount;
372
Steve Block29357bc2012-01-06 19:20:56 +0000373 // ALOGE("buffer done, new input index %d", inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700374
375 mX0L = mBuffer.i16[mBuffer.frameCount-1];
376 provider->releaseBuffer(&mBuffer);
377
378 // verify that the releaseBuffer resets the buffer frameCount
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000379 // ALOG_ASSERT(mBuffer.frameCount == 0);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700380 }
381 }
382
Glenn Kasten90bebef2012-01-27 15:24:38 -0800383 // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700384
385resampleMono16_exit:
386 // save state
387 mInputIndex = inputIndex;
388 mPhaseFraction = phaseFraction;
389}
390
391#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
392
393/*******************************************************************
394*
395* AsmMono16Loop
396* asm optimized monotonic loop version; one loop is 2 frames
397* Input:
398* in : pointer on input samples
399* maxOutPt : pointer on first not filled
400* maxInIdx : index on first not used
401* outputIndex : pointer on current output index
402* out : pointer on output buffer
403* inputIndex : pointer on current input index
404* vl, vr : left and right gain
405* phaseFraction : pointer on current phase fraction
406* phaseIncrement
407* Ouput:
408* outputIndex :
409* out : updated buffer
410* inputIndex : index of next to use
411* phaseFraction : phase fraction for next interpolation
412*
413*******************************************************************/
Glenn Kastenc23e2f22011-11-17 13:27:22 -0800414__attribute__((noinline))
Mathias Agopian65ab4712010-07-14 17:59:35 -0700415void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
416 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
417 uint32_t &phaseFraction, uint32_t phaseIncrement)
418{
419#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex)
420
421 asm(
422 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
423 // get parameters
424 " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction
425 " ldr r6, [r6]\n" // phaseFraction
426 " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex
427 " ldr r7, [r7]\n" // inputIndex
428 " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out
429 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex
430 " ldr r0, [r0]\n" // outputIndex
431 " add r8, r0, asl #2\n" // curOut
432 " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement
433 " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl
434 " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr
435
436 // r0 pin, x0, Samp
437
438 // r1 in
439 // r2 maxOutPt
440 // r3 maxInIdx
441
442 // r4 x1, i1, i3, Out1
443 // r5 out0
444
445 // r6 frac
446 // r7 inputIndex
447 // r8 curOut
448
449 // r9 inc
450 // r10 vl
451 // r11 vr
452
453 // r12
454 // r13 sp
455 // r14
456
457 // the following loop works on 2 frames
458
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700459 "1:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700460 " cmp r8, r2\n" // curOut - maxCurOut
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700461 " bcs 2f\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700462
463#define MO_ONE_FRAME \
464 " add r0, r1, r7, asl #1\n" /* in + inputIndex */\
465 " ldrsh r4, [r0]\n" /* in[inputIndex] */\
466 " ldr r5, [r8]\n" /* out[outputIndex] */\
467 " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\
468 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\
469 " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\
470 " mov r4, r4, lsl #2\n" /* <<2 */\
471 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\
472 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\
473 " add r0, r0, r4\n" /* x0 - (..) */\
474 " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\
475 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\
476 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\
477 " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\
478 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\
479 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */
480
481 MO_ONE_FRAME // frame 1
482 MO_ONE_FRAME // frame 2
483
484 " cmp r7, r3\n" // inputIndex - maxInIdx
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700485 " bcc 1b\n"
486 "2:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700487
488 " bic r6, r6, #0xC0000000\n" // phaseFraction & ...
489 // save modified values
490 " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction
491 " str r6, [r0]\n" // phaseFraction
492 " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex
493 " str r7, [r0]\n" // inputIndex
494 " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out
495 " sub r8, r0\n" // curOut - out
496 " asr r8, #2\n" // new outputIndex
497 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex
498 " str r8, [r0]\n" // save outputIndex
499
500 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
501 );
502}
503
504/*******************************************************************
505*
506* AsmStereo16Loop
507* asm optimized stereo loop version; one loop is 2 frames
508* Input:
509* in : pointer on input samples
510* maxOutPt : pointer on first not filled
511* maxInIdx : index on first not used
512* outputIndex : pointer on current output index
513* out : pointer on output buffer
514* inputIndex : pointer on current input index
515* vl, vr : left and right gain
516* phaseFraction : pointer on current phase fraction
517* phaseIncrement
518* Ouput:
519* outputIndex :
520* out : updated buffer
521* inputIndex : index of next to use
522* phaseFraction : phase fraction for next interpolation
523*
524*******************************************************************/
Glenn Kastenc23e2f22011-11-17 13:27:22 -0800525__attribute__((noinline))
Mathias Agopian65ab4712010-07-14 17:59:35 -0700526void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
527 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
528 uint32_t &phaseFraction, uint32_t phaseIncrement)
529{
530#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex)
531 asm(
532 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
533 // get parameters
534 " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction
535 " ldr r6, [r6]\n" // phaseFraction
536 " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex
537 " ldr r7, [r7]\n" // inputIndex
538 " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out
539 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex
540 " ldr r0, [r0]\n" // outputIndex
541 " add r8, r0, asl #2\n" // curOut
542 " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement
543 " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl
544 " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr
545
546 // r0 pin, x0, Samp
547
548 // r1 in
549 // r2 maxOutPt
550 // r3 maxInIdx
551
552 // r4 x1, i1, i3, out1
553 // r5 out0
554
555 // r6 frac
556 // r7 inputIndex
557 // r8 curOut
558
559 // r9 inc
560 // r10 vl
561 // r11 vr
562
563 // r12 temporary
564 // r13 sp
565 // r14
566
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700567 "3:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700568 " cmp r8, r2\n" // curOut - maxCurOut
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700569 " bcs 4f\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700570
571#define ST_ONE_FRAME \
572 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\
573\
574 " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\
575\
576 " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\
577 " ldr r5, [r8]\n" /* out[outputIndex] */\
578 " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\
579 " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\
580 " mov r4, r4, lsl #2\n" /* <<2 */\
581 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\
582 " add r12, r12, r4\n" /* x0 - (..) */\
583 " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\
584 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\
585 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\
586\
587 " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\
588 " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\
589 " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\
590 " mov r12, r12, lsl #2\n" /* <<2 */\
591 " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\
592 " add r12, r0, r12\n" /* x0 - (..) */\
593 " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\
594 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\
595\
596 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\
597 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */
598
599 ST_ONE_FRAME // frame 1
600 ST_ONE_FRAME // frame 1
601
602 " cmp r7, r3\n" // inputIndex - maxInIdx
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700603 " bcc 3b\n"
604 "4:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700605
606 " bic r6, r6, #0xC0000000\n" // phaseFraction & ...
607 // save modified values
608 " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction
609 " str r6, [r0]\n" // phaseFraction
610 " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex
611 " str r7, [r0]\n" // inputIndex
612 " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out
613 " sub r8, r0\n" // curOut - out
614 " asr r8, #2\n" // new outputIndex
615 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex
616 " str r8, [r0]\n" // save outputIndex
617
618 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
619 );
620}
621
622#endif // ASM_ARM_RESAMP1
623
624
625// ----------------------------------------------------------------------------
Mathias Agopian65ab4712010-07-14 17:59:35 -0700626
Glenn Kastenc23e2f22011-11-17 13:27:22 -0800627} // namespace android