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__ 320c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#include <machine/cpu-features.h> 330c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif 340c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang 3565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android { 3665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 370c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option 38c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1 390c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif // __ARM_HAVE_HALFWORD_MULTIPLY 4065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 4165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 4265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianclass AudioResamplerOrder1 : public AudioResampler { 4365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianpublic: 443348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResamplerOrder1(int inChannelCount, int32_t sampleRate) : 453348e36c51e91e78020bcc6578eda83d97c31becAndy Hung AudioResampler(inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) { 4665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 4765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian virtual void resample(int32_t* out, size_t outFrameCount, 4865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 4965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianprivate: 5065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // number of bits used in interpolation multiply - 15 bits avoids overflow 5165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static const int kNumInterpBits = 15; 5265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // bits to shift the phase fraction down to avoid overflow 5465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits; 5565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 5665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void init() {} 5765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void resampleMono16(int32_t* out, size_t outFrameCount, 5865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 5965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void resampleStereo16(int32_t* out, size_t outFrameCount, 6065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider); 6165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 6265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 6365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 6465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement); 6565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 6665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 6765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement); 6865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 6965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 7065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) { 7165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits); 7265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 7365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) { 7465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *frac += inc; 7565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *index += (size_t)(*frac >> kNumPhaseBits); 7665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian *frac &= kPhaseMask; 7765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 7865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int mX0L; 7965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int mX0R; 8065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}; 8165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 8201d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kasten/*static*/ 8301d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kastenconst double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits; 8401d3acba9de861cb2b718338e787cff3566fc5ecGlenn Kasten 85ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenbool AudioResampler::qualityIsSupported(src_quality quality) 86ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 87ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 88ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 89ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 90ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 91ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 92ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 9386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 9486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 9586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 96ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return true; 97ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 98ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return false; 99ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 100ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 101ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 10265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 10365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 104ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT; 105ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY; 10665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 107ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenvoid AudioResampler::init_routine() 108ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 10965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian char value[PROPERTY_VALUE_MAX]; 110ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (property_get("af.resampler.quality", value, NULL) > 0) { 111ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten char *endptr; 112ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten unsigned long l = strtoul(value, &endptr, 0); 113ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (*endptr == '\0') { 114ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = (src_quality) l; 115ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGD("forcing AudioResampler quality to %d", defaultQuality); 11686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) { 117ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten defaultQuality = DEFAULT_QUALITY; 118ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 119ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 120ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 121ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 122ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 123ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenuint32_t AudioResampler::qualityMHz(src_quality quality) 124ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{ 125ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 126ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 127ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case DEFAULT_QUALITY: 128ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 129ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 3; 130ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 131ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 6; 132ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 133ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 20; 134ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 135ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten return 34; 13686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 13786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 4; 13886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 13986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 6; 14086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 14186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung return 12; 14265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 143ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten} 144ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 145c4640c9eef850bb1c754bd6b477f1cc8350c6081Glenn Kastenstatic const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable 146ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 147ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic uint32_t currentMHz = 0; 14865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 1493348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount, 150ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) { 151ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 152ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten bool atFinalQuality; 153ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (quality == DEFAULT_QUALITY) { 154ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // read the resampler default quality property the first time it is needed 155ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int ok = pthread_once(&once_control, init_routine); 156ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (ok != 0) { 157ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGE("%s pthread_once failed: %d", __func__, ok); 158ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 159ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = defaultQuality; 160ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = false; 161ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } else { 162ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 163ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 164ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 1659e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung /* if the caller requests DEFAULT_QUALITY and af.resampler.property 1669e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * has not been set, the target resampler quality is set to DYN_MED_QUALITY, 1679e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary 1689e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * due to estimated CPU load of having too many active resamplers 1699e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung * (the code below the if). 1709e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung */ 1719e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung if (quality == DEFAULT_QUALITY) { 1729e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung quality = DYN_MED_QUALITY; 1739e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung } 1749e0308c03d4e76d3146cbb6e30aeb3ac03f05cf5Andy Hung 175ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // naive implementation of CPU load throttling doesn't account for whether resampler is active 176ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 177ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten for (;;) { 178ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 179ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t newMHz = currentMHz + deltaMHz; 180ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) { 181ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d", 182ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 183ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 184ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 185ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 186ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten // not enough CPU available for proposed quality level, so try next lowest level 187ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten switch (quality) { 188ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten default: 189ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case LOW_QUALITY: 190ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten atFinalQuality = true; 191ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 192ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case MED_QUALITY: 193ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = LOW_QUALITY; 194ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 195ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case HIGH_QUALITY: 196ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = MED_QUALITY; 197ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 198ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten case VERY_HIGH_QUALITY: 199ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten quality = HIGH_QUALITY; 200ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 20186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 20286eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung atFinalQuality = true; 20386eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 20486eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 20586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = DYN_LOW_QUALITY; 20686eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 20786eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 20886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung quality = DYN_MED_QUALITY; 20986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 210ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 211ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 212ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 213ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten 214ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten AudioResampler* resampler; 21565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (quality) { 21765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian default: 21865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case LOW_QUALITY: 2193856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create linear Resampler"); 2203348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2213348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerOrder1(inChannelCount, sampleRate); 22265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 22365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case MED_QUALITY: 2243856b090cd04ba5dd4a59a12430ed724d5995909Steve Block ALOGV("Create cubic Resampler"); 2253348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2263348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerCubic(inChannelCount, sampleRate); 22765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 22865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case HIGH_QUALITY: 22976b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani ALOGV("Create HIGH_QUALITY sinc Resampler"); 2303348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2313348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerSinc(inChannelCount, sampleRate); 232ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten break; 23376b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani case VERY_HIGH_QUALITY: 234ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality); 2353348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2363348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerSinc(inChannelCount, sampleRate, quality); 23765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 23886eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_LOW_QUALITY: 23986eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_MED_QUALITY: 24086eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung case DYN_HIGH_QUALITY: 24186eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung ALOGV("Create dynamic Resampler = %d", quality); 2423348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (format == AUDIO_FORMAT_PCM_FLOAT) { 2433348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<float, float, float>(inChannelCount, 244771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung sampleRate, quality); 245771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung } else { 2463348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT); 2473348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (quality == DYN_HIGH_QUALITY) { 2483348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(inChannelCount, 2493348e36c51e91e78020bcc6578eda83d97c31becAndy Hung sampleRate, quality); 2503348e36c51e91e78020bcc6578eda83d97c31becAndy Hung } else { 2513348e36c51e91e78020bcc6578eda83d97c31becAndy Hung resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(inChannelCount, 2523348e36c51e91e78020bcc6578eda83d97c31becAndy Hung sampleRate, quality); 2533348e36c51e91e78020bcc6578eda83d97c31becAndy Hung } 254771386e6e6e79697e2d839ef0f25a242946ba1e5Andy Hung } 25586eae0e5931103e040ac2cdd023ef5db252e09f6Andy Hung break; 25665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 25765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 25865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize resampler 25965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampler->init(); 26065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian return resampler; 26165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 26265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 2633348e36c51e91e78020bcc6578eda83d97c31becAndy HungAudioResampler::AudioResampler(int inChannelCount, 264ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t sampleRate, src_quality quality) : 2653348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mChannelCount(inChannelCount), 2663348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0), 2673348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mPhaseFraction(0), mLocalTimeFreq(0), 2683348e36c51e91e78020bcc6578eda83d97c31becAndy Hung mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) { 2693348e36c51e91e78020bcc6578eda83d97c31becAndy Hung 2705e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung const int maxChannels = quality < DYN_LOW_QUALITY ? 2 : 8; 2713348e36c51e91e78020bcc6578eda83d97c31becAndy Hung if (inChannelCount < 1 2725e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung || inChannelCount > maxChannels) { 2733348e36c51e91e78020bcc6578eda83d97c31becAndy Hung LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels", 2743348e36c51e91e78020bcc6578eda83d97c31becAndy Hung quality, inChannelCount); 27565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 276ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten if (sampleRate <= 0) { 277075abae2a954bf3edf18ad1705c2c0f188454ae0Andy Hung LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate); 278ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten } 27965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // initialize common members 28165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mVolume[0] = mVolume[1] = 0; 28265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = 0; 28365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 28465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 28565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianAudioResampler::~AudioResampler() { 286ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_lock(&mutex); 287ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten src_quality quality = getQuality(); 288ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten uint32_t deltaMHz = qualityMHz(quality); 289ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten int32_t newMHz = currentMHz - deltaMHz; 290ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d", 291ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz, newMHz, deltaMHz, quality); 292ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz); 293ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten currentMHz = newMHz; 294ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten pthread_mutex_unlock(&mutex); 29565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 29765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResampler::setSampleRate(int32_t inSampleRate) { 29865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInSampleRate = inSampleRate; 29965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate); 30065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 30165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3025e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hungvoid AudioResampler::setVolume(float left, float right) { 30365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // TODO: Implement anti-zipper filter 3045e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // convert to U4.12 for internal integer use (round down) 3055e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung // integer volume values are clamped to 0 to UNITY_GAIN. 3065e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolume[0] = u4_12_from_float(clampFloatVol(left)); 3075e58b0abe5b6c8f5bd96a8f78bbeeeb4d3892020Andy Hung mVolume[1] = u4_12_from_float(clampFloatVol(right)); 30865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 30965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 3104ff14bae91075eb274eb1c2975982358946e7e63John Grossmanvoid AudioResampler::setLocalTimeFreq(uint64_t freq) { 3114ff14bae91075eb274eb1c2975982358946e7e63John Grossman mLocalTimeFreq = freq; 3124ff14bae91075eb274eb1c2975982358946e7e63John Grossman} 3134ff14bae91075eb274eb1c2975982358946e7e63John Grossman 3144ff14bae91075eb274eb1c2975982358946e7e63John Grossmanvoid AudioResampler::setPTS(int64_t pts) { 3154ff14bae91075eb274eb1c2975982358946e7e63John Grossman mPTS = pts; 3164ff14bae91075eb274eb1c2975982358946e7e63John Grossman} 3174ff14bae91075eb274eb1c2975982358946e7e63John Grossman 3184ff14bae91075eb274eb1c2975982358946e7e63John Grossmanint64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) { 3194ff14bae91075eb274eb1c2975982358946e7e63John Grossman 3204ff14bae91075eb274eb1c2975982358946e7e63John Grossman if (mPTS == AudioBufferProvider::kInvalidPTS) { 3214ff14bae91075eb274eb1c2975982358946e7e63John Grossman return AudioBufferProvider::kInvalidPTS; 3224ff14bae91075eb274eb1c2975982358946e7e63John Grossman } else { 3234ff14bae91075eb274eb1c2975982358946e7e63John Grossman return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate); 3244ff14bae91075eb274eb1c2975982358946e7e63John Grossman } 3254ff14bae91075eb274eb1c2975982358946e7e63John Grossman} 3264ff14bae91075eb274eb1c2975982358946e7e63John Grossman 327243f5f91755c01614a8cafe90b0806396e22d553Eric Laurentvoid AudioResampler::reset() { 328243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mInputIndex = 0; 329243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mPhaseFraction = 0; 330243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent mBuffer.frameCount = 0; 331243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent} 332243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent 33365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 33465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 33565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount, 33665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 33765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 33865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // should never happen, but we overflow if it does 339c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(outFrameCount < 32767); 34065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 34165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // select the appropriate resampler 34265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian switch (mChannelCount) { 34365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 1: 34465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampleMono16(out, outFrameCount, provider); 34565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 34665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian case 2: 34765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian resampleStereo16(out, outFrameCount, provider); 34865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 34965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 35065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 35165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount, 35365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 35465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 35665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 35765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 35865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 35965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 36065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 36165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 36265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 36324781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung size_t inFrameCount = getInFrameCountRequired(outFrameCount); 36465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36590bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 36665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 36765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 36865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 36965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 37165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 37265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 3734ff14bae91075eb274eb1c2975982358946e7e63John Grossman provider->getNextBuffer(&mBuffer, 3744ff14bae91075eb274eb1c2975982358946e7e63John Grossman calculateOutputPTS(outputIndex / 2)); 37565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 37665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleStereo16_exit; 37765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 37865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 37990bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 38065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 38165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 38365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 38465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 38565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 386e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten // mBuffer.frameCount == 0 now so we reload a new buffer 38765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 38865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 38965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 39065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 39265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 39390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 39465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction); 39565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction); 39665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 3976e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten if (outputIndex == outputSampleCount) { 39865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 3996e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten } 40065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 40165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 40390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 40465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 40565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 40665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 40765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 40865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 40965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); // 2 because 2 frames per loop 41165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = mBuffer.frameCount - 2; 41265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 41365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 41465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 41565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 41665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 41765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 41865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * Interp(in[inputIndex*2-2], 41965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2], phaseFraction); 42065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * Interp(in[inputIndex*2-1], 42165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian in[inputIndex*2+1], phaseFraction); 42265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 42365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 42465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42590bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 42665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 42765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 42865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 42965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 43065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 43129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 43265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 43365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount*2-2]; 43465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0R = mBuffer.i16[mBuffer.frameCount*2-1]; 43565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 43665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 43765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 438c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 43965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 44065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 44165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 44290bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 44365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 44465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleStereo16_exit: 44565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 44665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 44765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 44865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 44965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 45065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount, 45165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AudioBufferProvider* provider) { 45265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 45365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vl = mVolume[0]; 45465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t vr = mVolume[1]; 45565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 45665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t inputIndex = mInputIndex; 45765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseFraction = mPhaseFraction; 45865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t phaseIncrement = mPhaseIncrement; 45965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputIndex = 0; 46065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t outputSampleCount = outFrameCount * 2; 46124781fff62a4cf7279d3dac83c33e2ac612712baAndy Hung size_t inFrameCount = getInFrameCountRequired(outFrameCount); 46265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 46390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d", 46465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // outFrameCount, inputIndex, phaseFraction, phaseIncrement); 46565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount) { 46665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // buffer is empty, fetch a new one 46765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (mBuffer.frameCount == 0) { 46865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mBuffer.frameCount = inFrameCount; 4694ff14bae91075eb274eb1c2975982358946e7e63John Grossman provider->getNextBuffer(&mBuffer, 4704ff14bae91075eb274eb1c2975982358946e7e63John Grossman calculateOutputPTS(outputIndex / 2)); 47165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.raw == NULL) { 47265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 47365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 47465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian goto resampleMono16_exit; 47565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 47690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount); 47765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (mBuffer.frameCount > inputIndex) break; 47865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 47965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 48065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 48165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 48265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // mBuffer.frameCount == 0 now so we reload a new buffer 48365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 48465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int16_t *in = mBuffer.i16; 48565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 48665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // handle boundary case 48765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (inputIndex == 0) { 48890bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("boundary case"); 48965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(mX0L, in[0], phaseFraction); 49065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 49165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 49265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 4936e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten if (outputIndex == outputSampleCount) { 49465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian break; 4956e2ebe97f2ad0a21907f20f9ee644c4eacbb7a40Glenn Kasten } 49665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 49765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 49865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // process input samples 49990bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("general case"); 50065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 50265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex + 2 < mBuffer.frameCount) { 50365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t* maxOutPt; 50465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t maxInIdx; 50565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 50665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxOutPt = out + (outputSampleCount - 2); 50765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian maxInIdx = (int32_t)mBuffer.frameCount - 2; 50865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr, 50965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction, phaseIncrement); 51065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 51165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 51265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 51365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) { 51465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian int32_t sample = Interp(in[inputIndex-1], in[inputIndex], 51565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian phaseFraction); 51665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vl * sample; 51765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian out[outputIndex++] += vr * sample; 51865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian Advance(&inputIndex, &phaseFraction, phaseIncrement); 51965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 52065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52290bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 52365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // if done with buffer, save samples 52565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian if (inputIndex >= mBuffer.frameCount) { 52665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian inputIndex -= mBuffer.frameCount; 52765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 52829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block // ALOGE("buffer done, new input index %d", inputIndex); 52965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 53065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mX0L = mBuffer.i16[mBuffer.frameCount-1]; 53165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian provider->releaseBuffer(&mBuffer); 53265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 53365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // verify that the releaseBuffer resets the buffer frameCount 534c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block // ALOG_ASSERT(mBuffer.frameCount == 0); 53565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 53665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian } 53765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 53890bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex); 53965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 54065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleMono16_exit: 54165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save state 54265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mInputIndex = inputIndex; 54365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian mPhaseFraction = phaseFraction; 54465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 54565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 54665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1 // asm optimisation for ResamplerOrder1 54765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 54865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 54965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 55065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmMono16Loop 55165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized monotonic loop version; one loop is 2 frames 55265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 55365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 55465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 55565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 55665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 55765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 55865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 55965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 56065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 56165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 56265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 56365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 56465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 56565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 56665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 56765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 56865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 569c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 57065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 57165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 57265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 57365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 574ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxOutPt; // remove unused parameter warnings 575ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxInIdx; 576ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)outputIndex; 577ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)out; 578ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)inputIndex; 579ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vl; 580ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vr; 581ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseFraction; 582ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseIncrement; 583ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)in; 58465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_PARAM5 "36" // offset of parameter 5 (outputIndex) 58565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 58665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 58765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n" 58865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 58965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 59065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 59165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 59265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 59365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" MO_PARAM5 " + 4]\n" // out 59465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 59565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 5965f51ade2c290e239a125dc88943b240e1105fd97synergy dev " add r8, r8, r0, asl #2\n" // curOut 59765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" MO_PARAM5 " + 24]\n" // phaseIncrement 59865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" MO_PARAM5 " + 12]\n" // vl 59965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" MO_PARAM5 " + 16]\n" // vr 60065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 60265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 60465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 60565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 60665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 60765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, Out1 60865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 60965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 61065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 61165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 61265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 61365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 61465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 61565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 61665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 61765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 61865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 61965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 62065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 62165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 62265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // the following loop works on 2 frames 62365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 624eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "1:\n" 62565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 626eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 2f\n" 62765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 62865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_ONE_FRAME \ 62965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #1\n" /* in + inputIndex */\ 63065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[inputIndex] */\ 63165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 63265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[inputIndex-1] */\ 63365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 63465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r0\n" /* in[inputIndex] - in[inputIndex-1] */\ 63565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 63665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 63765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 63865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r0, r4\n" /* x0 - (..) */\ 63965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r0, r10, r5\n" /* vl*interp + out[] */\ 64065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 64165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 64265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r0, r11, r4\n" /* vr*interp + out[] */\ 64365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */\ 64465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */ 64565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 64665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 1 64765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian MO_ONE_FRAME // frame 2 64865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 64965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 650eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 1b\n" 651eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "2:\n" 65265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 65365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 65465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 65565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 20]\n" // &phaseFraction 65665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 65765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 8]\n" // &inputIndex 65865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 65965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 4]\n" // out 66065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 66165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 66265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" MO_PARAM5 " + 0]\n" // &outputIndex 66365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 66465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 66565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n" 66665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 66765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 66865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 66965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/******************************************************************* 67065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 67165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* AsmStereo16Loop 67265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* asm optimized stereo loop version; one loop is 2 frames 67365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Input: 67465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* in : pointer on input samples 67565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxOutPt : pointer on first not filled 67665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* maxInIdx : index on first not used 67765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : pointer on current output index 67865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : pointer on output buffer 67965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : pointer on current input index 68065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* vl, vr : left and right gain 68165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : pointer on current phase fraction 68265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseIncrement 68365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* Ouput: 68465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* outputIndex : 68565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* out : updated buffer 68665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* inputIndex : index of next to use 68765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* phaseFraction : phase fraction for next interpolation 68865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian* 68965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/ 690c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline)) 69165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx, 69265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr, 69365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian uint32_t &phaseFraction, uint32_t phaseIncrement) 69465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{ 695ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxOutPt; // remove unused parameter warnings 696ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)maxInIdx; 697ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)outputIndex; 698ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)out; 699ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)inputIndex; 700ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vl; 701ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)vr; 702ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseFraction; 703ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)phaseIncrement; 704ee931ff7d6620e5705f4dfba901fdb03fa4a35fdAndy Hung (void)in; 70565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_PARAM5 "40" // offset of parameter 5 (outputIndex) 70665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian asm( 70765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian "stmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n" 70865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // get parameters 70965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 71065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r6, [r6]\n" // phaseFraction 71165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 71265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r7, [r7]\n" // inputIndex 71365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r8, [sp, #" ST_PARAM5 " + 4]\n" // out 71465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 71565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [r0]\n" // outputIndex 7165f51ade2c290e239a125dc88943b240e1105fd97synergy dev " add r8, r8, r0, asl #2\n" // curOut 71765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r9, [sp, #" ST_PARAM5 " + 24]\n" // phaseIncrement 71865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r10, [sp, #" ST_PARAM5 " + 12]\n" // vl 71965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r11, [sp, #" ST_PARAM5 " + 16]\n" // vr 72065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r0 pin, x0, Samp 72265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r1 in 72465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r2 maxOutPt 72565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r3 maxInIdx 72665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 72765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r4 x1, i1, i3, out1 72865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r5 out0 72965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 73065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r6 frac 73165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r7 inputIndex 73265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r8 curOut 73365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 73465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r9 inc 73565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r10 vl 73665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r11 vr 73765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 73865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r12 temporary 73965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r13 sp 74065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // r14 74165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 742eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "3:\n" 74365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r8, r2\n" // curOut - maxCurOut 744eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcs 4f\n" 74565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 74665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_ONE_FRAME \ 74765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" /* phaseFraction & ... */\ 74865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 74965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r0, r1, r7, asl #2\n" /* in + 2*inputIndex */\ 75065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 75165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r4, [r0]\n" /* in[2*inputIndex] */\ 75265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r5, [r8]\n" /* out[outputIndex] */\ 75365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #-4]\n" /* in[2*inputIndex-2] */\ 75465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r4, r4, r12\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 75565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r4, r4, lsl #2\n" /* <<2 */\ 75665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r4, r4, r6\n" /* (x1-x0)*.. */\ 75765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r12, r4\n" /* x0 - (..) */\ 75865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r5, r12, r10, r5\n" /* vl*interp + out[] */\ 75965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r4, [r8, #4]\n" /* out[outputIndex+1] */\ 76065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r5, [r8], #4\n" /* out[outputIndex++] = ... */\ 76165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 76265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r12, [r0, #+2]\n" /* in[2*inputIndex+1] */\ 76365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldrsh r0, [r0, #-2]\n" /* in[2*inputIndex-1] */\ 76465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r12, r12, r0\n" /* in[2*InputIndex] - in[2*InputIndex-2] */\ 76565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mov r12, r12, lsl #2\n" /* <<2 */\ 76665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " smulwt r12, r12, r6\n" /* (x1-x0)*.. */\ 76765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r12, r0, r12\n" /* x0 - (..) */\ 76865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " mla r4, r12, r11, r4\n" /* vr*interp + out[] */\ 76965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r4, [r8], #4\n" /* out[outputIndex++] = ... */\ 77065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\ 77165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r6, r6, r9\n" /* phaseFraction + phaseIncrement */\ 77265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " add r7, r7, r6, lsr #30\n" /* inputIndex + phaseFraction>>30 */ 77365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 77465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 77565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ST_ONE_FRAME // frame 1 77665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 77765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " cmp r7, r3\n" // inputIndex - maxInIdx 778eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich " bcc 3b\n" 779eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich "4:\n" 78065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 78165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " bic r6, r6, #0xC0000000\n" // phaseFraction & ... 78265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian // save modified values 78365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 20]\n" // &phaseFraction 78465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r6, [r0]\n" // phaseFraction 78565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 8]\n" // &inputIndex 78665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r7, [r0]\n" // inputIndex 78765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 4]\n" // out 78865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " sub r8, r0\n" // curOut - out 78965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " asr r8, #2\n" // new outputIndex 79065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldr r0, [sp, #" ST_PARAM5 " + 0]\n" // &outputIndex 79165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " str r8, [r0]\n" // save outputIndex 79265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 79365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian " ldmfd sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n" 79465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian ); 79565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian} 79665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 79765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif // ASM_ARM_RESAMP1 79865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 79965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 80065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ---------------------------------------------------------------------------- 80165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian 802c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten} // namespace android 803