blob: 5a03a0dd8e59a28d78c1ac096cd2ea10c3baf20d [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
SathishKumar Mani76b11162012-01-17 10:49:47 -080017#define LOG_TAG "AudioResamplerSinc"
18//#define LOG_NDEBUG 0
19
Zhongwei Yao12b44bd2014-04-10 17:23:42 +010020#define __STDC_CONSTANT_MACROS
Mathias Agopian7aa7ed72012-11-05 01:51:37 -080021#include <malloc.h>
Johan Harvyl7d805b22018-11-12 08:02:18 +010022#include <pthread.h>
Mathias Agopian65ab4712010-07-14 17:59:35 -070023#include <string.h>
SathishKumar Mani76b11162012-01-17 10:49:47 -080024#include <stdlib.h>
Mathias Agopian46afbec2012-11-04 02:03:49 -080025#include <dlfcn.h>
26
Mathias Agopiana798c972012-11-03 23:37:53 -070027#include <cutils/compiler.h>
Mathias Agopian46afbec2012-11-04 02:03:49 -080028#include <cutils/properties.h>
29
30#include <utils/Log.h>
Andy Hung5e58b0a2014-06-23 19:07:29 -070031#include <audio_utils/primitives.h>
Mathias Agopian46afbec2012-11-04 02:03:49 -080032
33#include "AudioResamplerSinc.h"
34
Bernhard Rosenkraenzer4fbf2322014-09-19 01:50:16 +020035#if defined(__clang__) && !__has_builtin(__builtin_assume_aligned)
36#define __builtin_assume_aligned(p, a) \
37 (((uintptr_t(p) % (a)) == 0) ? (p) : (__builtin_unreachable(), (p)))
38#endif
Mathias Agopianad9af032012-11-04 15:16:13 -080039
40#if defined(__arm__) && !defined(__thumb__)
41#define USE_INLINE_ASSEMBLY (true)
42#else
43#define USE_INLINE_ASSEMBLY (false)
44#endif
45
Zhongwei Yao12b44bd2014-04-10 17:23:42 +010046#if defined(__aarch64__) || defined(__ARM_NEON__)
Glenn Kasten4699a6a2016-02-16 10:49:09 -080047#ifndef USE_NEON
48#define USE_NEON (true)
49#endif
Mathias Agopianad9af032012-11-04 15:16:13 -080050#else
Glenn Kasten4699a6a2016-02-16 10:49:09 -080051#define USE_NEON (false)
52#endif
53#if USE_NEON
54#include <arm_neon.h>
Mathias Agopianad9af032012-11-04 15:16:13 -080055#endif
56
Zhongwei Yao12b44bd2014-04-10 17:23:42 +010057#define UNUSED(x) ((void)(x))
Mathias Agopianad9af032012-11-04 15:16:13 -080058
Mathias Agopian65ab4712010-07-14 17:59:35 -070059namespace android {
60// ----------------------------------------------------------------------------
61
62
63/*
64 * These coeficients are computed with the "fir" utility found in
65 * tools/resampler_tools
Mathias Agopiand88a0512012-10-30 12:49:07 -070066 * cmd-line: fir -l 7 -s 48000 -c 20478
Mathias Agopian65ab4712010-07-14 17:59:35 -070067 */
Glenn Kastenc4974312012-12-14 07:13:28 -080068const uint32_t AudioResamplerSinc::mFirCoefsUp[] __attribute__ ((aligned (32))) = {
Glenn Kasten675933b2015-02-17 14:23:04 -080069#include "AudioResamplerSincUp.h"
Mathias Agopian65ab4712010-07-14 17:59:35 -070070};
71
72/*
Mathias Agopian443e6962012-10-26 13:48:42 -070073 * These coefficients are optimized for 48KHz -> 44.1KHz
Mathias Agopian4ed475d2012-11-01 21:03:46 -070074 * cmd-line: fir -l 7 -s 48000 -c 17189
Mathias Agopian65ab4712010-07-14 17:59:35 -070075 */
Glenn Kastenc4974312012-12-14 07:13:28 -080076const uint32_t AudioResamplerSinc::mFirCoefsDown[] __attribute__ ((aligned (32))) = {
Glenn Kasten675933b2015-02-17 14:23:04 -080077#include "AudioResamplerSincDown.h"
Mathias Agopian65ab4712010-07-14 17:59:35 -070078};
79
Glenn Kastenac602052012-10-01 14:04:31 -070080// we use 15 bits to interpolate between these samples
81// this cannot change because the mul below rely on it.
82static const int pLerpBits = 15;
83
84static pthread_once_t once_control = PTHREAD_ONCE_INIT;
85static readCoefficientsFn readResampleCoefficients = NULL;
86
87/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::highQualityConstants;
88/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::veryHighQualityConstants;
89
90void AudioResamplerSinc::init_routine()
91{
92 // for high quality resampler, the parameters for coefficients are compile-time constants
93 Constants *c = &highQualityConstants;
94 c->coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
95 c->cShift = kNumPhaseBits - c->coefsBits;
96 c->cMask = ((1<< c->coefsBits)-1) << c->cShift;
97 c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits;
98 c->pMask = ((1<< pLerpBits)-1) << c->pShift;
99 c->halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
100
101 // for very high quality resampler, the parameters are load-time constants
102 veryHighQualityConstants = highQualityConstants;
103
104 // Open the dll to get the coefficients for VERY_HIGH_QUALITY
105 void *resampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW);
106 ALOGV("Open libaudio-resampler library = %p", resampleCoeffLib);
107 if (resampleCoeffLib == NULL) {
108 ALOGE("Could not open audio-resampler library: %s", dlerror());
109 return;
110 }
111
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800112 readResampleFirNumCoeffFn readResampleFirNumCoeff;
113 readResampleFirLerpIntBitsFn readResampleFirLerpIntBits;
114
115 readResampleCoefficients = (readCoefficientsFn)
116 dlsym(resampleCoeffLib, "readResamplerCoefficients");
117 readResampleFirNumCoeff = (readResampleFirNumCoeffFn)
Glenn Kastenac602052012-10-01 14:04:31 -0700118 dlsym(resampleCoeffLib, "readResampleFirNumCoeff");
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800119 readResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn)
Glenn Kastenac602052012-10-01 14:04:31 -0700120 dlsym(resampleCoeffLib, "readResampleFirLerpIntBits");
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800121
Glenn Kastenac602052012-10-01 14:04:31 -0700122 if (!readResampleCoefficients || !readResampleFirNumCoeff || !readResampleFirLerpIntBits) {
123 readResampleCoefficients = NULL;
124 dlclose(resampleCoeffLib);
125 resampleCoeffLib = NULL;
126 ALOGE("Could not find symbol: %s", dlerror());
127 return;
128 }
129
130 c = &veryHighQualityConstants;
Glenn Kastenac602052012-10-01 14:04:31 -0700131 c->coefsBits = readResampleFirLerpIntBits();
Glenn Kastenac602052012-10-01 14:04:31 -0700132 c->cShift = kNumPhaseBits - c->coefsBits;
133 c->cMask = ((1<<c->coefsBits)-1) << c->cShift;
134 c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits;
135 c->pMask = ((1<<pLerpBits)-1) << c->pShift;
136 // number of zero-crossing on each side
137 c->halfNumCoefs = readResampleFirNumCoeff();
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800138 ALOGV("coefsBits = %d", c->coefsBits);
Glenn Kastenac602052012-10-01 14:04:31 -0700139 ALOGV("halfNumCoefs = %d", c->halfNumCoefs);
140 // note that we "leak" resampleCoeffLib until the process exits
141}
SathishKumar Mani76b11162012-01-17 10:49:47 -0800142
Mathias Agopian65ab4712010-07-14 17:59:35 -0700143// ----------------------------------------------------------------------------
144
Glenn Kasten57c4e6f2016-03-18 14:54:07 -0700145#if !USE_NEON
146
Mathias Agopian65ab4712010-07-14 17:59:35 -0700147static inline
148int32_t mulRL(int left, int32_t in, uint32_t vRL)
149{
Mathias Agopianad9af032012-11-04 15:16:13 -0800150#if USE_INLINE_ASSEMBLY
Mathias Agopian65ab4712010-07-14 17:59:35 -0700151 int32_t out;
152 if (left) {
153 asm( "smultb %[out], %[in], %[vRL] \n"
154 : [out]"=r"(out)
155 : [in]"%r"(in), [vRL]"r"(vRL)
156 : );
157 } else {
158 asm( "smultt %[out], %[in], %[vRL] \n"
159 : [out]"=r"(out)
160 : [in]"%r"(in), [vRL]"r"(vRL)
161 : );
162 }
163 return out;
164#else
Mathias Agopian1f09b4a2012-10-30 13:51:44 -0700165 int16_t v = left ? int16_t(vRL) : int16_t(vRL>>16);
166 return int32_t((int64_t(in) * v) >> 16);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700167#endif
168}
169
170static inline
171int32_t mulAdd(int16_t in, int32_t v, int32_t a)
172{
Mathias Agopianad9af032012-11-04 15:16:13 -0800173#if USE_INLINE_ASSEMBLY
Mathias Agopian65ab4712010-07-14 17:59:35 -0700174 int32_t out;
175 asm( "smlawb %[out], %[v], %[in], %[a] \n"
176 : [out]"=r"(out)
177 : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
178 : );
179 return out;
180#else
Mathias Agopian1f09b4a2012-10-30 13:51:44 -0700181 return a + int32_t((int64_t(v) * in) >> 16);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700182#endif
183}
184
185static inline
186int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
187{
Mathias Agopianad9af032012-11-04 15:16:13 -0800188#if USE_INLINE_ASSEMBLY
Mathias Agopian65ab4712010-07-14 17:59:35 -0700189 int32_t out;
190 if (left) {
191 asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
192 : [out]"=r"(out)
193 : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
194 : );
195 } else {
196 asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
197 : [out]"=r"(out)
198 : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
199 : );
200 }
201 return out;
202#else
Mathias Agopian1f09b4a2012-10-30 13:51:44 -0700203 int16_t s = left ? int16_t(inRL) : int16_t(inRL>>16);
204 return a + int32_t((int64_t(v) * s) >> 16);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700205#endif
206}
207
Glenn Kasten57c4e6f2016-03-18 14:54:07 -0700208#endif // !USE_NEON
209
Mathias Agopian65ab4712010-07-14 17:59:35 -0700210// ----------------------------------------------------------------------------
211
Andy Hung3348e362014-07-07 10:21:44 -0700212AudioResamplerSinc::AudioResamplerSinc(
Glenn Kastenac602052012-10-01 14:04:31 -0700213 int inChannelCount, int32_t sampleRate, src_quality quality)
Andy Hung3348e362014-07-07 10:21:44 -0700214 : AudioResampler(inChannelCount, sampleRate, quality),
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800215 mState(0), mImpulse(0), mRingFull(0), mFirCoefs(0)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700216{
217 /*
218 * Layout of the state buffer for 32 tap:
219 *
220 * "present" sample beginning of 2nd buffer
221 * v v
222 * 0 01 2 23 3
223 * 0 F0 0 F0 F
224 * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
225 * ^ ^ head
226 *
227 * p = past samples, convoluted with the (p)ositive side of sinc()
228 * n = future samples, convoluted with the (n)egative side of sinc()
229 * r = extra space for implementing the ring buffer
230 *
231 */
232
Mathias Agopian0d585c82012-11-10 03:26:39 -0800233 mVolumeSIMD[0] = 0;
234 mVolumeSIMD[1] = 0;
235
Glenn Kastenac602052012-10-01 14:04:31 -0700236 // Load the constants for coefficients
237 int ok = pthread_once(&once_control, init_routine);
238 if (ok != 0) {
239 ALOGE("%s pthread_once failed: %d", __func__, ok);
SathishKumar Mani76b11162012-01-17 10:49:47 -0800240 }
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800241 mConstants = (quality == VERY_HIGH_QUALITY) ?
242 &veryHighQualityConstants : &highQualityConstants;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700243}
244
SathishKumar Mani76b11162012-01-17 10:49:47 -0800245
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800246AudioResamplerSinc::~AudioResamplerSinc() {
247 free(mState);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700248}
249
250void AudioResamplerSinc::init() {
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800251 const Constants& c(*mConstants);
252 const size_t numCoefs = 2 * c.halfNumCoefs;
SathishKumar Mani76b11162012-01-17 10:49:47 -0800253 const size_t stateSize = numCoefs * mChannelCount * 2;
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800254 mState = (int16_t*)memalign(32, stateSize*sizeof(int16_t));
SathishKumar Mani76b11162012-01-17 10:49:47 -0800255 memset(mState, 0, sizeof(int16_t)*stateSize);
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800256 mImpulse = mState + (c.halfNumCoefs-1)*mChannelCount;
SathishKumar Mani76b11162012-01-17 10:49:47 -0800257 mRingFull = mImpulse + (numCoefs+1)*mChannelCount;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700258}
259
Andy Hung5e58b0a2014-06-23 19:07:29 -0700260void AudioResamplerSinc::setVolume(float left, float right) {
Mathias Agopian0d585c82012-11-10 03:26:39 -0800261 AudioResampler::setVolume(left, right);
Andy Hung5e58b0a2014-06-23 19:07:29 -0700262 // convert to U4_28 (rounding down).
263 // integer volume values are clamped to 0 to UNITY_GAIN.
264 mVolumeSIMD[0] = u4_28_from_float(clampFloatVol(left));
265 mVolumeSIMD[1] = u4_28_from_float(clampFloatVol(right));
Mathias Agopian0d585c82012-11-10 03:26:39 -0800266}
267
Andy Hung6b3b7e32015-03-29 00:49:22 -0700268size_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
Mathias Agopian65ab4712010-07-14 17:59:35 -0700269 AudioBufferProvider* provider)
270{
Glenn Kastenac602052012-10-01 14:04:31 -0700271 // FIXME store current state (up or down sample) and only load the coefs when the state
272 // changes. Or load two pointers one for up and one for down in the init function.
273 // Not critical now since the read functions are fast, but would be important if read was slow.
Mathias Agopian61ea1172012-10-21 03:04:05 -0700274 if (mConstants == &veryHighQualityConstants && readResampleCoefficients) {
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800275 mFirCoefs = readResampleCoefficients( mInSampleRate <= mSampleRate );
Glenn Kastenac602052012-10-01 14:04:31 -0700276 } else {
Glenn Kasten2f5aa012015-02-17 15:04:28 -0800277 mFirCoefs = (const int32_t *)
278 ((mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown);
SathishKumar Mani76b11162012-01-17 10:49:47 -0800279 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700280
281 // select the appropriate resampler
282 switch (mChannelCount) {
283 case 1:
Andy Hung6b3b7e32015-03-29 00:49:22 -0700284 return resample<1>(out, outFrameCount, provider);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700285 case 2:
Andy Hung6b3b7e32015-03-29 00:49:22 -0700286 return resample<2>(out, outFrameCount, provider);
287 default:
288 LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount);
289 return 0;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700290 }
291}
292
293
294template<int CHANNELS>
Andy Hung6b3b7e32015-03-29 00:49:22 -0700295size_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
Mathias Agopian65ab4712010-07-14 17:59:35 -0700296 AudioBufferProvider* provider)
297{
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800298 const Constants& c(*mConstants);
299 const size_t headOffset = c.halfNumCoefs*CHANNELS;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700300 int16_t* impulse = mImpulse;
301 uint32_t vRL = mVolumeRL;
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;
Andy Hung24781ff2014-02-19 12:45:19 -0800307 size_t inFrameCount = getInFrameCountRequired(outFrameCount);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700308
Mathias Agopian65ab4712010-07-14 17:59:35 -0700309 while (outputIndex < outputSampleCount) {
310 // buffer is empty, fetch a new one
Glenn Kastend198b612012-02-02 14:09:43 -0800311 while (mBuffer.frameCount == 0) {
312 mBuffer.frameCount = inFrameCount;
Glenn Kastend79072e2016-01-06 08:41:20 -0800313 provider->getNextBuffer(&mBuffer);
Glenn Kastend198b612012-02-02 14:09:43 -0800314 if (mBuffer.raw == NULL) {
Mathias Agopian65ab4712010-07-14 17:59:35 -0700315 goto resample_exit;
316 }
317 const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
318 if (phaseIndex == 1) {
319 // read one frame
Glenn Kastend198b612012-02-02 14:09:43 -0800320 read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700321 } else if (phaseIndex == 2) {
322 // read 2 frames
Glenn Kastend198b612012-02-02 14:09:43 -0800323 read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700324 inputIndex++;
325 if (inputIndex >= mBuffer.frameCount) {
326 inputIndex -= mBuffer.frameCount;
Glenn Kastend198b612012-02-02 14:09:43 -0800327 provider->releaseBuffer(&mBuffer);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700328 } else {
Glenn Kastend198b612012-02-02 14:09:43 -0800329 read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700330 }
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700331 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700332 }
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800333 int16_t const * const in = mBuffer.i16;
Glenn Kastend198b612012-02-02 14:09:43 -0800334 const size_t frameCount = mBuffer.frameCount;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700335
336 // Always read-in the first samples from the input buffer
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800337 int16_t* head = impulse + headOffset;
Mathias Agopiana798c972012-11-03 23:37:53 -0700338 for (size_t i=0 ; i<CHANNELS ; i++) {
339 head[i] = in[inputIndex*CHANNELS + i];
340 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700341
342 // handle boundary case
Mathias Agopiana798c972012-11-03 23:37:53 -0700343 while (CC_LIKELY(outputIndex < outputSampleCount)) {
Mathias Agopian0d585c82012-11-10 03:26:39 -0800344 filterCoefficient<CHANNELS>(&out[outputIndex], phaseFraction, impulse, vRL);
345 outputIndex += 2;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700346
347 phaseFraction += phaseIncrement;
Mathias Agopiana798c972012-11-03 23:37:53 -0700348 const size_t phaseIndex = phaseFraction >> kNumPhaseBits;
349 for (size_t i=0 ; i<phaseIndex ; i++) {
Mathias Agopian65ab4712010-07-14 17:59:35 -0700350 inputIndex++;
Mathias Agopiana798c972012-11-03 23:37:53 -0700351 if (inputIndex >= frameCount) {
352 goto done; // need a new buffer
353 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700354 read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
355 }
356 }
Mathias Agopiana798c972012-11-03 23:37:53 -0700357done:
Mathias Agopian65ab4712010-07-14 17:59:35 -0700358 // if done with buffer, save samples
359 if (inputIndex >= frameCount) {
360 inputIndex -= frameCount;
Glenn Kastend198b612012-02-02 14:09:43 -0800361 provider->releaseBuffer(&mBuffer);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700362 }
363 }
364
365resample_exit:
366 mImpulse = impulse;
367 mInputIndex = inputIndex;
368 mPhaseFraction = phaseFraction;
Andy Hung6b3b7e32015-03-29 00:49:22 -0700369 return outputIndex / CHANNELS;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700370}
371
372template<int CHANNELS>
373/***
374* read()
375*
376* This function reads only one frame from input buffer and writes it in
377* state buffer
378*
379**/
380void AudioResamplerSinc::read(
381 int16_t*& impulse, uint32_t& phaseFraction,
Glenn Kasten54c3b662012-01-06 07:46:30 -0800382 const int16_t* in, size_t inputIndex)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700383{
Mathias Agopian65ab4712010-07-14 17:59:35 -0700384 impulse += CHANNELS;
385 phaseFraction -= 1LU<<kNumPhaseBits;
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800386
387 const Constants& c(*mConstants);
Mathias Agopiana798c972012-11-03 23:37:53 -0700388 if (CC_UNLIKELY(impulse >= mRingFull)) {
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800389 const size_t stateSize = (c.halfNumCoefs*2)*CHANNELS;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700390 memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
391 impulse -= stateSize;
392 }
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800393
394 int16_t* head = impulse + c.halfNumCoefs*CHANNELS;
Mathias Agopiana798c972012-11-03 23:37:53 -0700395 for (size_t i=0 ; i<CHANNELS ; i++) {
396 head[i] = in[inputIndex*CHANNELS + i];
397 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700398}
399
400template<int CHANNELS>
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100401void AudioResamplerSinc::filterCoefficient(int32_t* out, uint32_t phase,
402 const int16_t *samples, uint32_t vRL)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700403{
Mathias Agopian7492a7f2012-11-10 04:44:30 -0800404 // NOTE: be very careful when modifying the code here. register
405 // pressure is very high and a small change might cause the compiler
406 // to generate far less efficient code.
407 // Always sanity check the result with objdump or test-resample.
408
Mathias Agopian65ab4712010-07-14 17:59:35 -0700409 // compute the index of the coefficient on the positive side and
410 // negative side
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800411 const Constants& c(*mConstants);
Mathias Agopian7492a7f2012-11-10 04:44:30 -0800412 const int32_t ONE = c.cMask | c.pMask;
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800413 uint32_t indexP = ( phase & c.cMask) >> c.cShift;
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800414 uint32_t lerpP = ( phase & c.pMask) >> c.pShift;
Mathias Agopian7492a7f2012-11-10 04:44:30 -0800415 uint32_t indexN = ((ONE-phase) & c.cMask) >> c.cShift;
416 uint32_t lerpN = ((ONE-phase) & c.pMask) >> c.pShift;
417
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800418 const size_t offset = c.halfNumCoefs;
Mathias Agopian46afbec2012-11-04 02:03:49 -0800419 indexP *= offset;
420 indexN *= offset;
421
Mathias Agopian7aa7ed72012-11-05 01:51:37 -0800422 int32_t const* coefsP = mFirCoefs + indexP;
423 int32_t const* coefsN = mFirCoefs + indexN;
Mathias Agopian46afbec2012-11-04 02:03:49 -0800424 int16_t const* sP = samples;
425 int16_t const* sN = samples + CHANNELS;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700426
Mathias Agopian46afbec2012-11-04 02:03:49 -0800427 size_t count = offset;
Mathias Agopianad9af032012-11-04 15:16:13 -0800428
Glenn Kasten4699a6a2016-02-16 10:49:09 -0800429#if !USE_NEON
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100430 int32_t l = 0;
431 int32_t r = 0;
432 for (size_t i=0 ; i<count ; i++) {
433 interpolate<CHANNELS>(l, r, coefsP++, offset, lerpP, sP);
434 sP -= CHANNELS;
435 interpolate<CHANNELS>(l, r, coefsN++, offset, lerpN, sN);
436 sN += CHANNELS;
437 }
438 out[0] += 2 * mulRL(1, l, vRL);
439 out[1] += 2 * mulRL(0, r, vRL);
440#else
441 UNUSED(vRL);
442 if (CHANNELS == 1) {
Mathias Agopianad9af032012-11-04 15:16:13 -0800443 int32_t const* coefsP1 = coefsP + offset;
444 int32_t const* coefsN1 = coefsN + offset;
445 sP -= CHANNELS*3;
Mathias Agopianad9af032012-11-04 15:16:13 -0800446
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100447 int32x4_t sum;
448 int32x2_t lerpPN;
449 lerpPN = vdup_n_s32(0);
450 lerpPN = vld1_lane_s32((int32_t *)&lerpP, lerpPN, 0);
451 lerpPN = vld1_lane_s32((int32_t *)&lerpN, lerpPN, 1);
452 lerpPN = vshl_n_s32(lerpPN, 16);
453 sum = vdupq_n_s32(0);
Mathias Agopianad9af032012-11-04 15:16:13 -0800454
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100455 int16x4_t sampleP, sampleN;
456 int32x4_t samplePExt, sampleNExt;
457 int32x4_t coefsPV0, coefsPV1, coefsNV0, coefsNV1;
Mathias Agopianad9af032012-11-04 15:16:13 -0800458
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100459 coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16);
460 coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16);
461 coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16);
462 coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16);
463 for (; count > 0; count -= 4) {
464 sampleP = vld1_s16(sP);
465 sampleN = vld1_s16(sN);
466 coefsPV0 = vld1q_s32(coefsP);
467 coefsNV0 = vld1q_s32(coefsN);
468 coefsPV1 = vld1q_s32(coefsP1);
469 coefsNV1 = vld1q_s32(coefsN1);
470 sP -= 4;
471 sN += 4;
472 coefsP += 4;
473 coefsN += 4;
474 coefsP1 += 4;
475 coefsN1 += 4;
Mathias Agopianad9af032012-11-04 15:16:13 -0800476
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100477 sampleP = vrev64_s16(sampleP);
Mathias Agopianad9af032012-11-04 15:16:13 -0800478
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100479 // interpolate (step1)
480 coefsPV1 = vsubq_s32(coefsPV1, coefsPV0);
481 coefsNV1 = vsubq_s32(coefsNV1, coefsNV0);
482 samplePExt = vshll_n_s16(sampleP, 15);
483 // interpolate (step2)
484 coefsPV1 = vqrdmulhq_lane_s32(coefsPV1, lerpPN, 0);
485 coefsNV1 = vqrdmulhq_lane_s32(coefsNV1, lerpPN, 1);
486 sampleNExt = vshll_n_s16(sampleN, 15);
487 // interpolate (step3)
488 coefsPV0 = vaddq_s32(coefsPV0, coefsPV1);
489 coefsNV0 = vaddq_s32(coefsNV0, coefsNV1);
Mathias Agopianad9af032012-11-04 15:16:13 -0800490
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100491 samplePExt = vqrdmulhq_s32(samplePExt, coefsPV0);
492 sampleNExt = vqrdmulhq_s32(sampleNExt, coefsNV0);
493 sum = vaddq_s32(sum, samplePExt);
494 sum = vaddq_s32(sum, sampleNExt);
495 }
496 int32x2_t volumesV, outV;
497 volumesV = vld1_s32(mVolumeSIMD);
498 outV = vld1_s32(out);
Mathias Agopianad9af032012-11-04 15:16:13 -0800499
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100500 //add all 4 partial sums
501 int32x2_t sumLow, sumHigh;
502 sumLow = vget_low_s32(sum);
503 sumHigh = vget_high_s32(sum);
504 sumLow = vpadd_s32(sumLow, sumHigh);
505 sumLow = vpadd_s32(sumLow, sumLow);
Mathias Agopianad9af032012-11-04 15:16:13 -0800506
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100507 sumLow = vqrdmulh_s32(sumLow, volumesV);
508 outV = vadd_s32(outV, sumLow);
509 vst1_s32(out, outV);
Mathias Agopianad9af032012-11-04 15:16:13 -0800510 } else if (CHANNELS == 2) {
511 int32_t const* coefsP1 = coefsP + offset;
512 int32_t const* coefsN1 = coefsN + offset;
513 sP -= CHANNELS*3;
Mathias Agopianad9af032012-11-04 15:16:13 -0800514
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100515 int32x4_t sum0, sum1;
516 int32x2_t lerpPN;
Mathias Agopianad9af032012-11-04 15:16:13 -0800517
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100518 lerpPN = vdup_n_s32(0);
519 lerpPN = vld1_lane_s32((int32_t *)&lerpP, lerpPN, 0);
520 lerpPN = vld1_lane_s32((int32_t *)&lerpN, lerpPN, 1);
521 lerpPN = vshl_n_s32(lerpPN, 16);
522 sum0 = vdupq_n_s32(0);
523 sum1 = vdupq_n_s32(0);
Mathias Agopianad9af032012-11-04 15:16:13 -0800524
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100525 int16x4x2_t sampleP, sampleN;
526 int32x4x2_t samplePExt, sampleNExt;
527 int32x4_t coefsPV0, coefsPV1, coefsNV0, coefsNV1;
Mathias Agopianad9af032012-11-04 15:16:13 -0800528
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100529 coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16);
530 coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16);
531 coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16);
532 coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16);
533 for (; count > 0; count -= 4) {
534 sampleP = vld2_s16(sP);
535 sampleN = vld2_s16(sN);
536 coefsPV0 = vld1q_s32(coefsP);
537 coefsNV0 = vld1q_s32(coefsN);
538 coefsPV1 = vld1q_s32(coefsP1);
539 coefsNV1 = vld1q_s32(coefsN1);
540 sP -= 8;
541 sN += 8;
542 coefsP += 4;
543 coefsN += 4;
544 coefsP1 += 4;
545 coefsN1 += 4;
Mathias Agopianad9af032012-11-04 15:16:13 -0800546
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100547 sampleP.val[0] = vrev64_s16(sampleP.val[0]);
548 sampleP.val[1] = vrev64_s16(sampleP.val[1]);
Mathias Agopianad9af032012-11-04 15:16:13 -0800549
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100550 // interpolate (step1)
551 coefsPV1 = vsubq_s32(coefsPV1, coefsPV0);
552 coefsNV1 = vsubq_s32(coefsNV1, coefsNV0);
553 samplePExt.val[0] = vshll_n_s16(sampleP.val[0], 15);
554 samplePExt.val[1] = vshll_n_s16(sampleP.val[1], 15);
555 // interpolate (step2)
556 coefsPV1 = vqrdmulhq_lane_s32(coefsPV1, lerpPN, 0);
557 coefsNV1 = vqrdmulhq_lane_s32(coefsNV1, lerpPN, 1);
558 sampleNExt.val[0] = vshll_n_s16(sampleN.val[0], 15);
559 sampleNExt.val[1] = vshll_n_s16(sampleN.val[1], 15);
560 // interpolate (step3)
561 coefsPV0 = vaddq_s32(coefsPV0, coefsPV1);
562 coefsNV0 = vaddq_s32(coefsNV0, coefsNV1);
Mathias Agopianad9af032012-11-04 15:16:13 -0800563
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100564 samplePExt.val[0] = vqrdmulhq_s32(samplePExt.val[0], coefsPV0);
565 samplePExt.val[1] = vqrdmulhq_s32(samplePExt.val[1], coefsPV0);
566 sampleNExt.val[0] = vqrdmulhq_s32(sampleNExt.val[0], coefsNV0);
567 sampleNExt.val[1] = vqrdmulhq_s32(sampleNExt.val[1], coefsNV0);
568 sum0 = vaddq_s32(sum0, samplePExt.val[0]);
569 sum1 = vaddq_s32(sum1, samplePExt.val[1]);
570 sum0 = vaddq_s32(sum0, sampleNExt.val[0]);
571 sum1 = vaddq_s32(sum1, sampleNExt.val[1]);
572 }
573 int32x2_t volumesV, outV;
574 volumesV = vld1_s32(mVolumeSIMD);
575 outV = vld1_s32(out);
Mathias Agopianad9af032012-11-04 15:16:13 -0800576
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100577 //add all 4 partial sums
578 int32x2_t sumLow0, sumHigh0, sumLow1, sumHigh1;
579 sumLow0 = vget_low_s32(sum0);
580 sumHigh0 = vget_high_s32(sum0);
581 sumLow1 = vget_low_s32(sum1);
582 sumHigh1 = vget_high_s32(sum1);
583 sumLow0 = vpadd_s32(sumLow0, sumHigh0);
584 sumLow0 = vpadd_s32(sumLow0, sumLow0);
585 sumLow1 = vpadd_s32(sumLow1, sumHigh1);
586 sumLow1 = vpadd_s32(sumLow1, sumLow1);
Mathias Agopianad9af032012-11-04 15:16:13 -0800587
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100588 sumLow0 = vtrn_s32(sumLow0, sumLow1).val[0];
589 sumLow0 = vqrdmulh_s32(sumLow0, volumesV);
590 outV = vadd_s32(outV, sumLow0);
591 vst1_s32(out, outV);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700592 }
Zhongwei Yao12b44bd2014-04-10 17:23:42 +0100593#endif
Mathias Agopian65ab4712010-07-14 17:59:35 -0700594}
595
596template<int CHANNELS>
597void AudioResamplerSinc::interpolate(
598 int32_t& l, int32_t& r,
Mathias Agopian46afbec2012-11-04 02:03:49 -0800599 const int32_t* coefs, size_t offset,
600 int32_t lerp, const int16_t* samples)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700601{
602 int32_t c0 = coefs[0];
Mathias Agopian46afbec2012-11-04 02:03:49 -0800603 int32_t c1 = coefs[offset];
Mathias Agopian65ab4712010-07-14 17:59:35 -0700604 int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
605 if (CHANNELS == 2) {
Glenn Kasten54c3b662012-01-06 07:46:30 -0800606 uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700607 l = mulAddRL(1, rl, sinc, l);
608 r = mulAddRL(0, rl, sinc, r);
609 } else {
610 r = l = mulAdd(samples[0], sinc, l);
611 }
612}
Mathias Agopian65ab4712010-07-14 17:59:35 -0700613// ----------------------------------------------------------------------------
Glenn Kasten63238ef2015-03-02 15:50:29 -0800614} // namespace android