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> 255e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung#include <audio_utils/primitives.h> 2665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResampler.h" 2765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerSinc.h" 2865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerCubic.h" 2986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung#include "AudioResamplerDyn.h" 3065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 310c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#ifdef __arm__ 32505fd3025855f424353ae084495e1855522cf65bGlenn Kasten // bug 13102576 33505fd3025855f424353ae084495e1855522cf65bGlenn Kasten //#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 340c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif 350c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang 3665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android { 3765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 3965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 4065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianclass AudioResamplerOrder1 : public AudioResampler { 4165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianpublic: 423348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResamplerOrder1(int inChannelCount, int32_t sampleRate) : 433348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResampler(inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { 4465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 456b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung virtual size_t 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() {} 556b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung size_t resampleMono16(int32_t* out, size_t outFrameCount, 5665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 576b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung size_t 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 8001d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kasten/*static*/ 8101d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kastenconst double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits; 8201d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kasten 83ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenbool AudioResampler::qualityIsSupported(src_quality quality) 84ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 85ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 86ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 87ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 88ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 89ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 90ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 9186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 9286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 9386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 94ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return true; 95ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 96ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return false; 97ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 98ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 99ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 10065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 10165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 102ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 103ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY; 10465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 105ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenvoid AudioResampler::init_routine() 106ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 10765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian char value[PROPERTY_VALUE_MAX]; 108ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (property_get("af.resampler.quality", value, NULL) > 0) { 109ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten char *endptr; 110ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten unsigned long l = strtoul(value, &endptr, 0); 111ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (*endptr == '\0') { 112ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = (src_quality) l; 113ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGD("forcing AudioResampler quality to %d", defaultQuality); 11486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) { 115ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = DEFAULT_QUALITY; 116ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 117ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 118ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 119ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 120ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 121ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenuint32_t AudioResampler::qualityMHz(src_quality quality) 122ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 123ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 124ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 125ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 126ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 127ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 3; 128ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 129ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 6; 130ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 131ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 20; 132ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 133ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 34; 13486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 13586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 4; 13686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 13786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 6; 13886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 13986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 12; 14065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 141ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 142ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 143c4640c9eef850bb1c754bd6b477f1cc8350c6081Glenn Kastenstatic const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable 144ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 145ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic uint32_t currentMHz = 0; 14665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 1473348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount, 148ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) { 149ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 150ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten bool atFinalQuality; 151ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (quality == DEFAULT_QUALITY) { 152ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // read the resampler default quality property the first time it is needed 153ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int ok = pthread_once(&once_control, init_routine); 154ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (ok != 0) { 155ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("%s pthread_once failed: %d", __func__, ok); 156ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 157ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = defaultQuality; 158ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = false; 159ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } else { 160ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 161ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 162ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 1639e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung /* if the caller requests DEFAULT_QUALITY and af.resampler.property 1649e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * has not been set, the target resampler quality is set to DYN_MED_QUALITY, 1659e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary 1669e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * due to estimated CPU load of having too many active resamplers 1679e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * (the code below the if). 1689e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung */ 1699e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung if (quality == DEFAULT_QUALITY) { 1709e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung quality = DYN_MED_QUALITY; 1719e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung } 1729e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung 173ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // naive implementation of CPU load throttling doesn't account for whether resampler is active 174ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 175ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten for (;;) { 176ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 177ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t newMHz = currentMHz + deltaMHz; 178ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { 179ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", 180ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 181ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 182ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 183ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 184ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // not enough CPU available for proposed quality level, so try next lowest level 185ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 186ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 187ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 188ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 189ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 190ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 191ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = LOW_QUALITY; 192ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 193ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 194ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = MED_QUALITY; 195ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 196ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 197ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = HIGH_QUALITY; 198ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 19986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 20086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung atFinalQuality = true; 20186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 20286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 20386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = DYN_LOW_QUALITY; 20486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 20586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 20686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = DYN_MED_QUALITY; 20786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 208ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 209ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 210ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 211ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 212ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten AudioResampler* resampler; 21365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 21465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (quality) { 21565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian default: 21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case LOW_QUALITY: 2173856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create linear Resampler"); 2183348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2193348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerOrder1(inChannelCount, sampleRate); 22065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 22165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case MED_QUALITY: 2223856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create cubic Resampler"); 2233348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2243348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerCubic(inChannelCount, sampleRate); 22565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 22665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case HIGH_QUALITY: 22776b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani ALOGV("Create HIGH_QUALITY sinc Resampler"); 2283348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2293348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerSinc(inChannelCount, sampleRate); 230ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 23176b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani case VERY_HIGH_QUALITY: 232ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); 2333348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2343348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerSinc(inChannelCount, sampleRate, quality); 23565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 23686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 23786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 23886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 23986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung ALOGV("Create dynamic Resampler = %d", quality); 2403348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (format == AUDIO_FORMAT_PCM_FLOAT) { 2413348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<float, float, float>(inChannelCount, 242771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung sampleRate, quality); 243771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung } else { 2443348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2453348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (quality == DYN_HIGH_QUALITY) { 2463348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(inChannelCount, 2473348e36c51e91e78020bcc6578eda83d97c31becAndy Hung sampleRate, quality); 2483348e36c51e91e78020bcc6578eda83d97c31becAndy Hung } else { 2493348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(inChannelCount, 2503348e36c51e91e78020bcc6578eda83d97c31becAndy Hung sampleRate, quality); 2513348e36c51e91e78020bcc6578eda83d97c31becAndy Hung } 252771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung } 25386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 25465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 25565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 25665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize resampler 25765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampler->init(); 25865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return resampler; 25965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 26065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2613348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResampler::AudioResampler(int inChannelCount, 262ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) : 2633348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mChannelCount(inChannelCount), 2643348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), 265d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten mPhaseFraction(0), 266d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten mQuality(quality) { 2673348e36c51e91e78020bcc6578eda83d97c31becAndy Hung 2685e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8; 2693348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (inChannelCount < 1 2705e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung || inChannelCount > maxChannels) { 2713348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels", 2723348e36c51e91e78020bcc6578eda83d97c31becAndy Hung quality, inChannelCount); 27365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 274ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (sampleRate <= 0) { 275075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate); 276ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 27765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 27865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize common members 27965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mVolume[0] = mVolume[1] = 0; 28065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = 0; 28165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 28265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianAudioResampler::~AudioResampler() { 284ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 285ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten src_quality quality = getQuality(); 286ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 287ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t newMHz = currentMHz - deltaMHz; 288ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", 289ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 290ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); 291ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 292ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 29365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 29465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 29565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResampler::setSampleRate(int32_t inSampleRate) { 29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInSampleRate = inSampleRate; 29765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); 29865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 29965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3005e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungvoid AudioResampler::setVolume(float left, float right) { 30165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // TODO: Implement anti-zipper filter 3025e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // convert to U4.12 for internal integer use (round down) 3035e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // integer volume values are clamped to 0 to UNITY_GAIN. 3045e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolume[0] = u4_12_from_float(clampFloatVol(left)); 3055e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolume[1] = u4_12_from_float(clampFloatVol(right)); 30665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 30765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 308243f5f91755c01614a8cafe90b0806396e22d553Eric Laurentvoid AudioResampler::reset() { 309243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mInputIndex = 0; 310243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mPhaseFraction = 0; 311243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mBuffer.frameCount = 0; 312243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent} 313243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent 31465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 31565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3166b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, 31765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 31865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 31965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // should never happen, but we overflow if it does 320c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(outFrameCount < 32767); 32165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 32265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // select the appropriate resampler 32365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (mChannelCount) { 32465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 1: 3256b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return resampleMono16(out, outFrameCount, provider); 32665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 2: 3276b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return resampleStereo16(out, outFrameCount, provider); 3286b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung default: 3296b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount); 3306b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return 0; 33165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 33265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 33365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3346b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, 33565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 33665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 33765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 33865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 33965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 34065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 34165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 34265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 34365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 34465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 34524781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung size_t inFrameCount = getInFrameCountRequired(outFrameCount); 34665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 34790bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 34865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 34965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 35165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 35365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 35465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 355d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten provider->getNextBuffer(&mBuffer); 35665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 35765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleStereo16_exit; 35865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 35965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36090bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 36165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 36265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 36465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 36565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 36665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 367e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten // mBuffer.frameCount == 0 now so we reload a new buffer 36865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 36965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 37165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 37365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 37490bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 37565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction); 37665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction); 37765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 3786e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten if (outputIndex == outputSampleCount) { 37965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 3806e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten } 38165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 38265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 38490bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 38565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 38765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 38865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 38965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 39065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop 39265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = mBuffer.frameCount - 2; 39365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 39465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 39565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 39665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 39765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 39965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(in[inputIndex*2-2], 40065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2], phaseFraction); 40165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(in[inputIndex*2-1], 40265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2+1], phaseFraction); 40365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 40465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 40565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 40765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 40965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 41065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 41165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 41365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 41565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 41665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 41765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 419c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 42065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 42165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 42265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 42465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleStereo16_exit: 42665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 42765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 42865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 4296b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return outputIndex / 2 /* channels for stereo */; 43065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 43165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 4326b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hungsize_t AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, 43365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 43465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 43565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 43665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 43765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 43865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 43965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 44065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 44165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 44265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 44324781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung size_t inFrameCount = getInFrameCountRequired(outFrameCount); 44465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 44590bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 44665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 44765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 44865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 44965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 45065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 451d79072e9dff59f767cce2cda1caab80ce5a0815bGlenn Kasten provider->getNextBuffer(&mBuffer); 45265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 45365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 45465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 45565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleMono16_exit; 45665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 45790bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 45865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 45965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 46065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 46165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 46265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 46365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // mBuffer.frameCount == 0 now so we reload a new buffer 46465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 46565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 46665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 46765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 46865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 46990bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 47065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(mX0L, in[0], phaseFraction); 47165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 47265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 47365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 4746e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten if (outputIndex == outputSampleCount) { 47565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 4766e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten } 47765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 47865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 47965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 48090bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 48165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 48365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 48465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 48565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 48665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); 48865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = (int32_t)mBuffer.frameCount - 2; 48965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 49065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 49165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 49265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 49365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 49465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 49565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(in[inputIndex-1], in[inputIndex], 49665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction); 49765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 49865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 49965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 50065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 50165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 50465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 50665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 50765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 50865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 51065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 51165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 51265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 51365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 51465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 515c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 51665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 51765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 51865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 51990bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 52065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleMono16_exit: 52265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 52365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 52465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 5256b3b7e304e0f8f167241b2c75f1eb04a9ef192ecAndy Hung return outputIndex; 52665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 52765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 52965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 53065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 53165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 53265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmMono16Loop 53365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized monotonic loop version; one loop is 2 frames 53465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 53565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 53665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 53765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 53865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 53965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 54065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 54165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 54265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 54365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 54465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 54565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 54665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 54765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 54865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 54965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 55065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 551c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 55265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 55365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 55465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 55565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 556ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxOutPt; // remove unused parameter warnings 557ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxInIdx; 558ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)outputIndex; 559ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)out; 560ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)inputIndex; 561ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vl; 562ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vr; 563ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseFraction; 564ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseIncrement; 565ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)in; 56665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) 56765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 56865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 56965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" 57065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 57165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 57265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 57365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 57465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 57565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out 57665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 57765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 5785f51ade2c290e239a125dc88943b240e1105fd97synergy dev " add r8, r8, r0, asl #2\n" // curOut 57965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement 58065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl 58165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr 58265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 58465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 58665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 58765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 58865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, Out1 59065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 59165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 59265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 59365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 59465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 59565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 59665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 59765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 59865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 59965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 60165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 60265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 60365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // the following loop works on 2 frames 60565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 606eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "1:\n" 60765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 608eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 2f\n" 60965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 61065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_ONE_FRAME \ 61165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ 61265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[inputIndex] */\ 61365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 61465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ 61565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 61665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ 61765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 61865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 61965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 62065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r0, r4\n" /* x0 - (..) */\ 62165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ 62265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 62365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 62465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ 62565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ 62665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ 62765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 62865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 1 62965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 2 63065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 63165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 632eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 1b\n" 633eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "2:\n" 63465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 63565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 63665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 63765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 63865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 63965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 64065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 64165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out 64265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 64365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 64465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 64565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 64665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 64765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" 64865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 64965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 65065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 65165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 65265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 65365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmStereo16Loop 65465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized stereo loop version; one loop is 2 frames 65565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 65665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 65765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 65865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 65965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 66065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 66165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 66265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 66365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 66465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 66565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 66665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 66765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 66865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 66965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 67065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 67165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 672c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 67365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 67465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 67565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 67665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 677ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxOutPt; // remove unused parameter warnings 678ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxInIdx; 679ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)outputIndex; 680ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)out; 681ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)inputIndex; 682ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vl; 683ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vr; 684ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseFraction; 685ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseIncrement; 686ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)in; 68765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) 68865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 68965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" 69065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 69165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 69265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 69365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 69465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 69565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out 69665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 69765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 6985f51ade2c290e239a125dc88943b240e1105fd97synergy dev " add r8, r8, r0, asl #2\n" // curOut 69965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement 70065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl 70165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr 70265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 70465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 70665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 70765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 70865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 70965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, out1 71065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 71165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 71265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 71365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 71465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 71565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 71665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 71765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 71865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 71965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 temporary 72165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 72265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 72365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 724eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "3:\n" 72565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 726eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 4f\n" 72765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_ONE_FRAME \ 72965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 73065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 73165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ 73265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 73365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ 73465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 73565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ 73665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 73765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 73865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 73965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r12, r4\n" /* x0 - (..) */\ 74065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ 74165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 74265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 74365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 74465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ 74565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ 74665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 74765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r12, r12, lsl #2\n" /* <<2 */\ 74865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ 74965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r0, r12\n" /* x0 - (..) */\ 75065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ 75165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ 75265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 75365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 75465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ 75565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 75665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 75765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 75865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 75965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 760eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 3b\n" 761eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "4:\n" 76265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 76365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 76465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 76565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 76665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 76765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 76865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 76965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out 77065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 77165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 77265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 77365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 77465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 77565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" 77665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 77765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 77865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 77965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 78065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 78165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 78265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 78365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 784c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten} // namespace android 785