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