165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/*
265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * Copyright (C) 2007 The Android Open Source Project
365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *
465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * Licensed under the Apache License, Version 2.0 (the "License");
565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * you may not use this file except in compliance with the License.
665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * You may obtain a copy of the License at
765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *
865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *      http://www.apache.org/licenses/LICENSE-2.0
965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *
1065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * Unless required by applicable law or agreed to in writing, software
1165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * distributed under the License is distributed on an "AS IS" BASIS,
1265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * See the License for the specific language governing permissions and
1465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * limitations under the License.
1565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian */
1665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
1776b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani#define LOG_TAG "AudioResamplerSinc"
1876b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani//#define LOG_NDEBUG 0
1976b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani
2012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#define __STDC_CONSTANT_MACROS
217aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian#include <malloc.h>
2265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <string.h>
2346afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian#include <stdlib.h>
2476b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani#include <dlfcn.h>
2546afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian
2646afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian#include <cutils/compiler.h>
2776b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani#include <cutils/properties.h>
2846afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian
2976b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani#include <utils/Log.h>
305e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung#include <audio_utils/primitives.h>
3146afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian
3246afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian#include "AudioResamplerSinc.h"
3346afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian
344fbf23238e3f927871576170d1a38c855e04473eBernhard Rosenkraenzer#if defined(__clang__) && !__has_builtin(__builtin_assume_aligned)
354fbf23238e3f927871576170d1a38c855e04473eBernhard Rosenkraenzer#define __builtin_assume_aligned(p, a) \
364fbf23238e3f927871576170d1a38c855e04473eBernhard Rosenkraenzer	(((uintptr_t(p) % (a)) == 0) ? (p) : (__builtin_unreachable(), (p)))
374fbf23238e3f927871576170d1a38c855e04473eBernhard Rosenkraenzer#endif
38ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian
39ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#if defined(__arm__) && !defined(__thumb__)
40ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#define USE_INLINE_ASSEMBLY (true)
41ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#else
42ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#define USE_INLINE_ASSEMBLY (false)
43ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#endif
44ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian
4512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#if defined(__aarch64__) || defined(__ARM_NEON__)
464699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#ifndef USE_NEON
474699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#define USE_NEON (true)
484699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#endif
49ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#else
504699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#define USE_NEON (false)
514699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#endif
524699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#if USE_NEON
534699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#include <arm_neon.h>
54ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#endif
55ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian
5612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#define UNUSED(x) ((void)(x))
57ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian
5865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android {
5965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
6065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
6165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
6265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/*
6365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * These coeficients are computed with the "fir" utility found in
6465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * tools/resampler_tools
65d88a051aff15fdf5c57e1e5a4083bbd9635af3adMathias Agopian * cmd-line: fir -l 7 -s 48000 -c 20478
6665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian */
67c4974312e5a1e2ab94eca56045f991baf1508d73Glenn Kastenconst uint32_t AudioResamplerSinc::mFirCoefsUp[] __attribute__ ((aligned (32))) = {
68675933be11f2c24f9f66011345377d2840938646Glenn Kasten#include "AudioResamplerSincUp.h"
6965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian};
7065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
7165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/*
72443e69625d598ea578e2c838960778ce498fd773Mathias Agopian * These coefficients are optimized for 48KHz -> 44.1KHz
734ed475d3ad4231370371e14a94779c5d300eb3c5Mathias Agopian * cmd-line: fir -l 7 -s 48000 -c 17189
7465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian */
75c4974312e5a1e2ab94eca56045f991baf1508d73Glenn Kastenconst uint32_t AudioResamplerSinc::mFirCoefsDown[] __attribute__ ((aligned (32))) = {
76675933be11f2c24f9f66011345377d2840938646Glenn Kasten#include "AudioResamplerSincDown.h"
7765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian};
7865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
79ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten// we use 15 bits to interpolate between these samples
80ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten// this cannot change because the mul below rely on it.
81ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic const int pLerpBits = 15;
82ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
83ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT;
84ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic readCoefficientsFn readResampleCoefficients = NULL;
85ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
86ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::highQualityConstants;
87ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::veryHighQualityConstants;
88ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
89ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenvoid AudioResamplerSinc::init_routine()
90ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{
91ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // for high quality resampler, the parameters for coefficients are compile-time constants
92ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    Constants *c = &highQualityConstants;
93ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->coefsBits = RESAMPLE_FIR_LERP_INT_BITS;
94ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->cShift = kNumPhaseBits - c->coefsBits;
95ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->cMask = ((1<< c->coefsBits)-1) << c->cShift;
96ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits;
97ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->pMask = ((1<< pLerpBits)-1) << c->pShift;
98ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->halfNumCoefs = RESAMPLE_FIR_NUM_COEF;
99ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
100ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // for very high quality resampler, the parameters are load-time constants
101ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    veryHighQualityConstants = highQualityConstants;
102ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
103ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // Open the dll to get the coefficients for VERY_HIGH_QUALITY
104ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    void *resampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW);
105ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    ALOGV("Open libaudio-resampler library = %p", resampleCoeffLib);
106ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    if (resampleCoeffLib == NULL) {
107ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        ALOGE("Could not open audio-resampler library: %s", dlerror());
108ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return;
109ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    }
110ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
1117aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    readResampleFirNumCoeffFn readResampleFirNumCoeff;
1127aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    readResampleFirLerpIntBitsFn readResampleFirLerpIntBits;
1137aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian
1147aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    readResampleCoefficients = (readCoefficientsFn)
1157aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian            dlsym(resampleCoeffLib, "readResamplerCoefficients");
1167aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    readResampleFirNumCoeff = (readResampleFirNumCoeffFn)
117ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            dlsym(resampleCoeffLib, "readResampleFirNumCoeff");
1187aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    readResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn)
119ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            dlsym(resampleCoeffLib, "readResampleFirLerpIntBits");
1207aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian
121ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    if (!readResampleCoefficients || !readResampleFirNumCoeff || !readResampleFirLerpIntBits) {
122ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        readResampleCoefficients = NULL;
123ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        dlclose(resampleCoeffLib);
124ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        resampleCoeffLib = NULL;
125ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        ALOGE("Could not find symbol: %s", dlerror());
126ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return;
127ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    }
128ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
129ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c = &veryHighQualityConstants;
130ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->coefsBits = readResampleFirLerpIntBits();
131ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->cShift = kNumPhaseBits - c->coefsBits;
132ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->cMask = ((1<<c->coefsBits)-1) << c->cShift;
133ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits;
134ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->pMask = ((1<<pLerpBits)-1) << c->pShift;
135ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // number of zero-crossing on each side
136ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    c->halfNumCoefs = readResampleFirNumCoeff();
1377aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    ALOGV("coefsBits = %d", c->coefsBits);
138ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    ALOGV("halfNumCoefs = %d", c->halfNumCoefs);
139ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // note that we "leak" resampleCoeffLib until the process exits
140ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten}
14176b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani
14265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
14365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
14457c4e6f7464d458eb52d209c2a63524913d6406dGlenn Kasten#if !USE_NEON
14557c4e6f7464d458eb52d209c2a63524913d6406dGlenn Kasten
14665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianstatic inline
14765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianint32_t mulRL(int left, int32_t in, uint32_t vRL)
14865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
149ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#if USE_INLINE_ASSEMBLY
15065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t out;
15165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    if (left) {
15265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        asm( "smultb %[out], %[in], %[vRL] \n"
15365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [out]"=r"(out)
15465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [in]"%r"(in), [vRL]"r"(vRL)
15565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : );
15665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    } else {
15765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        asm( "smultt %[out], %[in], %[vRL] \n"
15865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [out]"=r"(out)
15965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [in]"%r"(in), [vRL]"r"(vRL)
16065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : );
16165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
16265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return out;
16365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#else
1641f09b4ada212d259b531228db67ca160d280275cMathias Agopian    int16_t v = left ? int16_t(vRL) : int16_t(vRL>>16);
1651f09b4ada212d259b531228db67ca160d280275cMathias Agopian    return int32_t((int64_t(in) * v) >> 16);
16665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif
16765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
16865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
16965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianstatic inline
17065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianint32_t mulAdd(int16_t in, int32_t v, int32_t a)
17165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
172ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#if USE_INLINE_ASSEMBLY
17365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t out;
17465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    asm( "smlawb %[out], %[v], %[in], %[a] \n"
17565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian         : [out]"=r"(out)
17665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian         : [in]"%r"(in), [v]"r"(v), [a]"r"(a)
17765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian         : );
17865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return out;
17965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#else
1801f09b4ada212d259b531228db67ca160d280275cMathias Agopian    return a + int32_t((int64_t(v) * in) >> 16);
18165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif
18265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
18365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
18465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianstatic inline
18565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianint32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a)
18665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
187ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#if USE_INLINE_ASSEMBLY
18865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t out;
18965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    if (left) {
19065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        asm( "smlawb %[out], %[v], %[inRL], %[a] \n"
19165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [out]"=r"(out)
19265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
19365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : );
19465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    } else {
19565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        asm( "smlawt %[out], %[v], %[inRL], %[a] \n"
19665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [out]"=r"(out)
19765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a)
19865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian             : );
19965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
20065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return out;
20165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#else
2021f09b4ada212d259b531228db67ca160d280275cMathias Agopian    int16_t s = left ? int16_t(inRL) : int16_t(inRL>>16);
2031f09b4ada212d259b531228db67ca160d280275cMathias Agopian    return a + int32_t((int64_t(v) * s) >> 16);
20465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif
20565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
20665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
20757c4e6f7464d458eb52d209c2a63524913d6406dGlenn Kasten#endif // !USE_NEON
20857c4e6f7464d458eb52d209c2a63524913d6406dGlenn Kasten
20965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
21065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2113348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResamplerSinc::AudioResamplerSinc(
212ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        int inChannelCount, int32_t sampleRate, src_quality quality)
2133348e36c51e91e78020bcc6578eda83d97c31becAndy Hung    : AudioResampler(inChannelCount, sampleRate, quality),
2147aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    mState(0), mImpulse(0), mRingFull(0), mFirCoefs(0)
21565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    /*
21765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     * Layout of the state buffer for 32 tap:
21865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     *
21965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     * "present" sample            beginning of 2nd buffer
22065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     *                 v                v
22165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     *  0              01               2              23              3
22265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     *  0              F0               0              F0              F
22365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn]
22465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     *                 ^               ^ head
22565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     *
22665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     * p = past samples, convoluted with the (p)ositive side of sinc()
22765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     * n = future samples, convoluted with the (n)egative side of sinc()
22865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     * r = extra space for implementing the ring buffer
22965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     *
23065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian     */
23165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2320d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian    mVolumeSIMD[0] = 0;
2330d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian    mVolumeSIMD[1] = 0;
2340d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian
235ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // Load the constants for coefficients
236ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    int ok = pthread_once(&once_control, init_routine);
237ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    if (ok != 0) {
238ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        ALOGE("%s pthread_once failed: %d", __func__, ok);
23976b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani    }
2407aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    mConstants = (quality == VERY_HIGH_QUALITY) ?
2417aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian            &veryHighQualityConstants : &highQualityConstants;
24265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
24365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
24476b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani
2457aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias AgopianAudioResamplerSinc::~AudioResamplerSinc() {
2467aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    free(mState);
24765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
24865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
24965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerSinc::init() {
2507aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    const Constants& c(*mConstants);
2517aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    const size_t numCoefs = 2 * c.halfNumCoefs;
25276b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani    const size_t stateSize = numCoefs * mChannelCount * 2;
2537aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    mState = (int16_t*)memalign(32, stateSize*sizeof(int16_t));
25476b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani    memset(mState, 0, sizeof(int16_t)*stateSize);
2557aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    mImpulse  = mState   + (c.halfNumCoefs-1)*mChannelCount;
25676b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani    mRingFull = mImpulse + (numCoefs+1)*mChannelCount;
25765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
25865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2595e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungvoid AudioResamplerSinc::setVolume(float left, float right) {
2600d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian    AudioResampler::setVolume(left, right);
2615e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    // convert to U4_28 (rounding down).
2625e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    // integer volume values are clamped to 0 to UNITY_GAIN.
2635e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    mVolumeSIMD[0] = u4_28_from_float(clampFloatVol(left));
2645e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung    mVolumeSIMD[1] = u4_28_from_float(clampFloatVol(right));
2650d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian}
2660d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian
2676b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
26865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            AudioBufferProvider* provider)
26965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
270ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // FIXME store current state (up or down sample) and only load the coefs when the state
271ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // changes. Or load two pointers one for up and one for down in the init function.
272ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // Not critical now since the read functions are fast, but would be important if read was slow.
27361ea117b03b53382b5ecbc33004c7d37ea70ea8bMathias Agopian    if (mConstants == &veryHighQualityConstants && readResampleCoefficients) {
2747aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian        mFirCoefs = readResampleCoefficients( mInSampleRate <= mSampleRate );
275ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    } else {
2762f5aa01e52b8869515373b5047f00272f245883eGlenn Kasten        mFirCoefs = (const int32_t *)
2772f5aa01e52b8869515373b5047f00272f245883eGlenn Kasten                ((mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown);
27876b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani    }
27965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
28065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // select the appropriate resampler
28165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    switch (mChannelCount) {
28265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    case 1:
2836b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung        return resample<1>(out, outFrameCount, provider);
28465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    case 2:
2856b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung        return resample<2>(out, outFrameCount, provider);
2866b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung    default:
2876b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung        LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount);
2886b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung        return 0;
28965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
29065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
29165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
29265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
29365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS>
2946b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount,
29565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AudioBufferProvider* provider)
29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
2977aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    const Constants& c(*mConstants);
2987aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    const size_t headOffset = c.halfNumCoefs*CHANNELS;
29965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int16_t* impulse = mImpulse;
30065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t vRL = mVolumeRL;
30165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t inputIndex = mInputIndex;
30265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t phaseFraction = mPhaseFraction;
30365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t phaseIncrement = mPhaseIncrement;
30465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t outputIndex = 0;
30565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t outputSampleCount = outFrameCount * 2;
30624781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung    size_t inFrameCount = getInFrameCountRequired(outFrameCount);
30765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
30865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    while (outputIndex < outputSampleCount) {
30965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // buffer is empty, fetch a new one
310d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten        while (mBuffer.frameCount == 0) {
311d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten            mBuffer.frameCount = inFrameCount;
312d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten            provider->getNextBuffer(&mBuffer);
313d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten            if (mBuffer.raw == NULL) {
31465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                goto resample_exit;
31565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            }
31665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits;
31765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            if (phaseIndex == 1) {
31865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                // read one frame
319d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten                read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
32065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            } else if (phaseIndex == 2) {
32165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                // read 2 frames
322d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten                read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
32365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                inputIndex++;
32465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                if (inputIndex >= mBuffer.frameCount) {
32565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                    inputIndex -= mBuffer.frameCount;
326d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten                    provider->releaseBuffer(&mBuffer);
32765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                } else {
328d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten                    read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex);
32965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                }
330e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten            }
33165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
3327aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian        int16_t const * const in = mBuffer.i16;
333d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten        const size_t frameCount = mBuffer.frameCount;
33465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
33565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // Always read-in the first samples from the input buffer
3367aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian        int16_t* head = impulse + headOffset;
337a798c97386a842d06d290797ba5dce95d031332aMathias Agopian        for (size_t i=0 ; i<CHANNELS ; i++) {
338a798c97386a842d06d290797ba5dce95d031332aMathias Agopian            head[i] = in[inputIndex*CHANNELS + i];
339a798c97386a842d06d290797ba5dce95d031332aMathias Agopian        }
34065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
34165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // handle boundary case
342a798c97386a842d06d290797ba5dce95d031332aMathias Agopian        while (CC_LIKELY(outputIndex < outputSampleCount)) {
3430d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian            filterCoefficient<CHANNELS>(&out[outputIndex], phaseFraction, impulse, vRL);
3440d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian            outputIndex += 2;
34565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
34665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            phaseFraction += phaseIncrement;
347a798c97386a842d06d290797ba5dce95d031332aMathias Agopian            const size_t phaseIndex = phaseFraction >> kNumPhaseBits;
348a798c97386a842d06d290797ba5dce95d031332aMathias Agopian            for (size_t i=0 ; i<phaseIndex ; i++) {
34965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                inputIndex++;
350a798c97386a842d06d290797ba5dce95d031332aMathias Agopian                if (inputIndex >= frameCount) {
351a798c97386a842d06d290797ba5dce95d031332aMathias Agopian                    goto done;  // need a new buffer
352a798c97386a842d06d290797ba5dce95d031332aMathias Agopian                }
35365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                read<CHANNELS>(impulse, phaseFraction, in, inputIndex);
35465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            }
35565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
356a798c97386a842d06d290797ba5dce95d031332aMathias Agopiandone:
35765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // if done with buffer, save samples
35865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        if (inputIndex >= frameCount) {
35965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            inputIndex -= frameCount;
360d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten            provider->releaseBuffer(&mBuffer);
36165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
36265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
36365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
36465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianresample_exit:
36565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mImpulse = impulse;
36665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mInputIndex = inputIndex;
36765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mPhaseFraction = phaseFraction;
3686b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung    return outputIndex / CHANNELS;
36965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
37065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
37165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS>
37265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/***
37365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* read()
37465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*
37565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* This function reads only one frame from input buffer and writes it in
37665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* state buffer
37765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*
37865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian**/
37965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerSinc::read(
38065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int16_t*& impulse, uint32_t& phaseFraction,
38154c3b66444ebfb9f2265ee70ac3b76ccefa0506aGlenn Kasten        const int16_t* in, size_t inputIndex)
38265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
38365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    impulse += CHANNELS;
38465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    phaseFraction -= 1LU<<kNumPhaseBits;
3857aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian
3867aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    const Constants& c(*mConstants);
387a798c97386a842d06d290797ba5dce95d031332aMathias Agopian    if (CC_UNLIKELY(impulse >= mRingFull)) {
3887aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian        const size_t stateSize = (c.halfNumCoefs*2)*CHANNELS;
38965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize);
39065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        impulse -= stateSize;
39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
3927aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian
3937aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    int16_t* head = impulse + c.halfNumCoefs*CHANNELS;
394a798c97386a842d06d290797ba5dce95d031332aMathias Agopian    for (size_t i=0 ; i<CHANNELS ; i++) {
395a798c97386a842d06d290797ba5dce95d031332aMathias Agopian        head[i] = in[inputIndex*CHANNELS + i];
396a798c97386a842d06d290797ba5dce95d031332aMathias Agopian    }
39765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
39865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
39965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS>
40012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yaovoid AudioResamplerSinc::filterCoefficient(int32_t* out, uint32_t phase,
40112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao         const int16_t *samples, uint32_t vRL)
40265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
4037492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian    // NOTE: be very careful when modifying the code here. register
4047492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian    // pressure is very high and a small change might cause the compiler
4057492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian    // to generate far less efficient code.
4067492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian    // Always sanity check the result with objdump or test-resample.
4077492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian
40865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // compute the index of the coefficient on the positive side and
40965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // negative side
4107aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    const Constants& c(*mConstants);
4117492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian    const int32_t ONE = c.cMask | c.pMask;
4127aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    uint32_t indexP = ( phase & c.cMask) >> c.cShift;
4137aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    uint32_t lerpP  = ( phase & c.pMask) >> c.pShift;
4147492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian    uint32_t indexN = ((ONE-phase) & c.cMask) >> c.cShift;
4157492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian    uint32_t lerpN  = ((ONE-phase) & c.pMask) >> c.pShift;
4167492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian
4177aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    const size_t offset = c.halfNumCoefs;
41846afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian    indexP *= offset;
41946afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian    indexN *= offset;
42046afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian
4217aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    int32_t const* coefsP = mFirCoefs + indexP;
4227aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian    int32_t const* coefsN = mFirCoefs + indexN;
42346afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian    int16_t const* sP = samples;
42446afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian    int16_t const* sN = samples + CHANNELS;
42565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
42646afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian    size_t count = offset;
427ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian
4284699a6a4c1fa62cd72dfda7b08573678eabbcfa3Glenn Kasten#if !USE_NEON
42912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    int32_t l = 0;
43012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    int32_t r = 0;
43112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    for (size_t i=0 ; i<count ; i++) {
43212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        interpolate<CHANNELS>(l, r, coefsP++, offset, lerpP, sP);
43312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sP -= CHANNELS;
43412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        interpolate<CHANNELS>(l, r, coefsN++, offset, lerpN, sN);
43512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sN += CHANNELS;
43612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    }
43712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    out[0] += 2 * mulRL(1, l, vRL);
43812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    out[1] += 2 * mulRL(0, r, vRL);
43912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#else
44012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    UNUSED(vRL);
44112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao    if (CHANNELS == 1) {
442ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian        int32_t const* coefsP1 = coefsP + offset;
443ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian        int32_t const* coefsN1 = coefsN + offset;
444ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian        sP -= CHANNELS*3;
44512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
44612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x4_t sum;
44712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x2_t lerpPN;
44812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vdup_n_s32(0);
44912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vld1_lane_s32((int32_t *)&lerpP, lerpPN, 0);
45012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vld1_lane_s32((int32_t *)&lerpN, lerpPN, 1);
45112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vshl_n_s32(lerpPN, 16);
45212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sum = vdupq_n_s32(0);
45312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
45412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int16x4_t sampleP, sampleN;
45512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x4_t samplePExt, sampleNExt;
45612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x4_t coefsPV0, coefsPV1, coefsNV0, coefsNV1;
45712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
45812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16);
45912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16);
46012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16);
46112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16);
46212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        for (; count > 0; count -= 4) {
46312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleP = vld1_s16(sP);
46412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleN = vld1_s16(sN);
46512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV0 = vld1q_s32(coefsP);
46612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV0 = vld1q_s32(coefsN);
46712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV1 = vld1q_s32(coefsP1);
46812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV1 = vld1q_s32(coefsN1);
46912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sP -= 4;
47012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sN += 4;
47112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsP += 4;
47212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsN += 4;
47312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsP1 += 4;
47412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsN1 += 4;
47512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
47612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleP = vrev64_s16(sampleP);
47712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
47812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            // interpolate (step1)
47912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV1 = vsubq_s32(coefsPV1, coefsPV0);
48012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV1 = vsubq_s32(coefsNV1, coefsNV0);
48112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            samplePExt = vshll_n_s16(sampleP, 15);
48212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            // interpolate (step2)
48312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV1 = vqrdmulhq_lane_s32(coefsPV1, lerpPN, 0);
48412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV1 = vqrdmulhq_lane_s32(coefsNV1, lerpPN, 1);
48512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleNExt = vshll_n_s16(sampleN, 15);
48612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            // interpolate (step3)
48712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV0 = vaddq_s32(coefsPV0, coefsPV1);
48812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV0 = vaddq_s32(coefsNV0, coefsNV1);
48912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
49012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            samplePExt = vqrdmulhq_s32(samplePExt, coefsPV0);
49112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleNExt = vqrdmulhq_s32(sampleNExt, coefsNV0);
49212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sum = vaddq_s32(sum, samplePExt);
49312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sum = vaddq_s32(sum, sampleNExt);
49412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        }
49512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x2_t volumesV, outV;
49612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        volumesV = vld1_s32(mVolumeSIMD);
49712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        outV = vld1_s32(out);
49812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
49912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        //add all 4 partial sums
50012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x2_t sumLow, sumHigh;
50112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow = vget_low_s32(sum);
50212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumHigh = vget_high_s32(sum);
50312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow = vpadd_s32(sumLow, sumHigh);
50412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow = vpadd_s32(sumLow, sumLow);
50512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
50612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow = vqrdmulh_s32(sumLow, volumesV);
50712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        outV = vadd_s32(outV, sumLow);
50812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        vst1_s32(out, outV);
509ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian    } else if (CHANNELS == 2) {
510ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian        int32_t const* coefsP1 = coefsP + offset;
511ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian        int32_t const* coefsN1 = coefsN + offset;
512ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian        sP -= CHANNELS*3;
51312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
51412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x4_t sum0, sum1;
51512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x2_t lerpPN;
51612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
51712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vdup_n_s32(0);
51812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vld1_lane_s32((int32_t *)&lerpP, lerpPN, 0);
51912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vld1_lane_s32((int32_t *)&lerpN, lerpPN, 1);
52012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        lerpPN = vshl_n_s32(lerpPN, 16);
52112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sum0 = vdupq_n_s32(0);
52212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sum1 = vdupq_n_s32(0);
52312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
52412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int16x4x2_t sampleP, sampleN;
52512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x4x2_t samplePExt, sampleNExt;
52612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x4_t coefsPV0, coefsPV1, coefsNV0, coefsNV1;
52712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
52812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16);
52912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16);
53012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16);
53112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16);
53212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        for (; count > 0; count -= 4) {
53312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleP = vld2_s16(sP);
53412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleN = vld2_s16(sN);
53512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV0 = vld1q_s32(coefsP);
53612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV0 = vld1q_s32(coefsN);
53712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV1 = vld1q_s32(coefsP1);
53812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV1 = vld1q_s32(coefsN1);
53912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sP -= 8;
54012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sN += 8;
54112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsP += 4;
54212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsN += 4;
54312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsP1 += 4;
54412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsN1 += 4;
54512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
54612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleP.val[0] = vrev64_s16(sampleP.val[0]);
54712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleP.val[1] = vrev64_s16(sampleP.val[1]);
54812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
54912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            // interpolate (step1)
55012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV1 = vsubq_s32(coefsPV1, coefsPV0);
55112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV1 = vsubq_s32(coefsNV1, coefsNV0);
55212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            samplePExt.val[0] = vshll_n_s16(sampleP.val[0], 15);
55312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            samplePExt.val[1] = vshll_n_s16(sampleP.val[1], 15);
55412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            // interpolate (step2)
55512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV1 = vqrdmulhq_lane_s32(coefsPV1, lerpPN, 0);
55612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV1 = vqrdmulhq_lane_s32(coefsNV1, lerpPN, 1);
55712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleNExt.val[0] = vshll_n_s16(sampleN.val[0], 15);
55812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleNExt.val[1] = vshll_n_s16(sampleN.val[1], 15);
55912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            // interpolate (step3)
56012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsPV0 = vaddq_s32(coefsPV0, coefsPV1);
56112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            coefsNV0 = vaddq_s32(coefsNV0, coefsNV1);
56212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
56312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            samplePExt.val[0] = vqrdmulhq_s32(samplePExt.val[0], coefsPV0);
56412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            samplePExt.val[1] = vqrdmulhq_s32(samplePExt.val[1], coefsPV0);
56512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleNExt.val[0] = vqrdmulhq_s32(sampleNExt.val[0], coefsNV0);
56612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sampleNExt.val[1] = vqrdmulhq_s32(sampleNExt.val[1], coefsNV0);
56712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sum0 = vaddq_s32(sum0, samplePExt.val[0]);
56812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sum1 = vaddq_s32(sum1, samplePExt.val[1]);
56912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sum0 = vaddq_s32(sum0, sampleNExt.val[0]);
57012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao            sum1 = vaddq_s32(sum1, sampleNExt.val[1]);
57112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        }
57212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x2_t volumesV, outV;
57312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        volumesV = vld1_s32(mVolumeSIMD);
57412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        outV = vld1_s32(out);
57512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
57612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        //add all 4 partial sums
57712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        int32x2_t sumLow0, sumHigh0, sumLow1, sumHigh1;
57812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow0 = vget_low_s32(sum0);
57912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumHigh0 = vget_high_s32(sum0);
58012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow1 = vget_low_s32(sum1);
58112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumHigh1 = vget_high_s32(sum1);
58212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow0 = vpadd_s32(sumLow0, sumHigh0);
58312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow0 = vpadd_s32(sumLow0, sumLow0);
58412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow1 = vpadd_s32(sumLow1, sumHigh1);
58512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow1 = vpadd_s32(sumLow1, sumLow1);
58612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao
58712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow0 = vtrn_s32(sumLow0, sumLow1).val[0];
58812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        sumLow0 = vqrdmulh_s32(sumLow0, volumesV);
58912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        outV = vadd_s32(outV, sumLow0);
59012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao        vst1_s32(out, outV);
59165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
59212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#endif
59365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
59465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
59565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS>
59665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerSinc::interpolate(
59765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int32_t& l, int32_t& r,
59846afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian        const int32_t* coefs, size_t offset,
59946afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian        int32_t lerp, const int16_t* samples)
60065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
60165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t c0 = coefs[0];
60246afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian    int32_t c1 = coefs[offset];
60365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0);
60465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    if (CHANNELS == 2) {
60554c3b66444ebfb9f2265ee70ac3b76ccefa0506aGlenn Kasten        uint32_t rl = *reinterpret_cast<const uint32_t*>(samples);
60665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        l = mulAddRL(1, rl, sinc, l);
60765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        r = mulAddRL(0, rl, sinc, r);
60865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    } else {
60965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        r = l = mulAdd(samples[0], sinc, l);
61065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
61165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
61265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
61363238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android
614