AudioResamplerSinc.cpp revision 6b3b7e304e0f8f167241b2c75f1eb04a9ef192ec
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__) 4612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#include <arm_neon.h> 4712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#define USE_NEON 48ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#else 4912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#undef USE_NEON 50ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#endif 51ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian 5212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#define UNUSED(x) ((void)(x)) 53ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian 5465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android { 5565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 5665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/* 5965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * These coeficients are computed with the "fir" utility found in 6065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * tools/resampler_tools 61d88a051aff15fdf5c57e1e5a4083bbd9635af3adMathias Agopian * cmd-line: fir -l 7 -s 48000 -c 20478 6265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian */ 63c4974312e5a1e2ab94eca56045f991baf1508d73Glenn Kastenconst uint32_t AudioResamplerSinc::mFirCoefsUp[] __attribute__ ((aligned (32))) = { 64675933be11f2c24f9f66011345377d2840938646Glenn Kasten#include "AudioResamplerSincUp.h" 6565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}; 6665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 6765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/* 68443e69625d598ea578e2c838960778ce498fd773Mathias Agopian * These coefficients are optimized for 48KHz -> 44.1KHz 694ed475d3ad4231370371e14a94779c5d300eb3c5Mathias Agopian * cmd-line: fir -l 7 -s 48000 -c 17189 7065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian */ 71c4974312e5a1e2ab94eca56045f991baf1508d73Glenn Kastenconst uint32_t AudioResamplerSinc::mFirCoefsDown[] __attribute__ ((aligned (32))) = { 72675933be11f2c24f9f66011345377d2840938646Glenn Kasten#include "AudioResamplerSincDown.h" 7365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}; 7465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 75ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten// we use 15 bits to interpolate between these samples 76ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten// this cannot change because the mul below rely on it. 77ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic const int pLerpBits = 15; 78ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 79ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 80ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic readCoefficientsFn readResampleCoefficients = NULL; 81ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 82ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::highQualityConstants; 83ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten/*static*/ AudioResamplerSinc::Constants AudioResamplerSinc::veryHighQualityConstants; 84ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 85ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenvoid AudioResamplerSinc::init_routine() 86ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 87ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // for high quality resampler, the parameters for coefficients are compile-time constants 88ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten Constants *c = &highQualityConstants; 89ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->coefsBits = RESAMPLE_FIR_LERP_INT_BITS; 90ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->cShift = kNumPhaseBits - c->coefsBits; 91ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->cMask = ((1<< c->coefsBits)-1) << c->cShift; 92ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits; 93ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->pMask = ((1<< pLerpBits)-1) << c->pShift; 94ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->halfNumCoefs = RESAMPLE_FIR_NUM_COEF; 95ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 96ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // for very high quality resampler, the parameters are load-time constants 97ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten veryHighQualityConstants = highQualityConstants; 98ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 99ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // Open the dll to get the coefficients for VERY_HIGH_QUALITY 100ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten void *resampleCoeffLib = dlopen("libaudio-resampler.so", RTLD_NOW); 101ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("Open libaudio-resampler library = %p", resampleCoeffLib); 102ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (resampleCoeffLib == NULL) { 103ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("Could not open audio-resampler library: %s", dlerror()); 104ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return; 105ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 106ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 1077aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian readResampleFirNumCoeffFn readResampleFirNumCoeff; 1087aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian readResampleFirLerpIntBitsFn readResampleFirLerpIntBits; 1097aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian 1107aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian readResampleCoefficients = (readCoefficientsFn) 1117aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian dlsym(resampleCoeffLib, "readResamplerCoefficients"); 1127aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian readResampleFirNumCoeff = (readResampleFirNumCoeffFn) 113ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten dlsym(resampleCoeffLib, "readResampleFirNumCoeff"); 1147aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian readResampleFirLerpIntBits = (readResampleFirLerpIntBitsFn) 115ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten dlsym(resampleCoeffLib, "readResampleFirLerpIntBits"); 1167aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian 117ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (!readResampleCoefficients || !readResampleFirNumCoeff || !readResampleFirLerpIntBits) { 118ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten readResampleCoefficients = NULL; 119ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten dlclose(resampleCoeffLib); 120ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten resampleCoeffLib = NULL; 121ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("Could not find symbol: %s", dlerror()); 122ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return; 123ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 124ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 125ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c = &veryHighQualityConstants; 126ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->coefsBits = readResampleFirLerpIntBits(); 127ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->cShift = kNumPhaseBits - c->coefsBits; 128ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->cMask = ((1<<c->coefsBits)-1) << c->cShift; 129ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->pShift = kNumPhaseBits - c->coefsBits - pLerpBits; 130ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->pMask = ((1<<pLerpBits)-1) << c->pShift; 131ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // number of zero-crossing on each side 132ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten c->halfNumCoefs = readResampleFirNumCoeff(); 1337aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian ALOGV("coefsBits = %d", c->coefsBits); 134ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("halfNumCoefs = %d", c->halfNumCoefs); 135ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // note that we "leak" resampleCoeffLib until the process exits 136ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 13776b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani 13865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 13965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 14065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianstatic inline 14165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianint32_t mulRL(int left, int32_t in, uint32_t vRL) 14265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 143ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#if USE_INLINE_ASSEMBLY 14465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t out; 14565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (left) { 14665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( "smultb %[out], %[in], %[vRL] \n" 14765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [out]"=r"(out) 14865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [in]"%r"(in), [vRL]"r"(vRL) 14965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : ); 15065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } else { 15165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( "smultt %[out], %[in], %[vRL] \n" 15265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [out]"=r"(out) 15365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [in]"%r"(in), [vRL]"r"(vRL) 15465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : ); 15565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 15665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return out; 15765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#else 1581f09b4ada212d259b531228db67ca160d280275cMathias Agopian int16_t v = left ? int16_t(vRL) : int16_t(vRL>>16); 1591f09b4ada212d259b531228db67ca160d280275cMathias Agopian return int32_t((int64_t(in) * v) >> 16); 16065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif 16165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 16265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 16365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianstatic inline 16465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianint32_t mulAdd(int16_t in, int32_t v, int32_t a) 16565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 166ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#if USE_INLINE_ASSEMBLY 16765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t out; 16865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( "smlawb %[out], %[v], %[in], %[a] \n" 16965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [out]"=r"(out) 17065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [in]"%r"(in), [v]"r"(v), [a]"r"(a) 17165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : ); 17265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return out; 17365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#else 1741f09b4ada212d259b531228db67ca160d280275cMathias Agopian return a + int32_t((int64_t(v) * in) >> 16); 17565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif 17665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 17765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 17865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianstatic inline 17965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianint32_t mulAddRL(int left, uint32_t inRL, int32_t v, int32_t a) 18065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 181ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian#if USE_INLINE_ASSEMBLY 18265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t out; 18365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (left) { 18465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( "smlawb %[out], %[v], %[inRL], %[a] \n" 18565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [out]"=r"(out) 18665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a) 18765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : ); 18865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } else { 18965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( "smlawt %[out], %[v], %[inRL], %[a] \n" 19065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [out]"=r"(out) 19165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : [inRL]"%r"(inRL), [v]"r"(v), [a]"r"(a) 19265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian : ); 19365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 19465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return out; 19565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#else 1961f09b4ada212d259b531228db67ca160d280275cMathias Agopian int16_t s = left ? int16_t(inRL) : int16_t(inRL>>16); 1971f09b4ada212d259b531228db67ca160d280275cMathias Agopian return a + int32_t((int64_t(v) * s) >> 16); 19865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif 19965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 20065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 20165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 20265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2033348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResamplerSinc::AudioResamplerSinc( 204ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int inChannelCount, int32_t sampleRate, src_quality quality) 2053348e36c51e91e78020bcc6578eda83d97c31becAndy Hung : AudioResampler(inChannelCount, sampleRate, quality), 2067aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian mState(0), mImpulse(0), mRingFull(0), mFirCoefs(0) 20765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 20865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian /* 20965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * Layout of the state buffer for 32 tap: 21065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * 21165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * "present" sample beginning of 2nd buffer 21265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * v v 21365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * 0 01 2 23 3 21465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * 0 F0 0 F0 F 21565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * [pppppppppppppppInnnnnnnnnnnnnnnnpppppppppppppppInnnnnnnnnnnnnnnn] 21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * ^ ^ head 21765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * 21865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * p = past samples, convoluted with the (p)ositive side of sinc() 21965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * n = future samples, convoluted with the (n)egative side of sinc() 22065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * r = extra space for implementing the ring buffer 22165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian * 22265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian */ 22365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2240d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian mVolumeSIMD[0] = 0; 2250d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian mVolumeSIMD[1] = 0; 2260d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian 227ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // Load the constants for coefficients 228ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int ok = pthread_once(&once_control, init_routine); 229ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (ok != 0) { 230ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("%s pthread_once failed: %d", __func__, ok); 23176b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani } 2327aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian mConstants = (quality == VERY_HIGH_QUALITY) ? 2337aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian &veryHighQualityConstants : &highQualityConstants; 23465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 23565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 23676b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani 2377aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias AgopianAudioResamplerSinc::~AudioResamplerSinc() { 2387aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian free(mState); 23965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 24065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 24165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerSinc::init() { 2427aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const Constants& c(*mConstants); 2437aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const size_t numCoefs = 2 * c.halfNumCoefs; 24476b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani const size_t stateSize = numCoefs * mChannelCount * 2; 2457aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian mState = (int16_t*)memalign(32, stateSize*sizeof(int16_t)); 24676b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani memset(mState, 0, sizeof(int16_t)*stateSize); 2477aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian mImpulse = mState + (c.halfNumCoefs-1)*mChannelCount; 24876b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani mRingFull = mImpulse + (numCoefs+1)*mChannelCount; 24965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 25065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2515e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungvoid AudioResamplerSinc::setVolume(float left, float right) { 2520d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian AudioResampler::setVolume(left, right); 2535e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // convert to U4_28 (rounding down). 2545e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // integer volume values are clamped to 0 to UNITY_GAIN. 2555e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolumeSIMD[0] = u4_28_from_float(clampFloatVol(left)); 2565e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolumeSIMD[1] = u4_28_from_float(clampFloatVol(right)); 2570d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian} 2580d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian 2596b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, 26065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) 26165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 262ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // FIXME store current state (up or down sample) and only load the coefs when the state 263ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // changes. Or load two pointers one for up and one for down in the init function. 264ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // Not critical now since the read functions are fast, but would be important if read was slow. 26561ea117b03b53382b5ecbc33004c7d37ea70ea8bMathias Agopian if (mConstants == &veryHighQualityConstants && readResampleCoefficients) { 2667aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian mFirCoefs = readResampleCoefficients( mInSampleRate <= mSampleRate ); 267ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } else { 2682f5aa01e52b8869515373b5047f00272f245883eGlenn Kasten mFirCoefs = (const int32_t *) 2692f5aa01e52b8869515373b5047f00272f245883eGlenn Kasten ((mInSampleRate <= mSampleRate) ? mFirCoefsUp : mFirCoefsDown); 27076b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani } 27165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 27265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // select the appropriate resampler 27365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (mChannelCount) { 27465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 1: 2756b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return resample<1>(out, outFrameCount, provider); 27665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 2: 2776b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return resample<2>(out, outFrameCount, provider); 2786b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung default: 2796b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); 2806b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return 0; 28165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 28265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 28365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS> 2866b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerSinc::resample(int32_t* out, size_t outFrameCount, 28765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) 28865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 2897aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const Constants& c(*mConstants); 2907aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const size_t headOffset = c.halfNumCoefs*CHANNELS; 29165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t* impulse = mImpulse; 29265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t vRL = mVolumeRL; 29365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 29465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 29565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 29765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 29824781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung size_t inFrameCount = getInFrameCountRequired(outFrameCount); 29965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 30065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 30165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 302d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten while (mBuffer.frameCount == 0) { 303d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten mBuffer.frameCount = inFrameCount; 3044ff14bae91075eb274eb1c2975982358946e7e63John Grossman provider->getNextBuffer(&mBuffer, 3054ff14bae91075eb274eb1c2975982358946e7e63John Grossman calculateOutputPTS(outputIndex / 2)); 306d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten if (mBuffer.raw == NULL) { 30765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resample_exit; 30865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 30965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian const uint32_t phaseIndex = phaseFraction >> kNumPhaseBits; 31065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (phaseIndex == 1) { 31165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // read one frame 312d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex); 31365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } else if (phaseIndex == 2) { 31465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // read 2 frames 315d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex); 31665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex++; 31765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 31865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 319d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten provider->releaseBuffer(&mBuffer); 32065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } else { 321d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten read<CHANNELS>(impulse, phaseFraction, mBuffer.i16, inputIndex); 32265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 323e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten } 32465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 3257aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian int16_t const * const in = mBuffer.i16; 326d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten const size_t frameCount = mBuffer.frameCount; 32765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 32865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // Always read-in the first samples from the input buffer 3297aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian int16_t* head = impulse + headOffset; 330a798c97386a842d06d290797ba5dce95d031332aMathias Agopian for (size_t i=0 ; i<CHANNELS ; i++) { 331a798c97386a842d06d290797ba5dce95d031332aMathias Agopian head[i] = in[inputIndex*CHANNELS + i]; 332a798c97386a842d06d290797ba5dce95d031332aMathias Agopian } 33365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 33465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 335a798c97386a842d06d290797ba5dce95d031332aMathias Agopian while (CC_LIKELY(outputIndex < outputSampleCount)) { 3360d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian filterCoefficient<CHANNELS>(&out[outputIndex], phaseFraction, impulse, vRL); 3370d585c85524eb5d398fadff5ca8dd43939ed9cb4Mathias Agopian outputIndex += 2; 33865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 33965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction += phaseIncrement; 340a798c97386a842d06d290797ba5dce95d031332aMathias Agopian const size_t phaseIndex = phaseFraction >> kNumPhaseBits; 341a798c97386a842d06d290797ba5dce95d031332aMathias Agopian for (size_t i=0 ; i<phaseIndex ; i++) { 34265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex++; 343a798c97386a842d06d290797ba5dce95d031332aMathias Agopian if (inputIndex >= frameCount) { 344a798c97386a842d06d290797ba5dce95d031332aMathias Agopian goto done; // need a new buffer 345a798c97386a842d06d290797ba5dce95d031332aMathias Agopian } 34665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian read<CHANNELS>(impulse, phaseFraction, in, inputIndex); 34765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 34865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 349a798c97386a842d06d290797ba5dce95d031332aMathias Agopiandone: 35065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 35165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= frameCount) { 35265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= frameCount; 353d198b61603d5fa9298edea4ddb5852ea45159906Glenn Kasten provider->releaseBuffer(&mBuffer); 35465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 35565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 35665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianresample_exit: 35865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mImpulse = impulse; 35965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 36065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 3616b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return outputIndex / CHANNELS; 36265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 36365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS> 36565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/*** 36665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* read() 36765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 36865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* This function reads only one frame from input buffer and writes it in 36965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* state buffer 37065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 37165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian**/ 37265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerSinc::read( 37365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t*& impulse, uint32_t& phaseFraction, 37454c3b66444ebfb9f2265ee70ac3b76ccefa0506aGlenn Kasten const int16_t* in, size_t inputIndex) 37565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 37665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian impulse += CHANNELS; 37765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction -= 1LU<<kNumPhaseBits; 3787aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian 3797aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const Constants& c(*mConstants); 380a798c97386a842d06d290797ba5dce95d031332aMathias Agopian if (CC_UNLIKELY(impulse >= mRingFull)) { 3817aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const size_t stateSize = (c.halfNumCoefs*2)*CHANNELS; 38265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian memcpy(mState, mState+stateSize, sizeof(int16_t)*stateSize); 38365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian impulse -= stateSize; 38465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 3857aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian 3867aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian int16_t* head = impulse + c.halfNumCoefs*CHANNELS; 387a798c97386a842d06d290797ba5dce95d031332aMathias Agopian for (size_t i=0 ; i<CHANNELS ; i++) { 388a798c97386a842d06d290797ba5dce95d031332aMathias Agopian head[i] = in[inputIndex*CHANNELS + i]; 389a798c97386a842d06d290797ba5dce95d031332aMathias Agopian } 39065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS> 39312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yaovoid AudioResamplerSinc::filterCoefficient(int32_t* out, uint32_t phase, 39412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao const int16_t *samples, uint32_t vRL) 39565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 3967492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian // NOTE: be very careful when modifying the code here. register 3977492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian // pressure is very high and a small change might cause the compiler 3987492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian // to generate far less efficient code. 3997492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian // Always sanity check the result with objdump or test-resample. 4007492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian 40165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // compute the index of the coefficient on the positive side and 40265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // negative side 4037aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const Constants& c(*mConstants); 4047492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian const int32_t ONE = c.cMask | c.pMask; 4057aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian uint32_t indexP = ( phase & c.cMask) >> c.cShift; 4067aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian uint32_t lerpP = ( phase & c.pMask) >> c.pShift; 4077492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian uint32_t indexN = ((ONE-phase) & c.cMask) >> c.cShift; 4087492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian uint32_t lerpN = ((ONE-phase) & c.pMask) >> c.pShift; 4097492a7ff46a75b5d8e10ae11d4ad50429cf945ceMathias Agopian 4107aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian const size_t offset = c.halfNumCoefs; 41146afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian indexP *= offset; 41246afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian indexN *= offset; 41346afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian 4147aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian int32_t const* coefsP = mFirCoefs + indexP; 4157aa7ed773040ea60bbe0a2a6ea949d62802304a4Mathias Agopian int32_t const* coefsN = mFirCoefs + indexN; 41646afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian int16_t const* sP = samples; 41746afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian int16_t const* sN = samples + CHANNELS; 41865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41946afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian size_t count = offset; 420ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian 42112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#ifndef USE_NEON 42212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32_t l = 0; 42312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32_t r = 0; 42412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao for (size_t i=0 ; i<count ; i++) { 42512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao interpolate<CHANNELS>(l, r, coefsP++, offset, lerpP, sP); 42612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sP -= CHANNELS; 42712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao interpolate<CHANNELS>(l, r, coefsN++, offset, lerpN, sN); 42812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sN += CHANNELS; 42912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao } 43012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao out[0] += 2 * mulRL(1, l, vRL); 43112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao out[1] += 2 * mulRL(0, r, vRL); 43212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#else 43312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao UNUSED(vRL); 43412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao if (CHANNELS == 1) { 435ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian int32_t const* coefsP1 = coefsP + offset; 436ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian int32_t const* coefsN1 = coefsN + offset; 437ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian sP -= CHANNELS*3; 43812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 43912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x4_t sum; 44012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x2_t lerpPN; 44112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vdup_n_s32(0); 44212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vld1_lane_s32((int32_t *)&lerpP, lerpPN, 0); 44312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vld1_lane_s32((int32_t *)&lerpN, lerpPN, 1); 44412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vshl_n_s32(lerpPN, 16); 44512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum = vdupq_n_s32(0); 44612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 44712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int16x4_t sampleP, sampleN; 44812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x4_t samplePExt, sampleNExt; 44912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x4_t coefsPV0, coefsPV1, coefsNV0, coefsNV1; 45012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 45112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16); 45212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16); 45312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16); 45412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16); 45512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao for (; count > 0; count -= 4) { 45612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleP = vld1_s16(sP); 45712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleN = vld1_s16(sN); 45812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV0 = vld1q_s32(coefsP); 45912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV0 = vld1q_s32(coefsN); 46012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV1 = vld1q_s32(coefsP1); 46112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV1 = vld1q_s32(coefsN1); 46212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sP -= 4; 46312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sN += 4; 46412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP += 4; 46512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN += 4; 46612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP1 += 4; 46712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN1 += 4; 46812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 46912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleP = vrev64_s16(sampleP); 47012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 47112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao // interpolate (step1) 47212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV1 = vsubq_s32(coefsPV1, coefsPV0); 47312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV1 = vsubq_s32(coefsNV1, coefsNV0); 47412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao samplePExt = vshll_n_s16(sampleP, 15); 47512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao // interpolate (step2) 47612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV1 = vqrdmulhq_lane_s32(coefsPV1, lerpPN, 0); 47712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV1 = vqrdmulhq_lane_s32(coefsNV1, lerpPN, 1); 47812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleNExt = vshll_n_s16(sampleN, 15); 47912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao // interpolate (step3) 48012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV0 = vaddq_s32(coefsPV0, coefsPV1); 48112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV0 = vaddq_s32(coefsNV0, coefsNV1); 48212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 48312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao samplePExt = vqrdmulhq_s32(samplePExt, coefsPV0); 48412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleNExt = vqrdmulhq_s32(sampleNExt, coefsNV0); 48512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum = vaddq_s32(sum, samplePExt); 48612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum = vaddq_s32(sum, sampleNExt); 48712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao } 48812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x2_t volumesV, outV; 48912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao volumesV = vld1_s32(mVolumeSIMD); 49012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao outV = vld1_s32(out); 49112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 49212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao //add all 4 partial sums 49312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x2_t sumLow, sumHigh; 49412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow = vget_low_s32(sum); 49512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumHigh = vget_high_s32(sum); 49612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow = vpadd_s32(sumLow, sumHigh); 49712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow = vpadd_s32(sumLow, sumLow); 49812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 49912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow = vqrdmulh_s32(sumLow, volumesV); 50012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao outV = vadd_s32(outV, sumLow); 50112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao vst1_s32(out, outV); 502ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian } else if (CHANNELS == 2) { 503ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian int32_t const* coefsP1 = coefsP + offset; 504ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian int32_t const* coefsN1 = coefsN + offset; 505ad9af03c4b491912239fc8c97a3ad0d342a33303Mathias Agopian sP -= CHANNELS*3; 50612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 50712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x4_t sum0, sum1; 50812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x2_t lerpPN; 50912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 51012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vdup_n_s32(0); 51112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vld1_lane_s32((int32_t *)&lerpP, lerpPN, 0); 51212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vld1_lane_s32((int32_t *)&lerpN, lerpPN, 1); 51312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao lerpPN = vshl_n_s32(lerpPN, 16); 51412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum0 = vdupq_n_s32(0); 51512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum1 = vdupq_n_s32(0); 51612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 51712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int16x4x2_t sampleP, sampleN; 51812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x4x2_t samplePExt, sampleNExt; 51912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x4_t coefsPV0, coefsPV1, coefsNV0, coefsNV1; 52012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 52112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP = (const int32_t*)__builtin_assume_aligned(coefsP, 16); 52212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN = (const int32_t*)__builtin_assume_aligned(coefsN, 16); 52312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP1 = (const int32_t*)__builtin_assume_aligned(coefsP1, 16); 52412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN1 = (const int32_t*)__builtin_assume_aligned(coefsN1, 16); 52512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao for (; count > 0; count -= 4) { 52612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleP = vld2_s16(sP); 52712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleN = vld2_s16(sN); 52812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV0 = vld1q_s32(coefsP); 52912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV0 = vld1q_s32(coefsN); 53012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV1 = vld1q_s32(coefsP1); 53112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV1 = vld1q_s32(coefsN1); 53212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sP -= 8; 53312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sN += 8; 53412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP += 4; 53512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN += 4; 53612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsP1 += 4; 53712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsN1 += 4; 53812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 53912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleP.val[0] = vrev64_s16(sampleP.val[0]); 54012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleP.val[1] = vrev64_s16(sampleP.val[1]); 54112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 54212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao // interpolate (step1) 54312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV1 = vsubq_s32(coefsPV1, coefsPV0); 54412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV1 = vsubq_s32(coefsNV1, coefsNV0); 54512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao samplePExt.val[0] = vshll_n_s16(sampleP.val[0], 15); 54612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao samplePExt.val[1] = vshll_n_s16(sampleP.val[1], 15); 54712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao // interpolate (step2) 54812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV1 = vqrdmulhq_lane_s32(coefsPV1, lerpPN, 0); 54912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV1 = vqrdmulhq_lane_s32(coefsNV1, lerpPN, 1); 55012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleNExt.val[0] = vshll_n_s16(sampleN.val[0], 15); 55112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleNExt.val[1] = vshll_n_s16(sampleN.val[1], 15); 55212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao // interpolate (step3) 55312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsPV0 = vaddq_s32(coefsPV0, coefsPV1); 55412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao coefsNV0 = vaddq_s32(coefsNV0, coefsNV1); 55512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 55612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao samplePExt.val[0] = vqrdmulhq_s32(samplePExt.val[0], coefsPV0); 55712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao samplePExt.val[1] = vqrdmulhq_s32(samplePExt.val[1], coefsPV0); 55812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleNExt.val[0] = vqrdmulhq_s32(sampleNExt.val[0], coefsNV0); 55912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sampleNExt.val[1] = vqrdmulhq_s32(sampleNExt.val[1], coefsNV0); 56012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum0 = vaddq_s32(sum0, samplePExt.val[0]); 56112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum1 = vaddq_s32(sum1, samplePExt.val[1]); 56212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum0 = vaddq_s32(sum0, sampleNExt.val[0]); 56312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sum1 = vaddq_s32(sum1, sampleNExt.val[1]); 56412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao } 56512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x2_t volumesV, outV; 56612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao volumesV = vld1_s32(mVolumeSIMD); 56712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao outV = vld1_s32(out); 56812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 56912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao //add all 4 partial sums 57012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao int32x2_t sumLow0, sumHigh0, sumLow1, sumHigh1; 57112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow0 = vget_low_s32(sum0); 57212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumHigh0 = vget_high_s32(sum0); 57312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow1 = vget_low_s32(sum1); 57412b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumHigh1 = vget_high_s32(sum1); 57512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow0 = vpadd_s32(sumLow0, sumHigh0); 57612b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow0 = vpadd_s32(sumLow0, sumLow0); 57712b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow1 = vpadd_s32(sumLow1, sumHigh1); 57812b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow1 = vpadd_s32(sumLow1, sumLow1); 57912b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao 58012b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow0 = vtrn_s32(sumLow0, sumLow1).val[0]; 58112b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao sumLow0 = vqrdmulh_s32(sumLow0, volumesV); 58212b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao outV = vadd_s32(outV, sumLow0); 58312b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao vst1_s32(out, outV); 58465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 58512b44bd5fe3069cd3450d05b6c446b600e0553d3Zhongwei Yao#endif 58665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 58765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiantemplate<int CHANNELS> 58965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerSinc::interpolate( 59065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t& l, int32_t& r, 59146afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian const int32_t* coefs, size_t offset, 59246afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian int32_t lerp, const int16_t* samples) 59365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 59465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t c0 = coefs[0]; 59546afbec3743f1d799f185273ff897d1f8e0175ddMathias Agopian int32_t c1 = coefs[offset]; 59665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sinc = mulAdd(lerp, (c1-c0)<<1, c0); 59765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (CHANNELS == 2) { 59854c3b66444ebfb9f2265ee70ac3b76ccefa0506aGlenn Kasten uint32_t rl = *reinterpret_cast<const uint32_t*>(samples); 59965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian l = mulAddRL(1, rl, sinc, l); 60065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian r = mulAddRL(0, rl, sinc, r); 60165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } else { 60265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian r = l = mulAdd(samples[0], sinc, l); 60365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 60465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 60565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 60663238efb0d674758902918e3cdaac322126484b7Glenn Kasten} // namespace android 607