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 1765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define LOG_TAG "AudioResampler" 1865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian//#define LOG_NDEBUG 0 1965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <stdint.h> 2165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <stdlib.h> 2265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <sys/types.h> 2365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <cutils/log.h> 2465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <cutils/properties.h> 2565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResampler.h" 2665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerSinc.h" 2765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerCubic.h" 2865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 290c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#ifdef __arm__ 300c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#include <machine/cpu-features.h> 310c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif 320c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang 3365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android { 3465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 350c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option 36c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 370c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif // __ARM_HAVE_HALFWORD_MULTIPLY 3865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 3965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 4065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianclass AudioResamplerOrder1 : public AudioResampler { 4165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianpublic: 4265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) : 43ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten AudioResampler(bitDepth, inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { 4465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 4565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian virtual void resample(int32_t* out, size_t outFrameCount, 4665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 4765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianprivate: 4865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // number of bits used in interpolation multiply - 15 bits avoids overflow 4965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static const int kNumInterpBits = 15; 5065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // bits to shift the phase fraction down to avoid overflow 5265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; 5365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void init() {} 5565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void resampleMono16(int32_t* out, size_t outFrameCount, 5665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 5765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void resampleStereo16(int32_t* out, size_t outFrameCount, 5865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 5965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 6065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 6165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 6265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement); 6365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 6465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 6565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement); 6665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 6765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 6865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) { 6965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits); 7065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 7165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) { 7265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *frac += inc; 7365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *index += (size_t)(*frac >> kNumPhaseBits); 7465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *frac &= kPhaseMask; 7565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 7665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int mX0L; 7765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int mX0R; 7865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}; 7965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 80ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenbool AudioResampler::qualityIsSupported(src_quality quality) 81ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 82ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 83ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 84ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 85ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten#if 0 // these have not been qualified recently so are not supported unless explicitly requested 86ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 87ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 88ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten#endif 89ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 90ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return true; 91ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 92ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return false; 93ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 94ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 95ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 9665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 9765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 98ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 99ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY; 10065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 101ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenvoid AudioResampler::init_routine() 102ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 10365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian char value[PROPERTY_VALUE_MAX]; 104ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (property_get("af.resampler.quality", value, NULL) > 0) { 105ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten char *endptr; 106ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten unsigned long l = strtoul(value, &endptr, 0); 107ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (*endptr == '\0') { 108ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = (src_quality) l; 109ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGD("forcing AudioResampler quality to %d", defaultQuality); 110ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) { 111ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = DEFAULT_QUALITY; 112ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 113ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 114ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 115ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 116ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 117ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenuint32_t AudioResampler::qualityMHz(src_quality quality) 118ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 119ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 120ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 121ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 122ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 123ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 3; 124ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 125ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 6; 126ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 127ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 20; 128ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 129ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 34; 13065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 131ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 132ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 133c4640c9eef850bb1c754bd6b477f1cc8350c6081Glenn Kastenstatic const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable 134ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 135ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic uint32_t currentMHz = 0; 13665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 137ac6020508acedd316391dee42329040bf45f8d90Glenn KastenAudioResampler* AudioResampler::create(int bitDepth, int inChannelCount, 138ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) { 139ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 140ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten bool atFinalQuality; 141ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (quality == DEFAULT_QUALITY) { 142ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // read the resampler default quality property the first time it is needed 143ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int ok = pthread_once(&once_control, init_routine); 144ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (ok != 0) { 145ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("%s pthread_once failed: %d", __func__, ok); 146ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 147ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = defaultQuality; 148ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = false; 149ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } else { 150ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 151ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 152ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 153ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // naive implementation of CPU load throttling doesn't account for whether resampler is active 154ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 155ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten for (;;) { 156ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 157ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t newMHz = currentMHz + deltaMHz; 158ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { 159ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", 160ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 161ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 162ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 163ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 164ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // not enough CPU available for proposed quality level, so try next lowest level 165ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 166ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 167ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 168ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 169ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 170ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 171ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 172ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = LOW_QUALITY; 173ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 174ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 175ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = MED_QUALITY; 176ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 177ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 178ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = HIGH_QUALITY; 179ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 180ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 181ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 182ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 183ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 184ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten AudioResampler* resampler; 18565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 18665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (quality) { 18765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian default: 188ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 18965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case LOW_QUALITY: 1903856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create linear Resampler"); 19165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate); 19265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 193ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten#if 0 // disabled because it has not been qualified recently, if requested will use default: 19465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case MED_QUALITY: 1953856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create cubic Resampler"); 19665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate); 19765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 19876b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani#endif 19965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case HIGH_QUALITY: 20076b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani ALOGV("Create HIGH_QUALITY sinc Resampler"); 20165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate); 202ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 20376b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani case VERY_HIGH_QUALITY: 204ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); 20576b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality); 20665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 20765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 20865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 20965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize resampler 21065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampler->init(); 21165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return resampler; 21265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 21365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 21465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianAudioResampler::AudioResampler(int bitDepth, int inChannelCount, 215ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) : 21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBitDepth(bitDepth), mChannelCount(inChannelCount), 21765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), 2184ff14bae91075eb274eb1c2975982358946e7e63John Grossman mPhaseFraction(0), mLocalTimeFreq(0), 219ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) { 22065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // sanity check on format 22165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) { 22229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth, 22365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inChannelCount); 224c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(0); 22565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 226ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (sampleRate <= 0) { 227ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("Unsupported sample rate %d Hz", sampleRate); 228ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 22965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 23065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize common members 23165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mVolume[0] = mVolume[1] = 0; 23265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = 0; 23365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 23465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 23565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 23665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianAudioResampler::~AudioResampler() { 237ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 238ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten src_quality quality = getQuality(); 239ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 240ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t newMHz = currentMHz - deltaMHz; 241ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", 242ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 243ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); 244ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 245ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 24665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 24765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 24865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResampler::setSampleRate(int32_t inSampleRate) { 24965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInSampleRate = inSampleRate; 25065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); 25165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 25265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 25365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResampler::setVolume(int16_t left, int16_t right) { 25465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // TODO: Implement anti-zipper filter 25565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mVolume[0] = left; 25665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mVolume[1] = right; 25765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 25865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2594ff14bae91075eb274eb1c2975982358946e7e63John Grossmanvoid AudioResampler::setLocalTimeFreq(uint64_t freq) { 2604ff14bae91075eb274eb1c2975982358946e7e63John Grossman mLocalTimeFreq = freq; 2614ff14bae91075eb274eb1c2975982358946e7e63John Grossman} 2624ff14bae91075eb274eb1c2975982358946e7e63John Grossman 2634ff14bae91075eb274eb1c2975982358946e7e63John Grossmanvoid AudioResampler::setPTS(int64_t pts) { 2644ff14bae91075eb274eb1c2975982358946e7e63John Grossman mPTS = pts; 2654ff14bae91075eb274eb1c2975982358946e7e63John Grossman} 2664ff14bae91075eb274eb1c2975982358946e7e63John Grossman 2674ff14bae91075eb274eb1c2975982358946e7e63John Grossmanint64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) { 2684ff14bae91075eb274eb1c2975982358946e7e63John Grossman 2694ff14bae91075eb274eb1c2975982358946e7e63John Grossman if (mPTS == AudioBufferProvider::kInvalidPTS) { 2704ff14bae91075eb274eb1c2975982358946e7e63John Grossman return AudioBufferProvider::kInvalidPTS; 2714ff14bae91075eb274eb1c2975982358946e7e63John Grossman } else { 2724ff14bae91075eb274eb1c2975982358946e7e63John Grossman return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate); 2734ff14bae91075eb274eb1c2975982358946e7e63John Grossman } 2744ff14bae91075eb274eb1c2975982358946e7e63John Grossman} 2754ff14bae91075eb274eb1c2975982358946e7e63John Grossman 276243f5f91755c01614a8cafe90b0806396e22d553Eric Laurentvoid AudioResampler::reset() { 277243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mInputIndex = 0; 278243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mPhaseFraction = 0; 279243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mBuffer.frameCount = 0; 280243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent} 281243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent 28265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 28365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, 28565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 28665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // should never happen, but we overflow if it does 288c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(outFrameCount < 32767); 28965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 29065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // select the appropriate resampler 29165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (mChannelCount) { 29265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 1: 29365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampleMono16(out, outFrameCount, provider); 29465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 29565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 2: 29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampleStereo16(out, outFrameCount, provider); 29765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 29865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 29965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 30065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 30165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, 30265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 30365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 30465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 30565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 30665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 30765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 30865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 30965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 31065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 31165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 31265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; 31365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 31490bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 31565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 31665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 31765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 31865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 31965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 32065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 32165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 3224ff14bae91075eb274eb1c2975982358946e7e63John Grossman provider->getNextBuffer(&mBuffer, 3234ff14bae91075eb274eb1c2975982358946e7e63John Grossman calculateOutputPTS(outputIndex / 2)); 32465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 32565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleStereo16_exit; 32665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 32765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 32890bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 32965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 33065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 33165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 33265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 33365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 33465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 335e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten // mBuffer.frameCount == 0 now so we reload a new buffer 33665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 33765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 33865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 33965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 34065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 34165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 34290bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 34365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction); 34465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction); 34565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 34665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (outputIndex == outputSampleCount) 34765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 34865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 34965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 35190bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 35265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 35465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 35565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 35665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 35765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop 35965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = mBuffer.frameCount - 2; 36065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 36165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 36265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 36365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 36465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 36665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(in[inputIndex*2-2], 36765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2], phaseFraction); 36865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(in[inputIndex*2-1], 36965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2+1], phaseFraction); 37065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 37165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 37265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 37465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 37665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 37765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 37865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 38065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 38265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 38365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 38465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 386c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 38765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 38865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 38965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39090bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleStereo16_exit: 39365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 39465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 39565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 39665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 39765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, 39965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 40065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 40265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 40365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 40565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 40665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 40765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 40865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 40965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate; 41065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41190bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 41265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 41365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 41465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 41565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 41665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 4174ff14bae91075eb274eb1c2975982358946e7e63John Grossman provider->getNextBuffer(&mBuffer, 4184ff14bae91075eb274eb1c2975982358946e7e63John Grossman calculateOutputPTS(outputIndex / 2)); 41965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 42065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 42165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 42265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleMono16_exit; 42365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 42490bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 42565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 42665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 42865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 42965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 43065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // mBuffer.frameCount == 0 now so we reload a new buffer 43165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 43265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 43365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 43465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 43565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 43690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 43765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(mX0L, in[0], phaseFraction); 43865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 43965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 44065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 44165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (outputIndex == outputSampleCount) 44265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 44365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 44465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 44565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 44690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 44765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 44865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 44965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 45065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 45165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 45265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 45365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); 45465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = (int32_t)mBuffer.frameCount - 2; 45565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 45665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 45765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 45865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 45965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 46065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 46165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(in[inputIndex-1], in[inputIndex], 46265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction); 46365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 46465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 46565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 46665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 46765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 46865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 46990bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 47065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 47165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 47265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 47365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 47465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 47529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 47665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 47765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 47865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 47965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 481c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 48265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 48365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 48465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48590bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 48665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleMono16_exit: 48865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 48965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 49065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 49165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 49265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 49365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 49465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 49565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 49665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 49765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmMono16Loop 49865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized monotonic loop version; one loop is 2 frames 49965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 50065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 50165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 50265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 50365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 50465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 50565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 50665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 50765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 50865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 50965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 51065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 51165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 51265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 51365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 51465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 51565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 516c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 51765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 51865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 51965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 52065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 52165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) 52265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 52465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" 52565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 52665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 52765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 52865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 52965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 53065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out 53165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 53265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 53365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r8, r0, asl #2\n" // curOut 53465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement 53565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl 53665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr 53765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 53865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 53965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 54065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 54165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 54265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 54365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 54465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, Out1 54565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 54665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 54765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 54865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 54965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 55065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 55165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 55265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 55365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 55465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 55565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 55665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 55765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 55865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 55965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // the following loop works on 2 frames 56065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 561eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "1:\n" 56265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 563eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 2f\n" 56465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 56565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_ONE_FRAME \ 56665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ 56765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[inputIndex] */\ 56865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 56965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ 57065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 57165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ 57265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 57365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 57465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 57565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r0, r4\n" /* x0 - (..) */\ 57665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ 57765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 57865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 57965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ 58065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ 58165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ 58265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 1 58465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 2 58565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 587eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 1b\n" 588eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "2:\n" 58965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 59065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 59165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 59265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 59365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 59465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 59565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 59665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out 59765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 59865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 59965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 60065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 60165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" 60365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 60465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 60565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 60765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 60865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmStereo16Loop 60965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized stereo loop version; one loop is 2 frames 61065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 61165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 61265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 61365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 61465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 61565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 61665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 61765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 61865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 61965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 62065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 62165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 62265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 62365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 62465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 62565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 62665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 627c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 62865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 62965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 63065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 63165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 63265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) 63365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 63465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" 63565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 63665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 63765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 63865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 63965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 64065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out 64165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 64265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 64365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r8, r0, asl #2\n" // curOut 64465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement 64565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl 64665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr 64765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 64865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 64965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 65065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 65165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 65265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 65365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 65465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, out1 65565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 65665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 65765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 65865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 65965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 66065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 66165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 66265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 66365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 66465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 66565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 temporary 66665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 66765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 66865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 669eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "3:\n" 67065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 671eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 4f\n" 67265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 67365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_ONE_FRAME \ 67465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 67565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 67665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ 67765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 67865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ 67965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 68065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ 68165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 68265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 68365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 68465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r12, r4\n" /* x0 - (..) */\ 68565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ 68665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 68765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 68865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 68965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ 69065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ 69165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 69265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r12, r12, lsl #2\n" /* <<2 */\ 69365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ 69465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r0, r12\n" /* x0 - (..) */\ 69565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ 69665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ 69765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 69865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 69965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ 70065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 70265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 70365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 705eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 3b\n" 706eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "4:\n" 70765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 70965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 71065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 71165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 71265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 71365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 71465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out 71565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 71665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 71765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 71865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 71965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" 72165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 72265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 72365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 72565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 72865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 729c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten} // namespace android 730