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 2060d02077d86d2d1092443519290101f503aa6f7aMark Salyzyn#include <pthread.h> 2165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <stdint.h> 2265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <stdlib.h> 2365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <sys/types.h> 2460d02077d86d2d1092443519290101f503aa6f7aMark Salyzyn 2565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include <cutils/properties.h> 26eb16561336e6445f7edae047998f2459e046cdfeMark Salyzyn#include <log/log.h> 2760d02077d86d2d1092443519290101f503aa6f7aMark Salyzyn 285e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung#include <audio_utils/primitives.h> 29068561c8e84569d51df2adbbb53b56fdfd09c06bAndy Hung#include <media/AudioResampler.h> 3065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerSinc.h" 3165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerCubic.h" 3286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerDyn.h" 3365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 340c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#ifdef __arm__ 35505fd3025855f424353ae084495e1855522cf65bGlenn Kasten // bug 13102576 36505fd3025855f424353ae084495e1855522cf65bGlenn Kasten //#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 370c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif 380c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang 3965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android { 4065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 4165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 4265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 4365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianclass AudioResamplerOrder1 : public AudioResampler { 4465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianpublic: 453348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResamplerOrder1(int inChannelCount, int32_t sampleRate) : 463348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResampler(inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { 4765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 486b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung virtual size_t resample(int32_t* out, size_t outFrameCount, 4965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 5065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianprivate: 5165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // number of bits used in interpolation multiply - 15 bits avoids overflow 5265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static const int kNumInterpBits = 15; 5365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // bits to shift the phase fraction down to avoid overflow 5565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; 5665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void init() {} 586b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung size_t resampleMono16(int32_t* out, size_t outFrameCount, 5965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 606b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung size_t resampleStereo16(int32_t* out, size_t outFrameCount, 6165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 6265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 6365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void AsmMono16Loop(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 void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 6765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 6865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement); 6965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 7065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 7165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) { 7265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits); 7365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 7465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) { 7565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *frac += inc; 7665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *index += (size_t)(*frac >> kNumPhaseBits); 7765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *frac &= kPhaseMask; 7865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 7965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int mX0L; 8065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int mX0R; 8165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}; 8265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 8301d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kasten/*static*/ 8401d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kastenconst double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits; 8501d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kasten 86ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenbool AudioResampler::qualityIsSupported(src_quality quality) 87ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 88ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 89ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 90ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 91ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 92ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 93ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 9486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 9586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 9686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 97ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return true; 98ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 99ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return false; 100ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 101ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 102ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 10365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 10465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 105ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 106ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY; 10765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 108ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenvoid AudioResampler::init_routine() 109ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 11065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian char value[PROPERTY_VALUE_MAX]; 111ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (property_get("af.resampler.quality", value, NULL) > 0) { 112ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten char *endptr; 113ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten unsigned long l = strtoul(value, &endptr, 0); 114ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (*endptr == '\0') { 115ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = (src_quality) l; 116ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGD("forcing AudioResampler quality to %d", defaultQuality); 11786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) { 118ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = DEFAULT_QUALITY; 119ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 120ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 121ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 122ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 123ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 124ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenuint32_t AudioResampler::qualityMHz(src_quality quality) 125ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 126ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 127ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 128ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 129ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 130ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 3; 131ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 132ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 6; 133ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 134ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 20; 135ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 136ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 34; 13786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 13886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 4; 13986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 14086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 6; 14186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 14286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 12; 14365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 144ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 145ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 146c4640c9eef850bb1c754bd6b477f1cc8350c6081Glenn Kastenstatic const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable 147ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 148ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic uint32_t currentMHz = 0; 14965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 1503348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount, 151ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) { 152ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 153ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten bool atFinalQuality; 154ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (quality == DEFAULT_QUALITY) { 155ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // read the resampler default quality property the first time it is needed 156ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int ok = pthread_once(&once_control, init_routine); 157ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (ok != 0) { 158ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("%s pthread_once failed: %d", __func__, ok); 159ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 160ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = defaultQuality; 161ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = false; 162ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } else { 163ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 164ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 165ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 1669e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung /* if the caller requests DEFAULT_QUALITY and af.resampler.property 1679e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * has not been set, the target resampler quality is set to DYN_MED_QUALITY, 1689e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary 1699e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * due to estimated CPU load of having too many active resamplers 1709e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * (the code below the if). 1719e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung */ 1729e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung if (quality == DEFAULT_QUALITY) { 1739e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung quality = DYN_MED_QUALITY; 1749e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung } 1759e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung 176ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // naive implementation of CPU load throttling doesn't account for whether resampler is active 177ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 178ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten for (;;) { 179ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 180ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t newMHz = currentMHz + deltaMHz; 181ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { 182ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", 183ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 184ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 185ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 186ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 187ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // not enough CPU available for proposed quality level, so try next lowest level 188ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 189ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 190ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 191ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 192ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 193ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 194ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = LOW_QUALITY; 195ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 196ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 197ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = MED_QUALITY; 198ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 199ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 200ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = HIGH_QUALITY; 201ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 20286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 20386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung atFinalQuality = true; 20486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 20586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 20686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = DYN_LOW_QUALITY; 20786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 20886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 20986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = DYN_MED_QUALITY; 21086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 211ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 212ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 213ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 214ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 215ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten AudioResampler* resampler; 21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 21765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (quality) { 21865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian default: 21965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case LOW_QUALITY: 2203856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create linear Resampler"); 2213348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2223348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerOrder1(inChannelCount, sampleRate); 22365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 22465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case MED_QUALITY: 2253856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create cubic Resampler"); 2263348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2273348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerCubic(inChannelCount, sampleRate); 22865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 22965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case HIGH_QUALITY: 23076b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani ALOGV("Create HIGH_QUALITY sinc Resampler"); 2313348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2323348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerSinc(inChannelCount, sampleRate); 233ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 23476b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani case VERY_HIGH_QUALITY: 235ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); 2363348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2373348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerSinc(inChannelCount, sampleRate, quality); 23865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 23986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 24086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 24186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 24286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung ALOGV("Create dynamic Resampler = %d", quality); 2433348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (format == AUDIO_FORMAT_PCM_FLOAT) { 2443348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<float, float, float>(inChannelCount, 245771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung sampleRate, quality); 246771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung } else { 2473348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2483348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (quality == DYN_HIGH_QUALITY) { 2493348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(inChannelCount, 2503348e36c51e91e78020bcc6578eda83d97c31becAndy Hung sampleRate, quality); 2513348e36c51e91e78020bcc6578eda83d97c31becAndy Hung } else { 2523348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(inChannelCount, 2533348e36c51e91e78020bcc6578eda83d97c31becAndy Hung sampleRate, quality); 2543348e36c51e91e78020bcc6578eda83d97c31becAndy Hung } 255771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung } 25686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 25765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 25865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 25965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize resampler 26065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampler->init(); 26165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return resampler; 26265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 26365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2643348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResampler::AudioResampler(int inChannelCount, 265ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) : 2663348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mChannelCount(inChannelCount), 2673348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), 268d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten mPhaseFraction(0), 269d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten mQuality(quality) { 2703348e36c51e91e78020bcc6578eda83d97c31becAndy Hung 2715e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8; 2723348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (inChannelCount < 1 2735e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung || inChannelCount > maxChannels) { 2743348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels", 2753348e36c51e91e78020bcc6578eda83d97c31becAndy Hung quality, inChannelCount); 27665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 277ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (sampleRate <= 0) { 278075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate); 279ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 28065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize common members 28265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mVolume[0] = mVolume[1] = 0; 28365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = 0; 28465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 28565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianAudioResampler::~AudioResampler() { 287ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 288ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten src_quality quality = getQuality(); 289ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 290ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t newMHz = currentMHz - deltaMHz; 291ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", 292ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 293ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); 294ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 295ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 29765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 29865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResampler::setSampleRate(int32_t inSampleRate) { 29965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInSampleRate = inSampleRate; 30065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); 30165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 30265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3035e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungvoid AudioResampler::setVolume(float left, float right) { 30465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // TODO: Implement anti-zipper filter 3055e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // convert to U4.12 for internal integer use (round down) 3065e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // integer volume values are clamped to 0 to UNITY_GAIN. 3075e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolume[0] = u4_12_from_float(clampFloatVol(left)); 3085e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolume[1] = u4_12_from_float(clampFloatVol(right)); 30965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 31065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 311243f5f91755c01614a8cafe90b0806396e22d553Eric Laurentvoid AudioResampler::reset() { 312243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mInputIndex = 0; 313243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mPhaseFraction = 0; 314243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mBuffer.frameCount = 0; 315243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent} 316243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent 31765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 31865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3196b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, 32065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 32165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 32265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // should never happen, but we overflow if it does 323c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(outFrameCount < 32767); 32465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 32565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // select the appropriate resampler 32665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (mChannelCount) { 32765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 1: 3286b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return resampleMono16(out, outFrameCount, provider); 32965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 2: 3306b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return resampleStereo16(out, outFrameCount, provider); 3316b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung default: 3326b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); 3336b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return 0; 33465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 33565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 33665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3376b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, 33865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 33965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 34065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 34165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 34265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 34365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 34465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 34565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 34665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 34765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 34824781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung size_t inFrameCount = getInFrameCountRequired(outFrameCount); 34965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35090bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 35165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 35265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 35465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 35665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 35765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 358d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten provider->getNextBuffer(&mBuffer); 35965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 36065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleStereo16_exit; 36165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 36265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 36465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 36565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 36765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 36865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 36965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 370e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten // mBuffer.frameCount == 0 now so we reload a new buffer 37165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 37265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 37465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 37665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 37790bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 37865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction); 37965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction); 38065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 3816e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten if (outputIndex == outputSampleCount) { 38265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 3836e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten } 38465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 38565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 38790bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 38865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 39065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 39265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 39365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop 39565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = mBuffer.frameCount - 2; 39665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 39765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 39865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 39965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 40065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 40265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(in[inputIndex*2-2], 40365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2], phaseFraction); 40465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(in[inputIndex*2-1], 40565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2+1], phaseFraction); 40665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 40765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 40865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40990bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 41065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 41265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 41365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 41465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 41665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 41865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 41965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 42065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 422c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 42365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 42465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 42565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 42765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleStereo16_exit: 42965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 43065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 43165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 4326b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return outputIndex / 2 /* channels for stereo */; 43365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 43465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 4356b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, 43665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 43765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 43865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 43965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 44065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 44165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 44265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 44365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 44465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 44565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 44624781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung size_t inFrameCount = getInFrameCountRequired(outFrameCount); 44765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 44890bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 44965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 45065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 45165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 45265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 45365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 454d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten provider->getNextBuffer(&mBuffer); 45565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 45665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 45765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 45865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleMono16_exit; 45965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 46090bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 46165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 46265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 46365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 46465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 46565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 46665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // mBuffer.frameCount == 0 now so we reload a new buffer 46765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 46865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 46965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 47065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 47165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 47290bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 47365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(mX0L, in[0], phaseFraction); 47465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 47565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 47665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 4776e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten if (outputIndex == outputSampleCount) { 47865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 4796e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten } 48065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 48165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 48390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 48465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 48665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 48765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 48865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 48965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 49065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); 49165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = (int32_t)mBuffer.frameCount - 2; 49265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 49365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 49465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 49565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 49665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 49765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 49865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(in[inputIndex-1], in[inputIndex], 49965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction); 50065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 50165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 50265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 50365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 50465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 50765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 50965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 51065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 51165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 51229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 51365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 51465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 51565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 51665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 51765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 518c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 51965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 52065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 52165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52290bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 52365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleMono16_exit: 52565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 52665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 52765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 5286b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return outputIndex; 52965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 53065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 53165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 53265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 53365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 53465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 53565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmMono16Loop 53665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized monotonic loop version; one loop is 2 frames 53765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 53865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 53965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 54065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 54165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 54265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 54365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 54465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 54565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 54665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 54765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 54865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 54965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 55065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 55165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 55265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 55365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 554c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 55565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 55665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 55765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 55865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 559ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxOutPt; // remove unused parameter warnings 560ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxInIdx; 561ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)outputIndex; 562ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)out; 563ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)inputIndex; 564ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vl; 565ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vr; 566ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseFraction; 567ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseIncrement; 568ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)in; 56965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) 57065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 57165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 57265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" 57365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 57465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 57565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 57665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 57765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 57865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out 57965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 58065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 5815f51ade2c290e239a125dc88943b240e1105fd97synergy dev " add r8, r8, r0, asl #2\n" // curOut 58265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement 58365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl 58465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr 58565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 58765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 58965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 59065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 59165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 59265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, Out1 59365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 59465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 59565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 59665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 59765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 59865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 59965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 60065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 60165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 60265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 60465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 60565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 60665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // the following loop works on 2 frames 60865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 609eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "1:\n" 61065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 611eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 2f\n" 61265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 61365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_ONE_FRAME \ 61465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ 61565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[inputIndex] */\ 61665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 61765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ 61865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 61965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ 62065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 62165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 62265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 62365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r0, r4\n" /* x0 - (..) */\ 62465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ 62565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 62665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 62765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ 62865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ 62965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ 63065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 63165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 1 63265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 2 63365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 63465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 635eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 1b\n" 636eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "2:\n" 63765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 63865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 63965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 64065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 64165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 64265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 64365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 64465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out 64565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 64665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 64765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 64865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 64965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 65065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" 65165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 65265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 65365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 65465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 65565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 65665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmStereo16Loop 65765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized stereo loop version; one loop is 2 frames 65865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 65965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 66065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 66165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 66265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 66365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 66465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 66565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 66665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 66765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 66865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 66965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 67065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 67165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 67265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 67365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 67465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 675c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 67665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 67765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 67865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 67965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 680ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxOutPt; // remove unused parameter warnings 681ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxInIdx; 682ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)outputIndex; 683ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)out; 684ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)inputIndex; 685ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vl; 686ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vr; 687ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseFraction; 688ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseIncrement; 689ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)in; 69065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) 69165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 69265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" 69365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 69465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 69565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 69665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 69765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 69865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out 69965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 70065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 7015f51ade2c290e239a125dc88943b240e1105fd97synergy dev " add r8, r8, r0, asl #2\n" // curOut 70265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement 70365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl 70465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr 70565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 70765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 70965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 71065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 71165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 71265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, out1 71365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 71465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 71565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 71665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 71765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 71865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 71965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 72065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 72165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 72265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 temporary 72465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 72565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 72665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 727eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "3:\n" 72865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 729eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 4f\n" 73065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 73165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_ONE_FRAME \ 73265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 73365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 73465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ 73565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 73665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ 73765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 73865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ 73965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 74065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 74165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 74265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r12, r4\n" /* x0 - (..) */\ 74365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ 74465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 74565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 74665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 74765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ 74865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ 74965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 75065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r12, r12, lsl #2\n" /* <<2 */\ 75165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ 75265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r0, r12\n" /* x0 - (..) */\ 75365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ 75465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ 75565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 75665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 75765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ 75865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 75965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 76065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 76165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 76265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 763eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 3b\n" 764eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "4:\n" 76565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 76665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 76765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 76865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 76965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 77065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 77165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 77265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out 77365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 77465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 77565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 77665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 77765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 77865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" 77965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 78065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 78165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 78265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 78365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 78465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 78565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 78665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 787c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten} // namespace android 788