blob: 0ae4b645e401cccab0afae033bf4b9be5de53fc7 [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
Mathias Agopian65ab4712010-07-14 17:59:35 -070020#include <string.h>
21#include "AudioResamplerSinc.h"
SathishKumar Mani76b11162012-01-17 10:49:47 -080022#include <dlfcn.h>
23#include <cutils/properties.h>
24#include <stdlib.h>
25#include <utils/Log.h>
Mathias Agopian65ab4712010-07-14 17:59:35 -070026
27namespace android {
28// ----------------------------------------------------------------------------
29
30
31/*
32 * These coeficients are computed with the "fir" utility found in
33 * tools/resampler_tools
34 * TODO: A good optimization would be to transpose this matrix, to take
35 * better advantage of the data-cache.
36 */
37const int32_t AudioResamplerSinc::mFirCoefsUp[] = {
38 0x7fffffff, 0x7f15d078, 0x7c5e0da6, 0x77ecd867, 0x71e2e251, 0x6a6c304a, 0x61be7269, 0x58170412, 0x4db8ab05, 0x42e92ea6, 0x37eee214, 0x2d0e3bb1, 0x22879366, 0x18951e95, 0x0f693d0d, 0x072d2621,
39 0x00000000, 0xf9f66655, 0xf51a5fd7, 0xf16bbd84, 0xeee0d9ac, 0xed67a922, 0xece70de6, 0xed405897, 0xee50e505, 0xeff3be30, 0xf203370f, 0xf45a6741, 0xf6d67d53, 0xf957db66, 0xfbc2f647, 0xfe00f2b9,
40 0x00000000, 0x01b37218, 0x0313a0c6, 0x041d930d, 0x04d28057, 0x053731b0, 0x05534dff, 0x05309bfd, 0x04da440d, 0x045c1aee, 0x03c1fcdd, 0x03173ef5, 0x02663ae8, 0x01b7f736, 0x0113ec79, 0x007fe6a9,
41 0x00000000, 0xff96b229, 0xff44f99f, 0xff0a86be, 0xfee5f803, 0xfed518fd, 0xfed521fd, 0xfee2f4fd, 0xfefb54f8, 0xff1b159b, 0xff3f4203, 0xff6539e0, 0xff8ac502, 0xffae1ddd, 0xffcdf3f9, 0xffe96798,
42 0x00000000, 0x00119de6, 0x001e6b7e, 0x0026cb7a, 0x002b4830, 0x002c83d6, 0x002b2a82, 0x0027e67a, 0x002356f9, 0x001e098e, 0x001875e4, 0x0012fbbe, 0x000de2d1, 0x00095c10, 0x00058414, 0x00026636,
43 0x00000000, 0xfffe44a9, 0xfffd206d, 0xfffc7b7f, 0xfffc3c8f, 0xfffc4ac2, 0xfffc8f2b, 0xfffcf5c4, 0xfffd6df3, 0xfffdeab2, 0xfffe6275, 0xfffececf, 0xffff2c07, 0xffff788c, 0xffffb471, 0xffffe0f2,
44 0x00000000, 0x000013e6, 0x00001f03, 0x00002396, 0x00002399, 0x000020b6, 0x00001c3c, 0x00001722, 0x00001216, 0x00000d81, 0x0000099c, 0x0000067c, 0x00000419, 0x0000025f, 0x00000131, 0x00000070,
45 0x00000000, 0xffffffc7, 0xffffffb3, 0xffffffb3, 0xffffffbe, 0xffffffcd, 0xffffffdb, 0xffffffe7, 0xfffffff0, 0xfffffff7, 0xfffffffb, 0xfffffffe, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
46 0x00000000 // this one is needed for lerping the last coefficient
47};
48
49/*
50 * These coefficients are optimized for 48KHz -> 44.1KHz (stop-band at 22.050KHz)
51 * It's possible to use the above coefficient for any down-sampling
52 * at the expense of a slower processing loop (we can interpolate
53 * these coefficient from the above by "Stretching" them in time).
54 */
55const int32_t AudioResamplerSinc::mFirCoefsDown[] = {
56 0x7fffffff, 0x7f55e46d, 0x7d5b4c60, 0x7a1b4b98, 0x75a7fb14, 0x7019f0bd, 0x698f875a, 0x622bfd59, 0x5a167256, 0x5178cc54, 0x487e8e6c, 0x3f53aae8, 0x36235ad4, 0x2d17047b, 0x245539ab, 0x1c00d540,
57 0x14383e57, 0x0d14d5ca, 0x06aa910b, 0x0107c38b, 0xfc351654, 0xf835abae, 0xf5076b45, 0xf2a37202, 0xf0fe9faa, 0xf00a3bbd, 0xefb4aa81, 0xefea2b05, 0xf0959716, 0xf1a11e83, 0xf2f6f7a0, 0xf481fff4,
58 0xf62e48ce, 0xf7e98ca5, 0xf9a38b4c, 0xfb4e4bfa, 0xfcde456f, 0xfe4a6d30, 0xff8c2fdf, 0x009f5555, 0x0181d393, 0x0233940f, 0x02b62f06, 0x030ca07d, 0x033afa62, 0x03461725, 0x03334f83, 0x030835fa,
59 0x02ca59cc, 0x027f12d1, 0x022b570d, 0x01d39a49, 0x017bb78f, 0x0126e414, 0x00d7aaaf, 0x008feec7, 0x0050f584, 0x001b73e3, 0xffefa063, 0xffcd46ed, 0xffb3ddcd, 0xffa29aaa, 0xff988691, 0xff949066,
60 0xff959d24, 0xff9a959e, 0xffa27195, 0xffac4011, 0xffb72d2b, 0xffc28569, 0xffcdb706, 0xffd85171, 0xffe20364, 0xffea97e9, 0xfff1f2b2, 0xfff80c06, 0xfffcec92, 0x0000a955, 0x00035fd8, 0x000532cf,
61 0x00064735, 0x0006c1f9, 0x0006c62d, 0x000673ba, 0x0005e68f, 0x00053630, 0x000475a3, 0x0003b397, 0x0002fac1, 0x00025257, 0x0001be9e, 0x0001417a, 0x0000dafd, 0x000089eb, 0x00004c28, 0x00001f1d,
62 0x00000000, 0xffffec10, 0xffffe0be, 0xffffdbc5, 0xffffdb39, 0xffffdd8b, 0xffffe182, 0xffffe638, 0xffffeb0a, 0xffffef8f, 0xfffff38b, 0xfffff6e3, 0xfffff993, 0xfffffba6, 0xfffffd30, 0xfffffe4a,
63 0xffffff09, 0xffffff85, 0xffffffd1, 0xfffffffb, 0x0000000f, 0x00000016, 0x00000015, 0x00000012, 0x0000000d, 0x00000009, 0x00000006, 0x00000003, 0x00000002, 0x00000001, 0x00000000, 0x00000000,
64 0x00000000 // this one is needed for lerping the last coefficient
65};
66
SathishKumar Mani76b11162012-01-17 10:49:47 -080067//Define the static variables
68int AudioResamplerSinc::coefsBits;
69int AudioResamplerSinc::cShift;
70uint32_t AudioResamplerSinc::cMask;
71int AudioResamplerSinc::pShift;
72uint32_t AudioResamplerSinc::pMask;
73unsigned int AudioResamplerSinc::halfNumCoefs;
74
Mathias Agopian65ab4712010-07-14 17:59:35 -070075// ----------------------------------------------------------------------------
76
77static inline
78int32_t mulRL(int left, int32_t in, uint32_t vRL)
79{
80#if defined(__arm__) && !defined(__thumb__)
81 int32_t out;
82 if (left) {
83 asm( "smultb %[out], %[in], %[vRL] \n"
84 : [out]"=r"(out)
85 : [in]"%r"(in), [vRL]"r"(vRL)
86 : );
87 } else {
88 asm( "smultt %[out], %[in], %[vRL] \n"
89 : [out]"=r"(out)
90 : [in]"%r"(in), [vRL]"r"(vRL)
91 : );
92 }
93 return out;
94#else
95 if (left) {
96 return int16_t(in>>16) * int16_t(vRL&0xFFFF);
97 } else {
98 return int16_t(in>>16) * int16_t(vRL>>16);
99 }
100#endif
101}
102
103static inline
104int32_t mulAdd(int16_t in, int32_t v, int32_t a)
105{
106#if defined(__arm__) && !defined(__thumb__)
107 int32_t out;
108 asm( "smlawb %[out], %[v], %[in], %[a] \n"
109 : [out]"=r"(out)
110 : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
111 : );
112 return out;
113#else
114 return a + in * (v>>16);
115 // improved precision
116 // return a + in * (v>>16) + ((in * (v & 0xffff)) >> 16);
117#endif
118}
119
120static inline
121int32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
122{
123#if defined(__arm__) && !defined(__thumb__)
124 int32_t out;
125 if (left) {
126 asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
127 : [out]"=r"(out)
128 : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
129 : );
130 } else {
131 asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
132 : [out]"=r"(out)
133 : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
134 : );
135 }
136 return out;
137#else
138 if (left) {
139 return a + (int16_t(inRL&0xFFFF) * (v>>16));
140 //improved precision
141 // return a + (int16_t(inRL&0xFFFF) * (v>>16)) + ((int16_t(inRL&0xFFFF) * (v & 0xffff)) >> 16);
142 } else {
143 return a + (int16_t(inRL>>16) * (v>>16));
144 }
145#endif
146}
147
148// ----------------------------------------------------------------------------
149
150AudioResamplerSinc::AudioResamplerSinc(int bitDepth,
SathishKumar Mani76b11162012-01-17 10:49:47 -0800151 int inChannelCount, int32_t sampleRate, int32_t quality)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700152 : AudioResampler(bitDepth, inChannelCount, sampleRate),
153 mState(0)
154{
155 /*
156 * Layout of the state buffer for 32 tap:
157 *
158 * "present" sample beginning of 2nd buffer
159 * v v
160 * 0 01 2 23 3
161 * 0 F0 0 F0 F
162 * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
163 * ^ ^ head
164 *
165 * p = past samples, convoluted with the (p)ositive side of sinc()
166 * n = future samples, convoluted with the (n)egative side of sinc()
167 * r = extra space for implementing the ring buffer
168 *
169 */
170
SathishKumar Mani76b11162012-01-17 10:49:47 -0800171 mResampleCoeffLib = NULL;
172 //Intialize the parameters for resampler coefficients
173 //for high quality
174 coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
175 cShift = kNumPhaseBits - coefsBits;
176 cMask = ((1<< coefsBits)-1) << cShift;
177
178 pShift = kNumPhaseBits - coefsBits - pLerpBits;
179 pMask = ((1<< pLerpBits)-1) << pShift;
180
181 halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
182
183 //Check if qcom highest quality can be used
184 char value[PROPERTY_VALUE_MAX];
185 //Open the dll to get the coefficients for VERY_HIGH_QUALITY
186 if (quality == VERY_HIGH_QUALITY ) {
187 mResampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW);
188 ALOGV("Open libaudio-resampler library = %p",mResampleCoeffLib);
189 if (mResampleCoeffLib == NULL) {
190 ALOGE("Could not open audio-resampler library: %s", dlerror());
191 return;
192 }
193 mReadResampleCoefficients = (readCoefficientsFn)dlsym(mResampleCoeffLib, "readResamplerCoefficients");
194 mReadResampleFirNumCoeff = (readResampleFirNumCoeffFn)dlsym(mResampleCoeffLib, "readResampleFirNumCoeff");
195 mReadResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn)dlsym(mResampleCoeffLib,"readResampleFirLerpIntBits");
196 if (!mReadResampleCoefficients || !mReadResampleFirNumCoeff || !mReadResampleFirLerpIntBits) {
197 mReadResampleCoefficients = NULL;
198 mReadResampleFirNumCoeff = NULL;
199 mReadResampleFirLerpIntBits = NULL;
200 dlclose(mResampleCoeffLib);
201 mResampleCoeffLib = NULL;
202 ALOGE("Could not find convert symbol: %s", dlerror());
203 return;
204 }
205 // we have 16 coefs samples per zero-crossing
206 coefsBits = mReadResampleFirLerpIntBits();
207 ALOGV("coefsBits = %d",coefsBits);
208 cShift = kNumPhaseBits - coefsBits;
209 cMask = ((1<<coefsBits)-1) << cShift;
210 pShift = kNumPhaseBits - coefsBits - pLerpBits;
211 pMask = ((1<<pLerpBits)-1) << pShift;
212 // number of zero-crossing on each side
213 halfNumCoefs = mReadResampleFirNumCoeff();
214 ALOGV("halfNumCoefs = %d",halfNumCoefs);
215 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700216}
217
SathishKumar Mani76b11162012-01-17 10:49:47 -0800218
Mathias Agopian65ab4712010-07-14 17:59:35 -0700219AudioResamplerSinc::~AudioResamplerSinc()
220{
SathishKumar Mani76b11162012-01-17 10:49:47 -0800221 if(mResampleCoeffLib) {
222 ALOGV("close the libaudio-resampler library");
223 dlclose(mResampleCoeffLib);
224 mResampleCoeffLib = NULL;
225 mReadResampleCoefficients = NULL;
226 mReadResampleFirNumCoeff = NULL;
227 mReadResampleFirLerpIntBits = NULL;
228 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700229 delete [] mState;
230}
231
232void AudioResamplerSinc::init() {
SathishKumar Mani76b11162012-01-17 10:49:47 -0800233
234 const size_t numCoefs = 2*halfNumCoefs;
235 const size_t stateSize = numCoefs * mChannelCount * 2;
236 mState = new int16_t[stateSize];
237 memset(mState, 0, sizeof(int16_t)*stateSize);
238 mImpulse = mState + (halfNumCoefs-1)*mChannelCount;
239 mRingFull = mImpulse + (numCoefs+1)*mChannelCount;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700240}
241
242void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
243 AudioBufferProvider* provider)
244{
SathishKumar Mani76b11162012-01-17 10:49:47 -0800245
246 if(mResampleCoeffLib){
247 ALOGV("get coefficient from libmm-audio resampler library");
248 mFirCoefs = (mInSampleRate <= mSampleRate) ? mReadResampleCoefficients(true) : mReadResampleCoefficients(false);
249 }
250 else {
251 ALOGV("Use default coefficients");
252 mFirCoefs = (mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown;
253 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700254
255 // select the appropriate resampler
256 switch (mChannelCount) {
257 case 1:
258 resample<1>(out, outFrameCount, provider);
259 break;
260 case 2:
261 resample<2>(out, outFrameCount, provider);
262 break;
263 }
SathishKumar Mani76b11162012-01-17 10:49:47 -0800264
Mathias Agopian65ab4712010-07-14 17:59:35 -0700265}
266
267
268template<int CHANNELS>
269void AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
270 AudioBufferProvider* provider)
271{
272 int16_t* impulse = mImpulse;
273 uint32_t vRL = mVolumeRL;
274 size_t inputIndex = mInputIndex;
275 uint32_t phaseFraction = mPhaseFraction;
276 uint32_t phaseIncrement = mPhaseIncrement;
277 size_t outputIndex = 0;
278 size_t outputSampleCount = outFrameCount * 2;
279 size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
280
Mathias Agopian65ab4712010-07-14 17:59:35 -0700281 while (outputIndex < outputSampleCount) {
282 // buffer is empty, fetch a new one
Glenn Kastend198b612012-02-02 14:09:43 -0800283 while (mBuffer.frameCount == 0) {
284 mBuffer.frameCount = inFrameCount;
John Grossman4ff14ba2012-02-08 16:37:41 -0800285 provider->getNextBuffer(&mBuffer,
286 calculateOutputPTS(outputIndex / 2));
Glenn Kastend198b612012-02-02 14:09:43 -0800287 if (mBuffer.raw == NULL) {
Mathias Agopian65ab4712010-07-14 17:59:35 -0700288 goto resample_exit;
289 }
290 const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
291 if (phaseIndex == 1) {
292 // read one frame
Glenn Kastend198b612012-02-02 14:09:43 -0800293 read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700294 } else if (phaseIndex == 2) {
295 // read 2 frames
Glenn Kastend198b612012-02-02 14:09:43 -0800296 read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700297 inputIndex++;
298 if (inputIndex >= mBuffer.frameCount) {
299 inputIndex -= mBuffer.frameCount;
Glenn Kastend198b612012-02-02 14:09:43 -0800300 provider->releaseBuffer(&mBuffer);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700301 } else {
Glenn Kastend198b612012-02-02 14:09:43 -0800302 read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700303 }
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700304 }
Mathias Agopian65ab4712010-07-14 17:59:35 -0700305 }
Glenn Kastend198b612012-02-02 14:09:43 -0800306 int16_t *in = mBuffer.i16;
307 const size_t frameCount = mBuffer.frameCount;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700308
309 // Always read-in the first samples from the input buffer
310 int16_t* head = impulse + halfNumCoefs*CHANNELS;
311 head[0] = in[inputIndex*CHANNELS + 0];
312 if (CHANNELS == 2)
313 head[1] = in[inputIndex*CHANNELS + 1];
314
315 // handle boundary case
316 int32_t l, r;
317 while (outputIndex < outputSampleCount) {
318 filterCoefficient<CHANNELS>(l, r, phaseFraction, impulse);
319 out[outputIndex++] += 2 * mulRL(1, l, vRL);
320 out[outputIndex++] += 2 * mulRL(0, r, vRL);
321
322 phaseFraction += phaseIncrement;
323 const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
324 if (phaseIndex == 1) {
325 inputIndex++;
326 if (inputIndex >= frameCount)
327 break; // need a new buffer
328 read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
Glenn Kastene53b9ea2012-03-12 16:29:55 -0700329 } else if (phaseIndex == 2) { // maximum value
Mathias Agopian65ab4712010-07-14 17:59:35 -0700330 inputIndex++;
331 if (inputIndex >= frameCount)
332 break; // 0 frame available, 2 frames needed
333 // read first frame
334 read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
335 inputIndex++;
336 if (inputIndex >= frameCount)
337 break; // 0 frame available, 1 frame needed
338 // read second frame
339 read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
340 }
341 }
342
343 // if done with buffer, save samples
344 if (inputIndex >= frameCount) {
345 inputIndex -= frameCount;
Glenn Kastend198b612012-02-02 14:09:43 -0800346 provider->releaseBuffer(&mBuffer);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700347 }
348 }
349
350resample_exit:
351 mImpulse = impulse;
352 mInputIndex = inputIndex;
353 mPhaseFraction = phaseFraction;
354}
355
356template<int CHANNELS>
357/***
358* read()
359*
360* This function reads only one frame from input buffer and writes it in
361* state buffer
362*
363**/
364void AudioResamplerSinc::read(
365 int16_t*& impulse, uint32_t& phaseFraction,
Glenn Kasten54c3b662012-01-06 07:46:30 -0800366 const int16_t* in, size_t inputIndex)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700367{
368 const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
369 impulse += CHANNELS;
370 phaseFraction -= 1LU<<kNumPhaseBits;
371 if (impulse >= mRingFull) {
372 const size_t stateSize = (halfNumCoefs*2)*CHANNELS;
373 memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
374 impulse -= stateSize;
375 }
376 int16_t* head = impulse + halfNumCoefs*CHANNELS;
377 head[0] = in[inputIndex*CHANNELS + 0];
378 if (CHANNELS == 2)
379 head[1] = in[inputIndex*CHANNELS + 1];
380}
381
382template<int CHANNELS>
383void AudioResamplerSinc::filterCoefficient(
Glenn Kasten54c3b662012-01-06 07:46:30 -0800384 int32_t& l, int32_t& r, uint32_t phase, const int16_t *samples)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700385{
386 // compute the index of the coefficient on the positive side and
387 // negative side
388 uint32_t indexP = (phase & cMask) >> cShift;
389 uint16_t lerpP = (phase & pMask) >> pShift;
390 uint32_t indexN = (-phase & cMask) >> cShift;
391 uint16_t lerpN = (-phase & pMask) >> pShift;
392 if ((indexP == 0) && (lerpP == 0)) {
393 indexN = cMask >> cShift;
394 lerpN = pMask >> pShift;
395 }
396
397 l = 0;
398 r = 0;
Glenn Kasten54c3b662012-01-06 07:46:30 -0800399 const int32_t* coefs = mFirCoefs;
400 const int16_t *sP = samples;
401 const int16_t *sN = samples+CHANNELS;
Mathias Agopian65ab4712010-07-14 17:59:35 -0700402 for (unsigned int i=0 ; i<halfNumCoefs/4 ; i++) {
403 interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
404 interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
405 sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
406 interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
407 interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
408 sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
409 interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
410 interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
411 sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
412 interpolate<CHANNELS>(l, r, coefs+indexP, lerpP, sP);
413 interpolate<CHANNELS>(l, r, coefs+indexN, lerpN, sN);
414 sP -= CHANNELS; sN += CHANNELS; coefs += 1<<coefsBits;
415 }
416}
417
418template<int CHANNELS>
419void AudioResamplerSinc::interpolate(
420 int32_t& l, int32_t& r,
Glenn Kasten54c3b662012-01-06 07:46:30 -0800421 const int32_t* coefs, int16_t lerp, const int16_t* samples)
Mathias Agopian65ab4712010-07-14 17:59:35 -0700422{
423 int32_t c0 = coefs[0];
424 int32_t c1 = coefs[1];
425 int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
426 if (CHANNELS == 2) {
Glenn Kasten54c3b662012-01-06 07:46:30 -0800427 uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
Mathias Agopian65ab4712010-07-14 17:59:35 -0700428 l = mulAddRL(1, rl, sinc, l);
429 r = mulAddRL(0, rl, sinc, r);
430 } else {
431 r = l = mulAdd(samples[0], sinc, l);
432 }
433}
Mathias Agopian65ab4712010-07-14 17:59:35 -0700434// ----------------------------------------------------------------------------
435}; // namespace android