blob: 562c4ea33717e5e76fbb58074e98417012385b07 [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"
27#include "AudioResamplerCubic.h"
Andy Hung86eae0e2013-12-09 12:12:46 -080028#include "AudioResamplerDyn.h"
Mathias Agopian65ab4712010-07-14 17:59:35 -070029
Jim Huang0c0a1c02011-04-06 14:19:29 +080030#ifdef __arm__
31#include <machine/cpu-features.h>
32#endif
33
Mathias Agopian65ab4712010-07-14 17:59:35 -070034namespace android {
35
Jim Huang0c0a1c02011-04-06 14:19:29 +080036#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
Glenn Kastenc23e2f22011-11-17 13:27:22 -080037 #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
Jim Huang0c0a1c02011-04-06 14:19:29 +080038#endif // __ARM_HAVE_HALFWORD_MULTIPLY
Mathias Agopian65ab4712010-07-14 17:59:35 -070039// ----------------------------------------------------------------------------
40
41class AudioResamplerOrder1 : public AudioResampler {
42public:
43 AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
Glenn Kastenac602052012-10-01 14:04:31 -070044 AudioResampler(bitDepth, inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) {
Mathias Agopian65ab4712010-07-14 17:59:35 -070045 }
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
Glenn Kasten01d3acb2014-02-06 08:24:07 -080081/*static*/
82const double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits;
83
Glenn Kastenac602052012-10-01 14:04:31 -070084bool AudioResampler::qualityIsSupported(src_quality quality)
85{
86 switch (quality) {
87 case DEFAULT_QUALITY:
88 case LOW_QUALITY:
Glenn Kastenac602052012-10-01 14:04:31 -070089 case MED_QUALITY:
90 case HIGH_QUALITY:
Glenn Kastenac602052012-10-01 14:04:31 -070091 case VERY_HIGH_QUALITY:
Andy Hung86eae0e2013-12-09 12:12:46 -080092 case DYN_LOW_QUALITY:
93 case DYN_MED_QUALITY:
94 case DYN_HIGH_QUALITY:
Glenn Kastenac602052012-10-01 14:04:31 -070095 return true;
96 default:
97 return false;
98 }
99}
100
Mathias Agopian65ab4712010-07-14 17:59:35 -0700101// ----------------------------------------------------------------------------
Mathias Agopian65ab4712010-07-14 17:59:35 -0700102
Glenn Kastenac602052012-10-01 14:04:31 -0700103static pthread_once_t once_control = PTHREAD_ONCE_INIT;
104static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700105
Glenn Kastenac602052012-10-01 14:04:31 -0700106void AudioResampler::init_routine()
107{
Mathias Agopian65ab4712010-07-14 17:59:35 -0700108 char value[PROPERTY_VALUE_MAX];
Glenn Kastenac602052012-10-01 14:04:31 -0700109 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);
Andy Hung86eae0e2013-12-09 12:12:46 -0800115 if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) {
Glenn Kastenac602052012-10-01 14:04:31 -0700116 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;
Andy Hung86eae0e2013-12-09 12:12:46 -0800135 case DYN_LOW_QUALITY:
136 return 4;
137 case DYN_MED_QUALITY:
138 return 6;
139 case DYN_HIGH_QUALITY:
140 return 12;
Glenn Kastenac602052012-10-01 14:04:31 -0700141 }
142}
143
Glenn Kastenc4640c92012-10-22 17:09:27 -0700144static const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable
Glenn Kastenac602052012-10-01 14:04:31 -0700145static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
146static uint32_t currentMHz = 0;
147
148AudioResampler* AudioResampler::create(int bitDepth, 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;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700162 }
163
Andy Hung9e0308c2014-01-30 14:32:31 -0800164 /* 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
Glenn Kastenac602052012-10-01 14:04:31 -0700174 // 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:
Glenn Kastenac602052012-10-01 14:04:31 -0700188 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;
Andy Hung86eae0e2013-12-09 12:12:46 -0800200 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;
Glenn Kastenac602052012-10-01 14:04:31 -0700209 }
210 }
211 pthread_mutex_unlock(&mutex);
212
213 AudioResampler* resampler;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700214
215 switch (quality) {
216 default:
217 case LOW_QUALITY:
Steve Block3856b092011-10-20 11:56:00 +0100218 ALOGV("Create linear Resampler");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700219 resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
220 break;
221 case MED_QUALITY:
Steve Block3856b092011-10-20 11:56:00 +0100222 ALOGV("Create cubic Resampler");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700223 resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
224 break;
SathishKumar Mani76b11162012-01-17 10:49:47 -0800225 case HIGH_QUALITY:
226 ALOGV("Create HIGH_QUALITY sinc Resampler");
227 resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
Glenn Kastenac602052012-10-01 14:04:31 -0700228 break;
SathishKumar Mani76b11162012-01-17 10:49:47 -0800229 case VERY_HIGH_QUALITY:
Glenn Kastenac602052012-10-01 14:04:31 -0700230 ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality);
SathishKumar Mani76b11162012-01-17 10:49:47 -0800231 resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality);
232 break;
Andy Hung86eae0e2013-12-09 12:12:46 -0800233 case DYN_LOW_QUALITY:
234 case DYN_MED_QUALITY:
235 case DYN_HIGH_QUALITY:
236 ALOGV("Create dynamic Resampler = %d", quality);
Andy Hung771386e2014-04-08 18:44:38 -0700237 if (bitDepth == 32) { /* bitDepth == 32 signals float precision */
238 resampler = new AudioResamplerDyn<float, float, float>(bitDepth, inChannelCount,
239 sampleRate, quality);
240 } else if (quality == DYN_HIGH_QUALITY) {
241 resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(bitDepth, inChannelCount,
242 sampleRate, quality);
243 } else {
244 resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(bitDepth, inChannelCount,
245 sampleRate, quality);
246 }
Andy Hung86eae0e2013-12-09 12:12:46 -0800247 break;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700248 }
249
250 // initialize resampler
251 resampler->init();
252 return resampler;
253}
254
255AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
Glenn Kastenac602052012-10-01 14:04:31 -0700256 int32_t sampleRate, src_quality quality) :
Mathias Agopian65ab4712010-07-14 17:59:35 -0700257 mBitDepth(bitDepth), mChannelCount(inChannelCount),
258 mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
John Grossman4ff14ba2012-02-08 16:37:41 -0800259 mPhaseFraction(0), mLocalTimeFreq(0),
Glenn Kastenac602052012-10-01 14:04:31 -0700260 mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
Mathias Agopian65ab4712010-07-14 17:59:35 -0700261 // sanity check on format
262 if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
Steve Block29357bc2012-01-06 19:20:56 +0000263 ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
Mathias Agopian65ab4712010-07-14 17:59:35 -0700264 inChannelCount);
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000265 // ALOG_ASSERT(0);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700266 }
Glenn Kastenac602052012-10-01 14:04:31 -0700267 if (sampleRate <= 0) {
268 ALOGE("Unsupported sample rate %d Hz", sampleRate);
269 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700270
271 // initialize common members
272 mVolume[0] = mVolume[1] = 0;
273 mBuffer.frameCount = 0;
274
Mathias Agopian65ab4712010-07-14 17:59:35 -0700275}
276
277AudioResampler::~AudioResampler() {
Glenn Kastenac602052012-10-01 14:04:31 -0700278 pthread_mutex_lock(&mutex);
279 src_quality quality = getQuality();
280 uint32_t deltaMHz = qualityMHz(quality);
281 int32_t newMHz = currentMHz - deltaMHz;
282 ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d",
283 currentMHz, newMHz, deltaMHz, quality);
284 LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz);
285 currentMHz = newMHz;
286 pthread_mutex_unlock(&mutex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700287}
288
289void AudioResampler::setSampleRate(int32_t inSampleRate) {
290 mInSampleRate = inSampleRate;
291 mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
292}
293
294void AudioResampler::setVolume(int16_t left, int16_t right) {
295 // TODO: Implement anti-zipper filter
296 mVolume[0] = left;
297 mVolume[1] = right;
298}
299
John Grossman4ff14ba2012-02-08 16:37:41 -0800300void AudioResampler::setLocalTimeFreq(uint64_t freq) {
301 mLocalTimeFreq = freq;
302}
303
304void AudioResampler::setPTS(int64_t pts) {
305 mPTS = pts;
306}
307
308int64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
309
310 if (mPTS == AudioBufferProvider::kInvalidPTS) {
311 return AudioBufferProvider::kInvalidPTS;
312 } else {
313 return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
314 }
315}
316
Eric Laurent243f5f92011-02-28 16:52:51 -0800317void AudioResampler::reset() {
318 mInputIndex = 0;
319 mPhaseFraction = 0;
320 mBuffer.frameCount = 0;
321}
322
Mathias Agopian65ab4712010-07-14 17:59:35 -0700323// ----------------------------------------------------------------------------
324
325void AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
326 AudioBufferProvider* provider) {
327
328 // should never happen, but we overflow if it does
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000329 // ALOG_ASSERT(outFrameCount < 32767);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700330
331 // select the appropriate resampler
332 switch (mChannelCount) {
333 case 1:
334 resampleMono16(out, outFrameCount, provider);
335 break;
336 case 2:
337 resampleStereo16(out, outFrameCount, provider);
338 break;
339 }
340}
341
342void AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
343 AudioBufferProvider* provider) {
344
345 int32_t vl = mVolume[0];
346 int32_t vr = mVolume[1];
347
348 size_t inputIndex = mInputIndex;
349 uint32_t phaseFraction = mPhaseFraction;
350 uint32_t phaseIncrement = mPhaseIncrement;
351 size_t outputIndex = 0;
352 size_t outputSampleCount = outFrameCount * 2;
Andy Hung24781ff2014-02-19 12:45:19 -0800353 size_t inFrameCount = getInFrameCountRequired(outFrameCount);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700354
Glenn Kasten90bebef2012-01-27 15:24:38 -0800355 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
Mathias Agopian65ab4712010-07-14 17:59:35 -0700356 // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
357
358 while (outputIndex < outputSampleCount) {
359
360 // buffer is empty, fetch a new one
361 while (mBuffer.frameCount == 0) {
362 mBuffer.frameCount = inFrameCount;
John Grossman4ff14ba2012-02-08 16:37:41 -0800363 provider->getNextBuffer(&mBuffer,
364 calculateOutputPTS(outputIndex / 2));
Mathias Agopian65ab4712010-07-14 17:59:35 -0700365 if (mBuffer.raw == NULL) {
366 goto resampleStereo16_exit;
367 }
368
Glenn Kasten90bebef2012-01-27 15:24:38 -0800369 // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700370 if (mBuffer.frameCount > inputIndex) break;
371
372 inputIndex -= mBuffer.frameCount;
373 mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
374 mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
375 provider->releaseBuffer(&mBuffer);
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700376 // mBuffer.frameCount == 0 now so we reload a new buffer
Mathias Agopian65ab4712010-07-14 17:59:35 -0700377 }
378
379 int16_t *in = mBuffer.i16;
380
381 // handle boundary case
382 while (inputIndex == 0) {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800383 // ALOGE("boundary case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700384 out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
385 out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
386 Advance(&inputIndex, &phaseFraction, phaseIncrement);
Glenn Kasten6e2ebe92013-08-13 09:14:51 -0700387 if (outputIndex == outputSampleCount) {
Mathias Agopian65ab4712010-07-14 17:59:35 -0700388 break;
Glenn Kasten6e2ebe92013-08-13 09:14:51 -0700389 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700390 }
391
392 // process input samples
Glenn Kasten90bebef2012-01-27 15:24:38 -0800393 // ALOGE("general case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700394
395#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
396 if (inputIndex + 2 < mBuffer.frameCount) {
397 int32_t* maxOutPt;
398 int32_t maxInIdx;
399
400 maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop
401 maxInIdx = mBuffer.frameCount - 2;
402 AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
403 phaseFraction, phaseIncrement);
404 }
405#endif // ASM_ARM_RESAMP1
406
407 while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
408 out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
409 in[inputIndex*2], phaseFraction);
410 out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
411 in[inputIndex*2+1], phaseFraction);
412 Advance(&inputIndex, &phaseFraction, phaseIncrement);
413 }
414
Glenn Kasten90bebef2012-01-27 15:24:38 -0800415 // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700416
417 // if done with buffer, save samples
418 if (inputIndex >= mBuffer.frameCount) {
419 inputIndex -= mBuffer.frameCount;
420
Steve Block29357bc2012-01-06 19:20:56 +0000421 // ALOGE("buffer done, new input index %d", inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700422
423 mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
424 mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
425 provider->releaseBuffer(&mBuffer);
426
427 // verify that the releaseBuffer resets the buffer frameCount
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000428 // ALOG_ASSERT(mBuffer.frameCount == 0);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700429 }
430 }
431
Glenn Kasten90bebef2012-01-27 15:24:38 -0800432 // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700433
434resampleStereo16_exit:
435 // save state
436 mInputIndex = inputIndex;
437 mPhaseFraction = phaseFraction;
438}
439
440void AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
441 AudioBufferProvider* provider) {
442
443 int32_t vl = mVolume[0];
444 int32_t vr = mVolume[1];
445
446 size_t inputIndex = mInputIndex;
447 uint32_t phaseFraction = mPhaseFraction;
448 uint32_t phaseIncrement = mPhaseIncrement;
449 size_t outputIndex = 0;
450 size_t outputSampleCount = outFrameCount * 2;
Andy Hung24781ff2014-02-19 12:45:19 -0800451 size_t inFrameCount = getInFrameCountRequired(outFrameCount);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700452
Glenn Kasten90bebef2012-01-27 15:24:38 -0800453 // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
Mathias Agopian65ab4712010-07-14 17:59:35 -0700454 // outFrameCount, inputIndex, phaseFraction, phaseIncrement);
455 while (outputIndex < outputSampleCount) {
456 // buffer is empty, fetch a new one
457 while (mBuffer.frameCount == 0) {
458 mBuffer.frameCount = inFrameCount;
John Grossman4ff14ba2012-02-08 16:37:41 -0800459 provider->getNextBuffer(&mBuffer,
460 calculateOutputPTS(outputIndex / 2));
Mathias Agopian65ab4712010-07-14 17:59:35 -0700461 if (mBuffer.raw == NULL) {
462 mInputIndex = inputIndex;
463 mPhaseFraction = phaseFraction;
464 goto resampleMono16_exit;
465 }
Glenn Kasten90bebef2012-01-27 15:24:38 -0800466 // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700467 if (mBuffer.frameCount > inputIndex) break;
468
469 inputIndex -= mBuffer.frameCount;
470 mX0L = mBuffer.i16[mBuffer.frameCount-1];
471 provider->releaseBuffer(&mBuffer);
472 // mBuffer.frameCount == 0 now so we reload a new buffer
473 }
474 int16_t *in = mBuffer.i16;
475
476 // handle boundary case
477 while (inputIndex == 0) {
Glenn Kasten90bebef2012-01-27 15:24:38 -0800478 // ALOGE("boundary case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700479 int32_t sample = Interp(mX0L, in[0], phaseFraction);
480 out[outputIndex++] += vl * sample;
481 out[outputIndex++] += vr * sample;
482 Advance(&inputIndex, &phaseFraction, phaseIncrement);
Glenn Kasten6e2ebe92013-08-13 09:14:51 -0700483 if (outputIndex == outputSampleCount) {
Mathias Agopian65ab4712010-07-14 17:59:35 -0700484 break;
Glenn Kasten6e2ebe92013-08-13 09:14:51 -0700485 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700486 }
487
488 // process input samples
Glenn Kasten90bebef2012-01-27 15:24:38 -0800489 // ALOGE("general case");
Mathias Agopian65ab4712010-07-14 17:59:35 -0700490
491#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
492 if (inputIndex + 2 < mBuffer.frameCount) {
493 int32_t* maxOutPt;
494 int32_t maxInIdx;
495
496 maxOutPt = out + (outputSampleCount - 2);
497 maxInIdx = (int32_t)mBuffer.frameCount - 2;
498 AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
499 phaseFraction, phaseIncrement);
500 }
501#endif // ASM_ARM_RESAMP1
502
503 while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
504 int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
505 phaseFraction);
506 out[outputIndex++] += vl * sample;
507 out[outputIndex++] += vr * sample;
508 Advance(&inputIndex, &phaseFraction, phaseIncrement);
509 }
510
511
Glenn Kasten90bebef2012-01-27 15:24:38 -0800512 // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700513
514 // if done with buffer, save samples
515 if (inputIndex >= mBuffer.frameCount) {
516 inputIndex -= mBuffer.frameCount;
517
Steve Block29357bc2012-01-06 19:20:56 +0000518 // ALOGE("buffer done, new input index %d", inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700519
520 mX0L = mBuffer.i16[mBuffer.frameCount-1];
521 provider->releaseBuffer(&mBuffer);
522
523 // verify that the releaseBuffer resets the buffer frameCount
Steve Blockc1dc1cb2012-01-09 18:35:44 +0000524 // ALOG_ASSERT(mBuffer.frameCount == 0);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700525 }
526 }
527
Glenn Kasten90bebef2012-01-27 15:24:38 -0800528 // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700529
530resampleMono16_exit:
531 // save state
532 mInputIndex = inputIndex;
533 mPhaseFraction = phaseFraction;
534}
535
536#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1
537
538/*******************************************************************
539*
540* AsmMono16Loop
541* asm optimized monotonic loop version; one loop is 2 frames
542* Input:
543* in : pointer on input samples
544* maxOutPt : pointer on first not filled
545* maxInIdx : index on first not used
546* outputIndex : pointer on current output index
547* out : pointer on output buffer
548* inputIndex : pointer on current input index
549* vl, vr : left and right gain
550* phaseFraction : pointer on current phase fraction
551* phaseIncrement
552* Ouput:
553* outputIndex :
554* out : updated buffer
555* inputIndex : index of next to use
556* phaseFraction : phase fraction for next interpolation
557*
558*******************************************************************/
Glenn Kastenc23e2f22011-11-17 13:27:22 -0800559__attribute__((noinline))
Mathias Agopian65ab4712010-07-14 17:59:35 -0700560void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
561 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
562 uint32_t &phaseFraction, uint32_t phaseIncrement)
563{
Andy Hungee931ff2014-01-28 13:44:14 -0800564 (void)maxOutPt; // remove unused parameter warnings
565 (void)maxInIdx;
566 (void)outputIndex;
567 (void)out;
568 (void)inputIndex;
569 (void)vl;
570 (void)vr;
571 (void)phaseFraction;
572 (void)phaseIncrement;
573 (void)in;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700574#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex)
575
576 asm(
577 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
578 // get parameters
579 " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction
580 " ldr r6, [r6]\n" // phaseFraction
581 " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex
582 " ldr r7, [r7]\n" // inputIndex
583 " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out
584 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex
585 " ldr r0, [r0]\n" // outputIndex
synergy dev5f51ade2014-02-04 06:38:33 -0500586 " add r8, r8, r0, asl #2\n" // curOut
Mathias Agopian65ab4712010-07-14 17:59:35 -0700587 " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement
588 " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl
589 " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr
590
591 // r0 pin, x0, Samp
592
593 // r1 in
594 // r2 maxOutPt
595 // r3 maxInIdx
596
597 // r4 x1, i1, i3, Out1
598 // r5 out0
599
600 // r6 frac
601 // r7 inputIndex
602 // r8 curOut
603
604 // r9 inc
605 // r10 vl
606 // r11 vr
607
608 // r12
609 // r13 sp
610 // r14
611
612 // the following loop works on 2 frames
613
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700614 "1:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700615 " cmp r8, r2\n" // curOut - maxCurOut
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700616 " bcs 2f\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700617
618#define MO_ONE_FRAME \
619 " add r0, r1, r7, asl #1\n" /* in + inputIndex */\
620 " ldrsh r4, [r0]\n" /* in[inputIndex] */\
621 " ldr r5, [r8]\n" /* out[outputIndex] */\
622 " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\
623 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\
624 " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\
625 " mov r4, r4, lsl #2\n" /* <<2 */\
626 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\
627 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\
628 " add r0, r0, r4\n" /* x0 - (..) */\
629 " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\
630 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\
631 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\
632 " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\
633 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\
634 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */
635
636 MO_ONE_FRAME // frame 1
637 MO_ONE_FRAME // frame 2
638
639 " cmp r7, r3\n" // inputIndex - maxInIdx
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700640 " bcc 1b\n"
641 "2:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700642
643 " bic r6, r6, #0xC0000000\n" // phaseFraction & ...
644 // save modified values
645 " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction
646 " str r6, [r0]\n" // phaseFraction
647 " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex
648 " str r7, [r0]\n" // inputIndex
649 " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out
650 " sub r8, r0\n" // curOut - out
651 " asr r8, #2\n" // new outputIndex
652 " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex
653 " str r8, [r0]\n" // save outputIndex
654
655 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
656 );
657}
658
659/*******************************************************************
660*
661* AsmStereo16Loop
662* asm optimized stereo loop version; one loop is 2 frames
663* Input:
664* in : pointer on input samples
665* maxOutPt : pointer on first not filled
666* maxInIdx : index on first not used
667* outputIndex : pointer on current output index
668* out : pointer on output buffer
669* inputIndex : pointer on current input index
670* vl, vr : left and right gain
671* phaseFraction : pointer on current phase fraction
672* phaseIncrement
673* Ouput:
674* outputIndex :
675* out : updated buffer
676* inputIndex : index of next to use
677* phaseFraction : phase fraction for next interpolation
678*
679*******************************************************************/
Glenn Kastenc23e2f22011-11-17 13:27:22 -0800680__attribute__((noinline))
Mathias Agopian65ab4712010-07-14 17:59:35 -0700681void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
682 size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
683 uint32_t &phaseFraction, uint32_t phaseIncrement)
684{
Andy Hungee931ff2014-01-28 13:44:14 -0800685 (void)maxOutPt; // remove unused parameter warnings
686 (void)maxInIdx;
687 (void)outputIndex;
688 (void)out;
689 (void)inputIndex;
690 (void)vl;
691 (void)vr;
692 (void)phaseFraction;
693 (void)phaseIncrement;
694 (void)in;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700695#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex)
696 asm(
697 "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
698 // get parameters
699 " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction
700 " ldr r6, [r6]\n" // phaseFraction
701 " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex
702 " ldr r7, [r7]\n" // inputIndex
703 " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out
704 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex
705 " ldr r0, [r0]\n" // outputIndex
synergy dev5f51ade2014-02-04 06:38:33 -0500706 " add r8, r8, r0, asl #2\n" // curOut
Mathias Agopian65ab4712010-07-14 17:59:35 -0700707 " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement
708 " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl
709 " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr
710
711 // r0 pin, x0, Samp
712
713 // r1 in
714 // r2 maxOutPt
715 // r3 maxInIdx
716
717 // r4 x1, i1, i3, out1
718 // r5 out0
719
720 // r6 frac
721 // r7 inputIndex
722 // r8 curOut
723
724 // r9 inc
725 // r10 vl
726 // r11 vr
727
728 // r12 temporary
729 // r13 sp
730 // r14
731
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700732 "3:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700733 " cmp r8, r2\n" // curOut - maxCurOut
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700734 " bcs 4f\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700735
736#define ST_ONE_FRAME \
737 " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\
738\
739 " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\
740\
741 " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\
742 " ldr r5, [r8]\n" /* out[outputIndex] */\
743 " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\
744 " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\
745 " mov r4, r4, lsl #2\n" /* <<2 */\
746 " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\
747 " add r12, r12, r4\n" /* x0 - (..) */\
748 " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\
749 " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\
750 " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\
751\
752 " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\
753 " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\
754 " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\
755 " mov r12, r12, lsl #2\n" /* <<2 */\
756 " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\
757 " add r12, r0, r12\n" /* x0 - (..) */\
758 " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\
759 " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\
760\
761 " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\
762 " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */
763
764 ST_ONE_FRAME // frame 1
765 ST_ONE_FRAME // frame 1
766
767 " cmp r7, r3\n" // inputIndex - maxInIdx
Nick Kralevicheb8b9142011-09-16 13:14:16 -0700768 " bcc 3b\n"
769 "4:\n"
Mathias Agopian65ab4712010-07-14 17:59:35 -0700770
771 " bic r6, r6, #0xC0000000\n" // phaseFraction & ...
772 // save modified values
773 " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction
774 " str r6, [r0]\n" // phaseFraction
775 " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex
776 " str r7, [r0]\n" // inputIndex
777 " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out
778 " sub r8, r0\n" // curOut - out
779 " asr r8, #2\n" // new outputIndex
780 " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex
781 " str r8, [r0]\n" // save outputIndex
782
783 " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
784 );
785}
786
787#endif // ASM_ARM_RESAMP1
788
789
790// ----------------------------------------------------------------------------
Mathias Agopian65ab4712010-07-14 17:59:35 -0700791
Glenn Kastenc23e2f22011-11-17 13:27:22 -0800792} // namespace android