xref: /aosp_15_r20/frameworks/av/media/libaudioprocessing/AudioResampler.cpp (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1*ec779b8eSAndroid Build Coastguard Worker /*
2*ec779b8eSAndroid Build Coastguard Worker  * Copyright (C) 2007 The Android Open Source Project
3*ec779b8eSAndroid Build Coastguard Worker  *
4*ec779b8eSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*ec779b8eSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*ec779b8eSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*ec779b8eSAndroid Build Coastguard Worker  *
8*ec779b8eSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*ec779b8eSAndroid Build Coastguard Worker  *
10*ec779b8eSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*ec779b8eSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*ec779b8eSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*ec779b8eSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*ec779b8eSAndroid Build Coastguard Worker  * limitations under the License.
15*ec779b8eSAndroid Build Coastguard Worker  */
16*ec779b8eSAndroid Build Coastguard Worker 
17*ec779b8eSAndroid Build Coastguard Worker #define LOG_TAG "AudioResampler"
18*ec779b8eSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
19*ec779b8eSAndroid Build Coastguard Worker 
20*ec779b8eSAndroid Build Coastguard Worker #include <pthread.h>
21*ec779b8eSAndroid Build Coastguard Worker #include <stdint.h>
22*ec779b8eSAndroid Build Coastguard Worker #include <stdlib.h>
23*ec779b8eSAndroid Build Coastguard Worker #include <sys/types.h>
24*ec779b8eSAndroid Build Coastguard Worker 
25*ec779b8eSAndroid Build Coastguard Worker #include <cutils/properties.h>
26*ec779b8eSAndroid Build Coastguard Worker #include <log/log.h>
27*ec779b8eSAndroid Build Coastguard Worker 
28*ec779b8eSAndroid Build Coastguard Worker #include <audio_utils/primitives.h>
29*ec779b8eSAndroid Build Coastguard Worker #include <media/AudioResampler.h>
30*ec779b8eSAndroid Build Coastguard Worker #include "AudioResamplerSinc.h"
31*ec779b8eSAndroid Build Coastguard Worker #include "AudioResamplerCubic.h"
32*ec779b8eSAndroid Build Coastguard Worker #include "AudioResamplerDyn.h"
33*ec779b8eSAndroid Build Coastguard Worker 
34*ec779b8eSAndroid Build Coastguard Worker #ifdef __arm__
35*ec779b8eSAndroid Build Coastguard Worker     // bug 13102576
36*ec779b8eSAndroid Build Coastguard Worker     //#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
37*ec779b8eSAndroid Build Coastguard Worker #endif
38*ec779b8eSAndroid Build Coastguard Worker 
39*ec779b8eSAndroid Build Coastguard Worker namespace android {
40*ec779b8eSAndroid Build Coastguard Worker 
41*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
42*ec779b8eSAndroid Build Coastguard Worker 
43*ec779b8eSAndroid Build Coastguard Worker class AudioResamplerOrder1 : public AudioResampler {
44*ec779b8eSAndroid Build Coastguard Worker public:
AudioResamplerOrder1(int inChannelCount,int32_t sampleRate)45*ec779b8eSAndroid Build Coastguard Worker     AudioResamplerOrder1(int inChannelCount, int32_t sampleRate) :
46*ec779b8eSAndroid Build Coastguard Worker         AudioResampler(inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) {
47*ec779b8eSAndroid Build Coastguard Worker     }
48*ec779b8eSAndroid Build Coastguard Worker     virtual size_t resample(int32_t* out, size_t outFrameCount,
49*ec779b8eSAndroid Build Coastguard Worker             AudioBufferProvider* provider);
50*ec779b8eSAndroid Build Coastguard Worker private:
51*ec779b8eSAndroid Build Coastguard Worker     // number of bits used in interpolation multiply - 15 bits avoids overflow
52*ec779b8eSAndroid Build Coastguard Worker     static const int kNumInterpBits = 15;
53*ec779b8eSAndroid Build Coastguard Worker 
54*ec779b8eSAndroid Build Coastguard Worker     // bits to shift the phase fraction down to avoid overflow
55*ec779b8eSAndroid Build Coastguard Worker     static const int kPreInterpShift = kNumPhaseBits - kNumInterpBits;
56*ec779b8eSAndroid Build Coastguard Worker 
init()57*ec779b8eSAndroid Build Coastguard Worker     void init() {}
58*ec779b8eSAndroid Build Coastguard Worker     size_t resampleMono16(int32_t* out, size_t outFrameCount,
59*ec779b8eSAndroid Build Coastguard Worker             AudioBufferProvider* provider);
60*ec779b8eSAndroid Build Coastguard Worker     size_t resampleStereo16(int32_t* out, size_t outFrameCount,
61*ec779b8eSAndroid Build Coastguard Worker             AudioBufferProvider* provider);
62*ec779b8eSAndroid Build Coastguard Worker #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
63*ec779b8eSAndroid Build Coastguard Worker     void AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
64*ec779b8eSAndroid Build Coastguard Worker             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
65*ec779b8eSAndroid Build Coastguard Worker             uint32_t &phaseFraction, uint32_t phaseIncrement);
66*ec779b8eSAndroid Build Coastguard Worker     void AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
67*ec779b8eSAndroid Build Coastguard Worker             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
68*ec779b8eSAndroid Build Coastguard Worker             uint32_t &phaseFraction, uint32_t phaseIncrement);
69*ec779b8eSAndroid Build Coastguard Worker #endif  // ASM_ARM_RESAMP1
70*ec779b8eSAndroid Build Coastguard Worker 
Interp(int32_t x0,int32_t x1,uint32_t f)71*ec779b8eSAndroid Build Coastguard Worker     static inline int32_t Interp(int32_t x0, int32_t x1, uint32_t f) {
72*ec779b8eSAndroid Build Coastguard Worker         return x0 + (((x1 - x0) * (int32_t)(f >> kPreInterpShift)) >> kNumInterpBits);
73*ec779b8eSAndroid Build Coastguard Worker     }
Advance(size_t * index,uint32_t * frac,uint32_t inc)74*ec779b8eSAndroid Build Coastguard Worker     static inline void Advance(size_t* index, uint32_t* frac, uint32_t inc) {
75*ec779b8eSAndroid Build Coastguard Worker         *frac += inc;
76*ec779b8eSAndroid Build Coastguard Worker         *index += (size_t)(*frac >> kNumPhaseBits);
77*ec779b8eSAndroid Build Coastguard Worker         *frac &= kPhaseMask;
78*ec779b8eSAndroid Build Coastguard Worker     }
79*ec779b8eSAndroid Build Coastguard Worker     int mX0L;
80*ec779b8eSAndroid Build Coastguard Worker     int mX0R;
81*ec779b8eSAndroid Build Coastguard Worker };
82*ec779b8eSAndroid Build Coastguard Worker 
83*ec779b8eSAndroid Build Coastguard Worker /*static*/
84*ec779b8eSAndroid Build Coastguard Worker const double AudioResampler::kPhaseMultiplier = 1L << AudioResampler::kNumPhaseBits;
85*ec779b8eSAndroid Build Coastguard Worker 
qualityIsSupported(src_quality quality)86*ec779b8eSAndroid Build Coastguard Worker bool AudioResampler::qualityIsSupported(src_quality quality)
87*ec779b8eSAndroid Build Coastguard Worker {
88*ec779b8eSAndroid Build Coastguard Worker     switch (quality) {
89*ec779b8eSAndroid Build Coastguard Worker     case DEFAULT_QUALITY:
90*ec779b8eSAndroid Build Coastguard Worker     case LOW_QUALITY:
91*ec779b8eSAndroid Build Coastguard Worker     case MED_QUALITY:
92*ec779b8eSAndroid Build Coastguard Worker     case HIGH_QUALITY:
93*ec779b8eSAndroid Build Coastguard Worker     case VERY_HIGH_QUALITY:
94*ec779b8eSAndroid Build Coastguard Worker     case DYN_LOW_QUALITY:
95*ec779b8eSAndroid Build Coastguard Worker     case DYN_MED_QUALITY:
96*ec779b8eSAndroid Build Coastguard Worker     case DYN_HIGH_QUALITY:
97*ec779b8eSAndroid Build Coastguard Worker         return true;
98*ec779b8eSAndroid Build Coastguard Worker     default:
99*ec779b8eSAndroid Build Coastguard Worker         return false;
100*ec779b8eSAndroid Build Coastguard Worker     }
101*ec779b8eSAndroid Build Coastguard Worker }
102*ec779b8eSAndroid Build Coastguard Worker 
103*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
104*ec779b8eSAndroid Build Coastguard Worker 
105*ec779b8eSAndroid Build Coastguard Worker static pthread_once_t once_control = PTHREAD_ONCE_INIT;
106*ec779b8eSAndroid Build Coastguard Worker static AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY;
107*ec779b8eSAndroid Build Coastguard Worker 
init_routine()108*ec779b8eSAndroid Build Coastguard Worker void AudioResampler::init_routine()
109*ec779b8eSAndroid Build Coastguard Worker {
110*ec779b8eSAndroid Build Coastguard Worker     char value[PROPERTY_VALUE_MAX];
111*ec779b8eSAndroid Build Coastguard Worker     if (property_get("af.resampler.quality", value, NULL) > 0) {
112*ec779b8eSAndroid Build Coastguard Worker         char *endptr;
113*ec779b8eSAndroid Build Coastguard Worker         unsigned long l = strtoul(value, &endptr, 0);
114*ec779b8eSAndroid Build Coastguard Worker         if (*endptr == '\0') {
115*ec779b8eSAndroid Build Coastguard Worker             defaultQuality = (src_quality) l;
116*ec779b8eSAndroid Build Coastguard Worker             ALOGD("forcing AudioResampler quality to %d", defaultQuality);
117*ec779b8eSAndroid Build Coastguard Worker             if (defaultQuality < DEFAULT_QUALITY || defaultQuality > DYN_HIGH_QUALITY) {
118*ec779b8eSAndroid Build Coastguard Worker                 defaultQuality = DEFAULT_QUALITY;
119*ec779b8eSAndroid Build Coastguard Worker             }
120*ec779b8eSAndroid Build Coastguard Worker         }
121*ec779b8eSAndroid Build Coastguard Worker     }
122*ec779b8eSAndroid Build Coastguard Worker }
123*ec779b8eSAndroid Build Coastguard Worker 
qualityMHz(src_quality quality)124*ec779b8eSAndroid Build Coastguard Worker uint32_t AudioResampler::qualityMHz(src_quality quality)
125*ec779b8eSAndroid Build Coastguard Worker {
126*ec779b8eSAndroid Build Coastguard Worker     switch (quality) {
127*ec779b8eSAndroid Build Coastguard Worker     default:
128*ec779b8eSAndroid Build Coastguard Worker     case DEFAULT_QUALITY:
129*ec779b8eSAndroid Build Coastguard Worker     case LOW_QUALITY:
130*ec779b8eSAndroid Build Coastguard Worker         return 3;
131*ec779b8eSAndroid Build Coastguard Worker     case MED_QUALITY:
132*ec779b8eSAndroid Build Coastguard Worker         return 6;
133*ec779b8eSAndroid Build Coastguard Worker     case HIGH_QUALITY:
134*ec779b8eSAndroid Build Coastguard Worker         return 20;
135*ec779b8eSAndroid Build Coastguard Worker     case VERY_HIGH_QUALITY:
136*ec779b8eSAndroid Build Coastguard Worker         return 34;
137*ec779b8eSAndroid Build Coastguard Worker     case DYN_LOW_QUALITY:
138*ec779b8eSAndroid Build Coastguard Worker         return 4;
139*ec779b8eSAndroid Build Coastguard Worker     case DYN_MED_QUALITY:
140*ec779b8eSAndroid Build Coastguard Worker         return 6;
141*ec779b8eSAndroid Build Coastguard Worker     case DYN_HIGH_QUALITY:
142*ec779b8eSAndroid Build Coastguard Worker         return 12;
143*ec779b8eSAndroid Build Coastguard Worker     }
144*ec779b8eSAndroid Build Coastguard Worker }
145*ec779b8eSAndroid Build Coastguard Worker 
146*ec779b8eSAndroid Build Coastguard Worker static const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable
147*ec779b8eSAndroid Build Coastguard Worker static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
148*ec779b8eSAndroid Build Coastguard Worker static uint32_t currentMHz = 0;
149*ec779b8eSAndroid Build Coastguard Worker 
create(audio_format_t format,int inChannelCount,int32_t sampleRate,src_quality quality)150*ec779b8eSAndroid Build Coastguard Worker AudioResampler* AudioResampler::create(audio_format_t format, int inChannelCount,
151*ec779b8eSAndroid Build Coastguard Worker         int32_t sampleRate, src_quality quality) {
152*ec779b8eSAndroid Build Coastguard Worker 
153*ec779b8eSAndroid Build Coastguard Worker     bool atFinalQuality;
154*ec779b8eSAndroid Build Coastguard Worker     if (quality == DEFAULT_QUALITY) {
155*ec779b8eSAndroid Build Coastguard Worker         // read the resampler default quality property the first time it is needed
156*ec779b8eSAndroid Build Coastguard Worker         int ok = pthread_once(&once_control, init_routine);
157*ec779b8eSAndroid Build Coastguard Worker         if (ok != 0) {
158*ec779b8eSAndroid Build Coastguard Worker             ALOGE("%s pthread_once failed: %d", __func__, ok);
159*ec779b8eSAndroid Build Coastguard Worker         }
160*ec779b8eSAndroid Build Coastguard Worker         quality = defaultQuality;
161*ec779b8eSAndroid Build Coastguard Worker         atFinalQuality = false;
162*ec779b8eSAndroid Build Coastguard Worker     } else {
163*ec779b8eSAndroid Build Coastguard Worker         atFinalQuality = true;
164*ec779b8eSAndroid Build Coastguard Worker     }
165*ec779b8eSAndroid Build Coastguard Worker 
166*ec779b8eSAndroid Build Coastguard Worker     /* if the caller requests DEFAULT_QUALITY and af.resampler.property
167*ec779b8eSAndroid Build Coastguard Worker      * has not been set, the target resampler quality is set to DYN_MED_QUALITY,
168*ec779b8eSAndroid Build Coastguard Worker      * and allowed to "throttle" down to DYN_LOW_QUALITY if necessary
169*ec779b8eSAndroid Build Coastguard Worker      * due to estimated CPU load of having too many active resamplers
170*ec779b8eSAndroid Build Coastguard Worker      * (the code below the if).
171*ec779b8eSAndroid Build Coastguard Worker      */
172*ec779b8eSAndroid Build Coastguard Worker     if (quality == DEFAULT_QUALITY) {
173*ec779b8eSAndroid Build Coastguard Worker         quality = DYN_MED_QUALITY;
174*ec779b8eSAndroid Build Coastguard Worker     }
175*ec779b8eSAndroid Build Coastguard Worker 
176*ec779b8eSAndroid Build Coastguard Worker     // naive implementation of CPU load throttling doesn't account for whether resampler is active
177*ec779b8eSAndroid Build Coastguard Worker     pthread_mutex_lock(&mutex);
178*ec779b8eSAndroid Build Coastguard Worker     for (;;) {
179*ec779b8eSAndroid Build Coastguard Worker         uint32_t deltaMHz = qualityMHz(quality);
180*ec779b8eSAndroid Build Coastguard Worker         uint32_t newMHz = currentMHz + deltaMHz;
181*ec779b8eSAndroid Build Coastguard Worker         if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) {
182*ec779b8eSAndroid Build Coastguard Worker             ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d",
183*ec779b8eSAndroid Build Coastguard Worker                     currentMHz, newMHz, deltaMHz, quality);
184*ec779b8eSAndroid Build Coastguard Worker             currentMHz = newMHz;
185*ec779b8eSAndroid Build Coastguard Worker             break;
186*ec779b8eSAndroid Build Coastguard Worker         }
187*ec779b8eSAndroid Build Coastguard Worker         // not enough CPU available for proposed quality level, so try next lowest level
188*ec779b8eSAndroid Build Coastguard Worker         switch (quality) {
189*ec779b8eSAndroid Build Coastguard Worker         default:
190*ec779b8eSAndroid Build Coastguard Worker         case LOW_QUALITY:
191*ec779b8eSAndroid Build Coastguard Worker             atFinalQuality = true;
192*ec779b8eSAndroid Build Coastguard Worker             break;
193*ec779b8eSAndroid Build Coastguard Worker         case MED_QUALITY:
194*ec779b8eSAndroid Build Coastguard Worker             quality = LOW_QUALITY;
195*ec779b8eSAndroid Build Coastguard Worker             break;
196*ec779b8eSAndroid Build Coastguard Worker         case HIGH_QUALITY:
197*ec779b8eSAndroid Build Coastguard Worker             quality = MED_QUALITY;
198*ec779b8eSAndroid Build Coastguard Worker             break;
199*ec779b8eSAndroid Build Coastguard Worker         case VERY_HIGH_QUALITY:
200*ec779b8eSAndroid Build Coastguard Worker             quality = HIGH_QUALITY;
201*ec779b8eSAndroid Build Coastguard Worker             break;
202*ec779b8eSAndroid Build Coastguard Worker         case DYN_LOW_QUALITY:
203*ec779b8eSAndroid Build Coastguard Worker             atFinalQuality = true;
204*ec779b8eSAndroid Build Coastguard Worker             break;
205*ec779b8eSAndroid Build Coastguard Worker         case DYN_MED_QUALITY:
206*ec779b8eSAndroid Build Coastguard Worker             quality = DYN_LOW_QUALITY;
207*ec779b8eSAndroid Build Coastguard Worker             break;
208*ec779b8eSAndroid Build Coastguard Worker         case DYN_HIGH_QUALITY:
209*ec779b8eSAndroid Build Coastguard Worker             quality = DYN_MED_QUALITY;
210*ec779b8eSAndroid Build Coastguard Worker             break;
211*ec779b8eSAndroid Build Coastguard Worker         }
212*ec779b8eSAndroid Build Coastguard Worker     }
213*ec779b8eSAndroid Build Coastguard Worker     pthread_mutex_unlock(&mutex);
214*ec779b8eSAndroid Build Coastguard Worker 
215*ec779b8eSAndroid Build Coastguard Worker     AudioResampler* resampler;
216*ec779b8eSAndroid Build Coastguard Worker 
217*ec779b8eSAndroid Build Coastguard Worker     switch (quality) {
218*ec779b8eSAndroid Build Coastguard Worker     default:
219*ec779b8eSAndroid Build Coastguard Worker     case LOW_QUALITY:
220*ec779b8eSAndroid Build Coastguard Worker         ALOGV("Create linear Resampler");
221*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT);
222*ec779b8eSAndroid Build Coastguard Worker         resampler = new AudioResamplerOrder1(inChannelCount, sampleRate);
223*ec779b8eSAndroid Build Coastguard Worker         break;
224*ec779b8eSAndroid Build Coastguard Worker     case MED_QUALITY:
225*ec779b8eSAndroid Build Coastguard Worker         ALOGV("Create cubic Resampler");
226*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT);
227*ec779b8eSAndroid Build Coastguard Worker         resampler = new AudioResamplerCubic(inChannelCount, sampleRate);
228*ec779b8eSAndroid Build Coastguard Worker         break;
229*ec779b8eSAndroid Build Coastguard Worker     case HIGH_QUALITY:
230*ec779b8eSAndroid Build Coastguard Worker         ALOGV("Create HIGH_QUALITY sinc Resampler");
231*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT);
232*ec779b8eSAndroid Build Coastguard Worker         resampler = new AudioResamplerSinc(inChannelCount, sampleRate);
233*ec779b8eSAndroid Build Coastguard Worker         break;
234*ec779b8eSAndroid Build Coastguard Worker     case VERY_HIGH_QUALITY:
235*ec779b8eSAndroid Build Coastguard Worker         ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality);
236*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT);
237*ec779b8eSAndroid Build Coastguard Worker         resampler = new AudioResamplerSinc(inChannelCount, sampleRate, quality);
238*ec779b8eSAndroid Build Coastguard Worker         break;
239*ec779b8eSAndroid Build Coastguard Worker     case DYN_LOW_QUALITY:
240*ec779b8eSAndroid Build Coastguard Worker     case DYN_MED_QUALITY:
241*ec779b8eSAndroid Build Coastguard Worker     case DYN_HIGH_QUALITY:
242*ec779b8eSAndroid Build Coastguard Worker         ALOGV("Create dynamic Resampler = %d", quality);
243*ec779b8eSAndroid Build Coastguard Worker         if (format == AUDIO_FORMAT_PCM_FLOAT) {
244*ec779b8eSAndroid Build Coastguard Worker             resampler = new AudioResamplerDyn<float, float, float>(inChannelCount,
245*ec779b8eSAndroid Build Coastguard Worker                     sampleRate, quality);
246*ec779b8eSAndroid Build Coastguard Worker         } else {
247*ec779b8eSAndroid Build Coastguard Worker             LOG_ALWAYS_FATAL_IF(format != AUDIO_FORMAT_PCM_16_BIT);
248*ec779b8eSAndroid Build Coastguard Worker             if (quality == DYN_HIGH_QUALITY) {
249*ec779b8eSAndroid Build Coastguard Worker                 resampler = new AudioResamplerDyn<int32_t, int16_t, int32_t>(inChannelCount,
250*ec779b8eSAndroid Build Coastguard Worker                         sampleRate, quality);
251*ec779b8eSAndroid Build Coastguard Worker             } else {
252*ec779b8eSAndroid Build Coastguard Worker                 resampler = new AudioResamplerDyn<int16_t, int16_t, int32_t>(inChannelCount,
253*ec779b8eSAndroid Build Coastguard Worker                         sampleRate, quality);
254*ec779b8eSAndroid Build Coastguard Worker             }
255*ec779b8eSAndroid Build Coastguard Worker         }
256*ec779b8eSAndroid Build Coastguard Worker         break;
257*ec779b8eSAndroid Build Coastguard Worker     }
258*ec779b8eSAndroid Build Coastguard Worker 
259*ec779b8eSAndroid Build Coastguard Worker     // initialize resampler
260*ec779b8eSAndroid Build Coastguard Worker     resampler->init();
261*ec779b8eSAndroid Build Coastguard Worker     return resampler;
262*ec779b8eSAndroid Build Coastguard Worker }
263*ec779b8eSAndroid Build Coastguard Worker 
AudioResampler(int inChannelCount,int32_t sampleRate,src_quality quality)264*ec779b8eSAndroid Build Coastguard Worker AudioResampler::AudioResampler(int inChannelCount,
265*ec779b8eSAndroid Build Coastguard Worker         int32_t sampleRate, src_quality quality) :
266*ec779b8eSAndroid Build Coastguard Worker         mChannelCount(inChannelCount),
267*ec779b8eSAndroid Build Coastguard Worker         mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
268*ec779b8eSAndroid Build Coastguard Worker         mPhaseFraction(0),
269*ec779b8eSAndroid Build Coastguard Worker         mQuality(quality) {
270*ec779b8eSAndroid Build Coastguard Worker 
271*ec779b8eSAndroid Build Coastguard Worker     const int maxChannels = quality < DYN_LOW_QUALITY ? FCC_2 : FCC_LIMIT;
272*ec779b8eSAndroid Build Coastguard Worker     if (inChannelCount < 1
273*ec779b8eSAndroid Build Coastguard Worker             || inChannelCount > maxChannels) {
274*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d channels",
275*ec779b8eSAndroid Build Coastguard Worker                 quality, inChannelCount);
276*ec779b8eSAndroid Build Coastguard Worker     }
277*ec779b8eSAndroid Build Coastguard Worker     if (sampleRate <= 0) {
278*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate);
279*ec779b8eSAndroid Build Coastguard Worker     }
280*ec779b8eSAndroid Build Coastguard Worker 
281*ec779b8eSAndroid Build Coastguard Worker     // initialize common members
282*ec779b8eSAndroid Build Coastguard Worker     mVolume[0] = mVolume[1] = 0;
283*ec779b8eSAndroid Build Coastguard Worker     mBuffer.frameCount = 0;
284*ec779b8eSAndroid Build Coastguard Worker }
285*ec779b8eSAndroid Build Coastguard Worker 
~AudioResampler()286*ec779b8eSAndroid Build Coastguard Worker AudioResampler::~AudioResampler() {
287*ec779b8eSAndroid Build Coastguard Worker     pthread_mutex_lock(&mutex);
288*ec779b8eSAndroid Build Coastguard Worker     src_quality quality = getQuality();
289*ec779b8eSAndroid Build Coastguard Worker     uint32_t deltaMHz = qualityMHz(quality);
290*ec779b8eSAndroid Build Coastguard Worker     int32_t newMHz = currentMHz - deltaMHz;
291*ec779b8eSAndroid Build Coastguard Worker     ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d",
292*ec779b8eSAndroid Build Coastguard Worker             currentMHz, newMHz, deltaMHz, quality);
293*ec779b8eSAndroid Build Coastguard Worker     LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz);
294*ec779b8eSAndroid Build Coastguard Worker     currentMHz = newMHz;
295*ec779b8eSAndroid Build Coastguard Worker     pthread_mutex_unlock(&mutex);
296*ec779b8eSAndroid Build Coastguard Worker }
297*ec779b8eSAndroid Build Coastguard Worker 
setSampleRate(int32_t inSampleRate)298*ec779b8eSAndroid Build Coastguard Worker void AudioResampler::setSampleRate(int32_t inSampleRate) {
299*ec779b8eSAndroid Build Coastguard Worker     mInSampleRate = inSampleRate;
300*ec779b8eSAndroid Build Coastguard Worker     mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
301*ec779b8eSAndroid Build Coastguard Worker }
302*ec779b8eSAndroid Build Coastguard Worker 
setVolume(float left,float right)303*ec779b8eSAndroid Build Coastguard Worker void AudioResampler::setVolume(float left, float right) {
304*ec779b8eSAndroid Build Coastguard Worker     // TODO: Implement anti-zipper filter
305*ec779b8eSAndroid Build Coastguard Worker     // convert to U4.12 for internal integer use (round down)
306*ec779b8eSAndroid Build Coastguard Worker     // integer volume values are clamped to 0 to UNITY_GAIN.
307*ec779b8eSAndroid Build Coastguard Worker     mVolume[0] = u4_12_from_float(clampFloatVol(left));
308*ec779b8eSAndroid Build Coastguard Worker     mVolume[1] = u4_12_from_float(clampFloatVol(right));
309*ec779b8eSAndroid Build Coastguard Worker }
310*ec779b8eSAndroid Build Coastguard Worker 
reset()311*ec779b8eSAndroid Build Coastguard Worker void AudioResampler::reset() {
312*ec779b8eSAndroid Build Coastguard Worker     mInputIndex = 0;
313*ec779b8eSAndroid Build Coastguard Worker     mPhaseFraction = 0;
314*ec779b8eSAndroid Build Coastguard Worker     mBuffer.frameCount = 0;
315*ec779b8eSAndroid Build Coastguard Worker }
316*ec779b8eSAndroid Build Coastguard Worker 
317*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
318*ec779b8eSAndroid Build Coastguard Worker 
resample(int32_t * out,size_t outFrameCount,AudioBufferProvider * provider)319*ec779b8eSAndroid Build Coastguard Worker size_t AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
320*ec779b8eSAndroid Build Coastguard Worker         AudioBufferProvider* provider) {
321*ec779b8eSAndroid Build Coastguard Worker 
322*ec779b8eSAndroid Build Coastguard Worker     // should never happen, but we overflow if it does
323*ec779b8eSAndroid Build Coastguard Worker     // ALOG_ASSERT(outFrameCount < 32767);
324*ec779b8eSAndroid Build Coastguard Worker 
325*ec779b8eSAndroid Build Coastguard Worker     // select the appropriate resampler
326*ec779b8eSAndroid Build Coastguard Worker     switch (mChannelCount) {
327*ec779b8eSAndroid Build Coastguard Worker     case 1:
328*ec779b8eSAndroid Build Coastguard Worker         return resampleMono16(out, outFrameCount, provider);
329*ec779b8eSAndroid Build Coastguard Worker     case 2:
330*ec779b8eSAndroid Build Coastguard Worker         return resampleStereo16(out, outFrameCount, provider);
331*ec779b8eSAndroid Build Coastguard Worker     default:
332*ec779b8eSAndroid Build Coastguard Worker         LOG_ALWAYS_FATAL("invalid channel count: %d", mChannelCount);
333*ec779b8eSAndroid Build Coastguard Worker         return 0;
334*ec779b8eSAndroid Build Coastguard Worker     }
335*ec779b8eSAndroid Build Coastguard Worker }
336*ec779b8eSAndroid Build Coastguard Worker 
resampleStereo16(int32_t * out,size_t outFrameCount,AudioBufferProvider * provider)337*ec779b8eSAndroid Build Coastguard Worker size_t AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
338*ec779b8eSAndroid Build Coastguard Worker         AudioBufferProvider* provider) {
339*ec779b8eSAndroid Build Coastguard Worker 
340*ec779b8eSAndroid Build Coastguard Worker     int32_t vl = mVolume[0];
341*ec779b8eSAndroid Build Coastguard Worker     int32_t vr = mVolume[1];
342*ec779b8eSAndroid Build Coastguard Worker 
343*ec779b8eSAndroid Build Coastguard Worker     size_t inputIndex = mInputIndex;
344*ec779b8eSAndroid Build Coastguard Worker     uint32_t phaseFraction = mPhaseFraction;
345*ec779b8eSAndroid Build Coastguard Worker     uint32_t phaseIncrement = mPhaseIncrement;
346*ec779b8eSAndroid Build Coastguard Worker     size_t outputIndex = 0;
347*ec779b8eSAndroid Build Coastguard Worker     size_t outputSampleCount = outFrameCount * 2;
348*ec779b8eSAndroid Build Coastguard Worker     size_t inFrameCount = getInFrameCountRequired(outFrameCount);
349*ec779b8eSAndroid Build Coastguard Worker 
350*ec779b8eSAndroid Build Coastguard Worker     // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
351*ec779b8eSAndroid Build Coastguard Worker     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
352*ec779b8eSAndroid Build Coastguard Worker 
353*ec779b8eSAndroid Build Coastguard Worker     while (outputIndex < outputSampleCount) {
354*ec779b8eSAndroid Build Coastguard Worker 
355*ec779b8eSAndroid Build Coastguard Worker         // buffer is empty, fetch a new one
356*ec779b8eSAndroid Build Coastguard Worker         while (mBuffer.frameCount == 0) {
357*ec779b8eSAndroid Build Coastguard Worker             mBuffer.frameCount = inFrameCount;
358*ec779b8eSAndroid Build Coastguard Worker             provider->getNextBuffer(&mBuffer);
359*ec779b8eSAndroid Build Coastguard Worker             if (mBuffer.raw == NULL) {
360*ec779b8eSAndroid Build Coastguard Worker                 goto resampleStereo16_exit;
361*ec779b8eSAndroid Build Coastguard Worker             }
362*ec779b8eSAndroid Build Coastguard Worker 
363*ec779b8eSAndroid Build Coastguard Worker             // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
364*ec779b8eSAndroid Build Coastguard Worker             if (mBuffer.frameCount > inputIndex) break;
365*ec779b8eSAndroid Build Coastguard Worker 
366*ec779b8eSAndroid Build Coastguard Worker             inputIndex -= mBuffer.frameCount;
367*ec779b8eSAndroid Build Coastguard Worker             mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
368*ec779b8eSAndroid Build Coastguard Worker             mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
369*ec779b8eSAndroid Build Coastguard Worker             provider->releaseBuffer(&mBuffer);
370*ec779b8eSAndroid Build Coastguard Worker             // mBuffer.frameCount == 0 now so we reload a new buffer
371*ec779b8eSAndroid Build Coastguard Worker         }
372*ec779b8eSAndroid Build Coastguard Worker 
373*ec779b8eSAndroid Build Coastguard Worker         int16_t *in = mBuffer.i16;
374*ec779b8eSAndroid Build Coastguard Worker 
375*ec779b8eSAndroid Build Coastguard Worker         // handle boundary case
376*ec779b8eSAndroid Build Coastguard Worker         while (inputIndex == 0) {
377*ec779b8eSAndroid Build Coastguard Worker             // ALOGE("boundary case");
378*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
379*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
380*ec779b8eSAndroid Build Coastguard Worker             Advance(&inputIndex, &phaseFraction, phaseIncrement);
381*ec779b8eSAndroid Build Coastguard Worker             if (outputIndex == outputSampleCount) {
382*ec779b8eSAndroid Build Coastguard Worker                 break;
383*ec779b8eSAndroid Build Coastguard Worker             }
384*ec779b8eSAndroid Build Coastguard Worker         }
385*ec779b8eSAndroid Build Coastguard Worker 
386*ec779b8eSAndroid Build Coastguard Worker         // process input samples
387*ec779b8eSAndroid Build Coastguard Worker         // ALOGE("general case");
388*ec779b8eSAndroid Build Coastguard Worker 
389*ec779b8eSAndroid Build Coastguard Worker #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
390*ec779b8eSAndroid Build Coastguard Worker         if (inputIndex + 2 < mBuffer.frameCount) {
391*ec779b8eSAndroid Build Coastguard Worker             int32_t* maxOutPt;
392*ec779b8eSAndroid Build Coastguard Worker             int32_t maxInIdx;
393*ec779b8eSAndroid Build Coastguard Worker 
394*ec779b8eSAndroid Build Coastguard Worker             maxOutPt = out + (outputSampleCount - 2);   // 2 because 2 frames per loop
395*ec779b8eSAndroid Build Coastguard Worker             maxInIdx = mBuffer.frameCount - 2;
396*ec779b8eSAndroid Build Coastguard Worker             AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
397*ec779b8eSAndroid Build Coastguard Worker                     phaseFraction, phaseIncrement);
398*ec779b8eSAndroid Build Coastguard Worker         }
399*ec779b8eSAndroid Build Coastguard Worker #endif  // ASM_ARM_RESAMP1
400*ec779b8eSAndroid Build Coastguard Worker 
401*ec779b8eSAndroid Build Coastguard Worker         while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
402*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
403*ec779b8eSAndroid Build Coastguard Worker                     in[inputIndex*2], phaseFraction);
404*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
405*ec779b8eSAndroid Build Coastguard Worker                     in[inputIndex*2+1], phaseFraction);
406*ec779b8eSAndroid Build Coastguard Worker             Advance(&inputIndex, &phaseFraction, phaseIncrement);
407*ec779b8eSAndroid Build Coastguard Worker         }
408*ec779b8eSAndroid Build Coastguard Worker 
409*ec779b8eSAndroid Build Coastguard Worker         // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
410*ec779b8eSAndroid Build Coastguard Worker 
411*ec779b8eSAndroid Build Coastguard Worker         // if done with buffer, save samples
412*ec779b8eSAndroid Build Coastguard Worker         if (inputIndex >= mBuffer.frameCount) {
413*ec779b8eSAndroid Build Coastguard Worker             inputIndex -= mBuffer.frameCount;
414*ec779b8eSAndroid Build Coastguard Worker 
415*ec779b8eSAndroid Build Coastguard Worker             // ALOGE("buffer done, new input index %d", inputIndex);
416*ec779b8eSAndroid Build Coastguard Worker 
417*ec779b8eSAndroid Build Coastguard Worker             mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
418*ec779b8eSAndroid Build Coastguard Worker             mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
419*ec779b8eSAndroid Build Coastguard Worker             provider->releaseBuffer(&mBuffer);
420*ec779b8eSAndroid Build Coastguard Worker 
421*ec779b8eSAndroid Build Coastguard Worker             // verify that the releaseBuffer resets the buffer frameCount
422*ec779b8eSAndroid Build Coastguard Worker             // ALOG_ASSERT(mBuffer.frameCount == 0);
423*ec779b8eSAndroid Build Coastguard Worker         }
424*ec779b8eSAndroid Build Coastguard Worker     }
425*ec779b8eSAndroid Build Coastguard Worker 
426*ec779b8eSAndroid Build Coastguard Worker     // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
427*ec779b8eSAndroid Build Coastguard Worker 
428*ec779b8eSAndroid Build Coastguard Worker resampleStereo16_exit:
429*ec779b8eSAndroid Build Coastguard Worker     // save state
430*ec779b8eSAndroid Build Coastguard Worker     mInputIndex = inputIndex;
431*ec779b8eSAndroid Build Coastguard Worker     mPhaseFraction = phaseFraction;
432*ec779b8eSAndroid Build Coastguard Worker     return outputIndex / 2 /* channels for stereo */;
433*ec779b8eSAndroid Build Coastguard Worker }
434*ec779b8eSAndroid Build Coastguard Worker 
resampleMono16(int32_t * out,size_t outFrameCount,AudioBufferProvider * provider)435*ec779b8eSAndroid Build Coastguard Worker size_t AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
436*ec779b8eSAndroid Build Coastguard Worker         AudioBufferProvider* provider) {
437*ec779b8eSAndroid Build Coastguard Worker 
438*ec779b8eSAndroid Build Coastguard Worker     int32_t vl = mVolume[0];
439*ec779b8eSAndroid Build Coastguard Worker     int32_t vr = mVolume[1];
440*ec779b8eSAndroid Build Coastguard Worker 
441*ec779b8eSAndroid Build Coastguard Worker     size_t inputIndex = mInputIndex;
442*ec779b8eSAndroid Build Coastguard Worker     uint32_t phaseFraction = mPhaseFraction;
443*ec779b8eSAndroid Build Coastguard Worker     uint32_t phaseIncrement = mPhaseIncrement;
444*ec779b8eSAndroid Build Coastguard Worker     size_t outputIndex = 0;
445*ec779b8eSAndroid Build Coastguard Worker     size_t outputSampleCount = outFrameCount * 2;
446*ec779b8eSAndroid Build Coastguard Worker     size_t inFrameCount = getInFrameCountRequired(outFrameCount);
447*ec779b8eSAndroid Build Coastguard Worker 
448*ec779b8eSAndroid Build Coastguard Worker     // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
449*ec779b8eSAndroid Build Coastguard Worker     //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
450*ec779b8eSAndroid Build Coastguard Worker     while (outputIndex < outputSampleCount) {
451*ec779b8eSAndroid Build Coastguard Worker         // buffer is empty, fetch a new one
452*ec779b8eSAndroid Build Coastguard Worker         while (mBuffer.frameCount == 0) {
453*ec779b8eSAndroid Build Coastguard Worker             mBuffer.frameCount = inFrameCount;
454*ec779b8eSAndroid Build Coastguard Worker             provider->getNextBuffer(&mBuffer);
455*ec779b8eSAndroid Build Coastguard Worker             if (mBuffer.raw == NULL) {
456*ec779b8eSAndroid Build Coastguard Worker                 mInputIndex = inputIndex;
457*ec779b8eSAndroid Build Coastguard Worker                 mPhaseFraction = phaseFraction;
458*ec779b8eSAndroid Build Coastguard Worker                 goto resampleMono16_exit;
459*ec779b8eSAndroid Build Coastguard Worker             }
460*ec779b8eSAndroid Build Coastguard Worker             // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
461*ec779b8eSAndroid Build Coastguard Worker             if (mBuffer.frameCount >  inputIndex) break;
462*ec779b8eSAndroid Build Coastguard Worker 
463*ec779b8eSAndroid Build Coastguard Worker             inputIndex -= mBuffer.frameCount;
464*ec779b8eSAndroid Build Coastguard Worker             mX0L = mBuffer.i16[mBuffer.frameCount-1];
465*ec779b8eSAndroid Build Coastguard Worker             provider->releaseBuffer(&mBuffer);
466*ec779b8eSAndroid Build Coastguard Worker             // mBuffer.frameCount == 0 now so we reload a new buffer
467*ec779b8eSAndroid Build Coastguard Worker         }
468*ec779b8eSAndroid Build Coastguard Worker         int16_t *in = mBuffer.i16;
469*ec779b8eSAndroid Build Coastguard Worker 
470*ec779b8eSAndroid Build Coastguard Worker         // handle boundary case
471*ec779b8eSAndroid Build Coastguard Worker         while (inputIndex == 0) {
472*ec779b8eSAndroid Build Coastguard Worker             // ALOGE("boundary case");
473*ec779b8eSAndroid Build Coastguard Worker             int32_t sample = Interp(mX0L, in[0], phaseFraction);
474*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vl * sample;
475*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vr * sample;
476*ec779b8eSAndroid Build Coastguard Worker             Advance(&inputIndex, &phaseFraction, phaseIncrement);
477*ec779b8eSAndroid Build Coastguard Worker             if (outputIndex == outputSampleCount) {
478*ec779b8eSAndroid Build Coastguard Worker                 break;
479*ec779b8eSAndroid Build Coastguard Worker             }
480*ec779b8eSAndroid Build Coastguard Worker         }
481*ec779b8eSAndroid Build Coastguard Worker 
482*ec779b8eSAndroid Build Coastguard Worker         // process input samples
483*ec779b8eSAndroid Build Coastguard Worker         // ALOGE("general case");
484*ec779b8eSAndroid Build Coastguard Worker 
485*ec779b8eSAndroid Build Coastguard Worker #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
486*ec779b8eSAndroid Build Coastguard Worker         if (inputIndex + 2 < mBuffer.frameCount) {
487*ec779b8eSAndroid Build Coastguard Worker             int32_t* maxOutPt;
488*ec779b8eSAndroid Build Coastguard Worker             int32_t maxInIdx;
489*ec779b8eSAndroid Build Coastguard Worker 
490*ec779b8eSAndroid Build Coastguard Worker             maxOutPt = out + (outputSampleCount - 2);
491*ec779b8eSAndroid Build Coastguard Worker             maxInIdx = (int32_t)mBuffer.frameCount - 2;
492*ec779b8eSAndroid Build Coastguard Worker                 AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
493*ec779b8eSAndroid Build Coastguard Worker                         phaseFraction, phaseIncrement);
494*ec779b8eSAndroid Build Coastguard Worker         }
495*ec779b8eSAndroid Build Coastguard Worker #endif  // ASM_ARM_RESAMP1
496*ec779b8eSAndroid Build Coastguard Worker 
497*ec779b8eSAndroid Build Coastguard Worker         while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
498*ec779b8eSAndroid Build Coastguard Worker             int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
499*ec779b8eSAndroid Build Coastguard Worker                     phaseFraction);
500*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vl * sample;
501*ec779b8eSAndroid Build Coastguard Worker             out[outputIndex++] += vr * sample;
502*ec779b8eSAndroid Build Coastguard Worker             Advance(&inputIndex, &phaseFraction, phaseIncrement);
503*ec779b8eSAndroid Build Coastguard Worker         }
504*ec779b8eSAndroid Build Coastguard Worker 
505*ec779b8eSAndroid Build Coastguard Worker 
506*ec779b8eSAndroid Build Coastguard Worker         // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
507*ec779b8eSAndroid Build Coastguard Worker 
508*ec779b8eSAndroid Build Coastguard Worker         // if done with buffer, save samples
509*ec779b8eSAndroid Build Coastguard Worker         if (inputIndex >= mBuffer.frameCount) {
510*ec779b8eSAndroid Build Coastguard Worker             inputIndex -= mBuffer.frameCount;
511*ec779b8eSAndroid Build Coastguard Worker 
512*ec779b8eSAndroid Build Coastguard Worker             // ALOGE("buffer done, new input index %d", inputIndex);
513*ec779b8eSAndroid Build Coastguard Worker 
514*ec779b8eSAndroid Build Coastguard Worker             mX0L = mBuffer.i16[mBuffer.frameCount-1];
515*ec779b8eSAndroid Build Coastguard Worker             provider->releaseBuffer(&mBuffer);
516*ec779b8eSAndroid Build Coastguard Worker 
517*ec779b8eSAndroid Build Coastguard Worker             // verify that the releaseBuffer resets the buffer frameCount
518*ec779b8eSAndroid Build Coastguard Worker             // ALOG_ASSERT(mBuffer.frameCount == 0);
519*ec779b8eSAndroid Build Coastguard Worker         }
520*ec779b8eSAndroid Build Coastguard Worker     }
521*ec779b8eSAndroid Build Coastguard Worker 
522*ec779b8eSAndroid Build Coastguard Worker     // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
523*ec779b8eSAndroid Build Coastguard Worker 
524*ec779b8eSAndroid Build Coastguard Worker resampleMono16_exit:
525*ec779b8eSAndroid Build Coastguard Worker     // save state
526*ec779b8eSAndroid Build Coastguard Worker     mInputIndex = inputIndex;
527*ec779b8eSAndroid Build Coastguard Worker     mPhaseFraction = phaseFraction;
528*ec779b8eSAndroid Build Coastguard Worker     return outputIndex;
529*ec779b8eSAndroid Build Coastguard Worker }
530*ec779b8eSAndroid Build Coastguard Worker 
531*ec779b8eSAndroid Build Coastguard Worker #ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
532*ec779b8eSAndroid Build Coastguard Worker 
533*ec779b8eSAndroid Build Coastguard Worker /*******************************************************************
534*ec779b8eSAndroid Build Coastguard Worker *
535*ec779b8eSAndroid Build Coastguard Worker *   AsmMono16Loop
536*ec779b8eSAndroid Build Coastguard Worker *   asm optimized monotonic loop version; one loop is 2 frames
537*ec779b8eSAndroid Build Coastguard Worker *   Input:
538*ec779b8eSAndroid Build Coastguard Worker *       in : pointer on input samples
539*ec779b8eSAndroid Build Coastguard Worker *       maxOutPt : pointer on first not filled
540*ec779b8eSAndroid Build Coastguard Worker *       maxInIdx : index on first not used
541*ec779b8eSAndroid Build Coastguard Worker *       outputIndex : pointer on current output index
542*ec779b8eSAndroid Build Coastguard Worker *       out : pointer on output buffer
543*ec779b8eSAndroid Build Coastguard Worker *       inputIndex : pointer on current input index
544*ec779b8eSAndroid Build Coastguard Worker *       vl, vr : left and right gain
545*ec779b8eSAndroid Build Coastguard Worker *       phaseFraction : pointer on current phase fraction
546*ec779b8eSAndroid Build Coastguard Worker *       phaseIncrement
547*ec779b8eSAndroid Build Coastguard Worker *   Ouput:
548*ec779b8eSAndroid Build Coastguard Worker *       outputIndex :
549*ec779b8eSAndroid Build Coastguard Worker *       out : updated buffer
550*ec779b8eSAndroid Build Coastguard Worker *       inputIndex : index of next to use
551*ec779b8eSAndroid Build Coastguard Worker *       phaseFraction : phase fraction for next interpolation
552*ec779b8eSAndroid Build Coastguard Worker *
553*ec779b8eSAndroid Build Coastguard Worker *******************************************************************/
554*ec779b8eSAndroid Build Coastguard Worker __attribute__((noinline))
AsmMono16Loop(int16_t * in,int32_t * maxOutPt,int32_t maxInIdx,size_t & outputIndex,int32_t * out,size_t & inputIndex,int32_t vl,int32_t vr,uint32_t & phaseFraction,uint32_t phaseIncrement)555*ec779b8eSAndroid Build Coastguard Worker void AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
556*ec779b8eSAndroid Build Coastguard Worker             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
557*ec779b8eSAndroid Build Coastguard Worker             uint32_t &phaseFraction, uint32_t phaseIncrement)
558*ec779b8eSAndroid Build Coastguard Worker {
559*ec779b8eSAndroid Build Coastguard Worker     (void)maxOutPt; // remove unused parameter warnings
560*ec779b8eSAndroid Build Coastguard Worker     (void)maxInIdx;
561*ec779b8eSAndroid Build Coastguard Worker     (void)outputIndex;
562*ec779b8eSAndroid Build Coastguard Worker     (void)out;
563*ec779b8eSAndroid Build Coastguard Worker     (void)inputIndex;
564*ec779b8eSAndroid Build Coastguard Worker     (void)vl;
565*ec779b8eSAndroid Build Coastguard Worker     (void)vr;
566*ec779b8eSAndroid Build Coastguard Worker     (void)phaseFraction;
567*ec779b8eSAndroid Build Coastguard Worker     (void)phaseIncrement;
568*ec779b8eSAndroid Build Coastguard Worker     (void)in;
569*ec779b8eSAndroid Build Coastguard Worker #define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
570*ec779b8eSAndroid Build Coastguard Worker 
571*ec779b8eSAndroid Build Coastguard Worker     asm(
572*ec779b8eSAndroid Build Coastguard Worker         "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
573*ec779b8eSAndroid Build Coastguard Worker         // get parameters
574*ec779b8eSAndroid Build Coastguard Worker         "   ldr r6, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
575*ec779b8eSAndroid Build Coastguard Worker         "   ldr r6, [r6]\n"                         // phaseFraction
576*ec779b8eSAndroid Build Coastguard Worker         "   ldr r7, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
577*ec779b8eSAndroid Build Coastguard Worker         "   ldr r7, [r7]\n"                         // inputIndex
578*ec779b8eSAndroid Build Coastguard Worker         "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
579*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
580*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [r0]\n"                         // outputIndex
581*ec779b8eSAndroid Build Coastguard Worker         "   add r8, r8, r0, asl #2\n"               // curOut
582*ec779b8eSAndroid Build Coastguard Worker         "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
583*ec779b8eSAndroid Build Coastguard Worker         "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
584*ec779b8eSAndroid Build Coastguard Worker         "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
585*ec779b8eSAndroid Build Coastguard Worker 
586*ec779b8eSAndroid Build Coastguard Worker         // r0 pin, x0, Samp
587*ec779b8eSAndroid Build Coastguard Worker 
588*ec779b8eSAndroid Build Coastguard Worker         // r1 in
589*ec779b8eSAndroid Build Coastguard Worker         // r2 maxOutPt
590*ec779b8eSAndroid Build Coastguard Worker         // r3 maxInIdx
591*ec779b8eSAndroid Build Coastguard Worker 
592*ec779b8eSAndroid Build Coastguard Worker         // r4 x1, i1, i3, Out1
593*ec779b8eSAndroid Build Coastguard Worker         // r5 out0
594*ec779b8eSAndroid Build Coastguard Worker 
595*ec779b8eSAndroid Build Coastguard Worker         // r6 frac
596*ec779b8eSAndroid Build Coastguard Worker         // r7 inputIndex
597*ec779b8eSAndroid Build Coastguard Worker         // r8 curOut
598*ec779b8eSAndroid Build Coastguard Worker 
599*ec779b8eSAndroid Build Coastguard Worker         // r9 inc
600*ec779b8eSAndroid Build Coastguard Worker         // r10 vl
601*ec779b8eSAndroid Build Coastguard Worker         // r11 vr
602*ec779b8eSAndroid Build Coastguard Worker 
603*ec779b8eSAndroid Build Coastguard Worker         // r12
604*ec779b8eSAndroid Build Coastguard Worker         // r13 sp
605*ec779b8eSAndroid Build Coastguard Worker         // r14
606*ec779b8eSAndroid Build Coastguard Worker 
607*ec779b8eSAndroid Build Coastguard Worker         // the following loop works on 2 frames
608*ec779b8eSAndroid Build Coastguard Worker 
609*ec779b8eSAndroid Build Coastguard Worker         "1:\n"
610*ec779b8eSAndroid Build Coastguard Worker         "   cmp r8, r2\n"                   // curOut - maxCurOut
611*ec779b8eSAndroid Build Coastguard Worker         "   bcs 2f\n"
612*ec779b8eSAndroid Build Coastguard Worker 
613*ec779b8eSAndroid Build Coastguard Worker #define MO_ONE_FRAME \
614*ec779b8eSAndroid Build Coastguard Worker     "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
615*ec779b8eSAndroid Build Coastguard Worker     "   ldrsh r4, [r0]\n"               /* in[inputIndex] */\
616*ec779b8eSAndroid Build Coastguard Worker     "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
617*ec779b8eSAndroid Build Coastguard Worker     "   ldrsh r0, [r0, #-2]\n"          /* in[inputIndex-1] */\
618*ec779b8eSAndroid Build Coastguard Worker     "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
619*ec779b8eSAndroid Build Coastguard Worker     "   sub r4, r4, r0\n"               /* in[inputIndex] - in[inputIndex-1] */\
620*ec779b8eSAndroid Build Coastguard Worker     "   mov r4, r4, lsl #2\n"           /* <<2 */\
621*ec779b8eSAndroid Build Coastguard Worker     "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
622*ec779b8eSAndroid Build Coastguard Worker     "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
623*ec779b8eSAndroid Build Coastguard Worker     "   add r0, r0, r4\n"               /* x0 - (..) */\
624*ec779b8eSAndroid Build Coastguard Worker     "   mla r5, r0, r10, r5\n"          /* vl*interp + out[] */\
625*ec779b8eSAndroid Build Coastguard Worker     "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
626*ec779b8eSAndroid Build Coastguard Worker     "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
627*ec779b8eSAndroid Build Coastguard Worker     "   mla r4, r0, r11, r4\n"          /* vr*interp + out[] */\
628*ec779b8eSAndroid Build Coastguard Worker     "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */\
629*ec779b8eSAndroid Build Coastguard Worker     "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */
630*ec779b8eSAndroid Build Coastguard Worker 
631*ec779b8eSAndroid Build Coastguard Worker         MO_ONE_FRAME    // frame 1
632*ec779b8eSAndroid Build Coastguard Worker         MO_ONE_FRAME    // frame 2
633*ec779b8eSAndroid Build Coastguard Worker 
634*ec779b8eSAndroid Build Coastguard Worker         "   cmp r7, r3\n"                   // inputIndex - maxInIdx
635*ec779b8eSAndroid Build Coastguard Worker         "   bcc 1b\n"
636*ec779b8eSAndroid Build Coastguard Worker         "2:\n"
637*ec779b8eSAndroid Build Coastguard Worker 
638*ec779b8eSAndroid Build Coastguard Worker         "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
639*ec779b8eSAndroid Build Coastguard Worker         // save modified values
640*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
641*ec779b8eSAndroid Build Coastguard Worker         "   str r6, [r0]\n"                         // phaseFraction
642*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
643*ec779b8eSAndroid Build Coastguard Worker         "   str r7, [r0]\n"                         // inputIndex
644*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" MO_PARAM5 " + 4]\n"     // out
645*ec779b8eSAndroid Build Coastguard Worker         "   sub r8, r0\n"                           // curOut - out
646*ec779b8eSAndroid Build Coastguard Worker         "   asr r8, #2\n"                           // new outputIndex
647*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
648*ec779b8eSAndroid Build Coastguard Worker         "   str r8, [r0]\n"                         // save outputIndex
649*ec779b8eSAndroid Build Coastguard Worker 
650*ec779b8eSAndroid Build Coastguard Worker         "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
651*ec779b8eSAndroid Build Coastguard Worker     );
652*ec779b8eSAndroid Build Coastguard Worker }
653*ec779b8eSAndroid Build Coastguard Worker 
654*ec779b8eSAndroid Build Coastguard Worker /*******************************************************************
655*ec779b8eSAndroid Build Coastguard Worker *
656*ec779b8eSAndroid Build Coastguard Worker *   AsmStereo16Loop
657*ec779b8eSAndroid Build Coastguard Worker *   asm optimized stereo loop version; one loop is 2 frames
658*ec779b8eSAndroid Build Coastguard Worker *   Input:
659*ec779b8eSAndroid Build Coastguard Worker *       in : pointer on input samples
660*ec779b8eSAndroid Build Coastguard Worker *       maxOutPt : pointer on first not filled
661*ec779b8eSAndroid Build Coastguard Worker *       maxInIdx : index on first not used
662*ec779b8eSAndroid Build Coastguard Worker *       outputIndex : pointer on current output index
663*ec779b8eSAndroid Build Coastguard Worker *       out : pointer on output buffer
664*ec779b8eSAndroid Build Coastguard Worker *       inputIndex : pointer on current input index
665*ec779b8eSAndroid Build Coastguard Worker *       vl, vr : left and right gain
666*ec779b8eSAndroid Build Coastguard Worker *       phaseFraction : pointer on current phase fraction
667*ec779b8eSAndroid Build Coastguard Worker *       phaseIncrement
668*ec779b8eSAndroid Build Coastguard Worker *   Ouput:
669*ec779b8eSAndroid Build Coastguard Worker *       outputIndex :
670*ec779b8eSAndroid Build Coastguard Worker *       out : updated buffer
671*ec779b8eSAndroid Build Coastguard Worker *       inputIndex : index of next to use
672*ec779b8eSAndroid Build Coastguard Worker *       phaseFraction : phase fraction for next interpolation
673*ec779b8eSAndroid Build Coastguard Worker *
674*ec779b8eSAndroid Build Coastguard Worker *******************************************************************/
675*ec779b8eSAndroid Build Coastguard Worker __attribute__((noinline))
AsmStereo16Loop(int16_t * in,int32_t * maxOutPt,int32_t maxInIdx,size_t & outputIndex,int32_t * out,size_t & inputIndex,int32_t vl,int32_t vr,uint32_t & phaseFraction,uint32_t phaseIncrement)676*ec779b8eSAndroid Build Coastguard Worker void AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
677*ec779b8eSAndroid Build Coastguard Worker             size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
678*ec779b8eSAndroid Build Coastguard Worker             uint32_t &phaseFraction, uint32_t phaseIncrement)
679*ec779b8eSAndroid Build Coastguard Worker {
680*ec779b8eSAndroid Build Coastguard Worker     (void)maxOutPt; // remove unused parameter warnings
681*ec779b8eSAndroid Build Coastguard Worker     (void)maxInIdx;
682*ec779b8eSAndroid Build Coastguard Worker     (void)outputIndex;
683*ec779b8eSAndroid Build Coastguard Worker     (void)out;
684*ec779b8eSAndroid Build Coastguard Worker     (void)inputIndex;
685*ec779b8eSAndroid Build Coastguard Worker     (void)vl;
686*ec779b8eSAndroid Build Coastguard Worker     (void)vr;
687*ec779b8eSAndroid Build Coastguard Worker     (void)phaseFraction;
688*ec779b8eSAndroid Build Coastguard Worker     (void)phaseIncrement;
689*ec779b8eSAndroid Build Coastguard Worker     (void)in;
690*ec779b8eSAndroid Build Coastguard Worker #define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
691*ec779b8eSAndroid Build Coastguard Worker     asm(
692*ec779b8eSAndroid Build Coastguard Worker         "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
693*ec779b8eSAndroid Build Coastguard Worker         // get parameters
694*ec779b8eSAndroid Build Coastguard Worker         "   ldr r6, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
695*ec779b8eSAndroid Build Coastguard Worker         "   ldr r6, [r6]\n"                         // phaseFraction
696*ec779b8eSAndroid Build Coastguard Worker         "   ldr r7, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
697*ec779b8eSAndroid Build Coastguard Worker         "   ldr r7, [r7]\n"                         // inputIndex
698*ec779b8eSAndroid Build Coastguard Worker         "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
699*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
700*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [r0]\n"                         // outputIndex
701*ec779b8eSAndroid Build Coastguard Worker         "   add r8, r8, r0, asl #2\n"               // curOut
702*ec779b8eSAndroid Build Coastguard Worker         "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
703*ec779b8eSAndroid Build Coastguard Worker         "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
704*ec779b8eSAndroid Build Coastguard Worker         "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
705*ec779b8eSAndroid Build Coastguard Worker 
706*ec779b8eSAndroid Build Coastguard Worker         // r0 pin, x0, Samp
707*ec779b8eSAndroid Build Coastguard Worker 
708*ec779b8eSAndroid Build Coastguard Worker         // r1 in
709*ec779b8eSAndroid Build Coastguard Worker         // r2 maxOutPt
710*ec779b8eSAndroid Build Coastguard Worker         // r3 maxInIdx
711*ec779b8eSAndroid Build Coastguard Worker 
712*ec779b8eSAndroid Build Coastguard Worker         // r4 x1, i1, i3, out1
713*ec779b8eSAndroid Build Coastguard Worker         // r5 out0
714*ec779b8eSAndroid Build Coastguard Worker 
715*ec779b8eSAndroid Build Coastguard Worker         // r6 frac
716*ec779b8eSAndroid Build Coastguard Worker         // r7 inputIndex
717*ec779b8eSAndroid Build Coastguard Worker         // r8 curOut
718*ec779b8eSAndroid Build Coastguard Worker 
719*ec779b8eSAndroid Build Coastguard Worker         // r9 inc
720*ec779b8eSAndroid Build Coastguard Worker         // r10 vl
721*ec779b8eSAndroid Build Coastguard Worker         // r11 vr
722*ec779b8eSAndroid Build Coastguard Worker 
723*ec779b8eSAndroid Build Coastguard Worker         // r12 temporary
724*ec779b8eSAndroid Build Coastguard Worker         // r13 sp
725*ec779b8eSAndroid Build Coastguard Worker         // r14
726*ec779b8eSAndroid Build Coastguard Worker 
727*ec779b8eSAndroid Build Coastguard Worker         "3:\n"
728*ec779b8eSAndroid Build Coastguard Worker         "   cmp r8, r2\n"                   // curOut - maxCurOut
729*ec779b8eSAndroid Build Coastguard Worker         "   bcs 4f\n"
730*ec779b8eSAndroid Build Coastguard Worker 
731*ec779b8eSAndroid Build Coastguard Worker #define ST_ONE_FRAME \
732*ec779b8eSAndroid Build Coastguard Worker     "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
733*ec779b8eSAndroid Build Coastguard Worker \
734*ec779b8eSAndroid Build Coastguard Worker     "   add r0, r1, r7, asl #2\n"       /* in + 2*inputIndex */\
735*ec779b8eSAndroid Build Coastguard Worker \
736*ec779b8eSAndroid Build Coastguard Worker     "   ldrsh r4, [r0]\n"               /* in[2*inputIndex] */\
737*ec779b8eSAndroid Build Coastguard Worker     "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
738*ec779b8eSAndroid Build Coastguard Worker     "   ldrsh r12, [r0, #-4]\n"         /* in[2*inputIndex-2] */\
739*ec779b8eSAndroid Build Coastguard Worker     "   sub r4, r4, r12\n"              /* in[2*InputIndex] - in[2*InputIndex-2] */\
740*ec779b8eSAndroid Build Coastguard Worker     "   mov r4, r4, lsl #2\n"           /* <<2 */\
741*ec779b8eSAndroid Build Coastguard Worker     "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
742*ec779b8eSAndroid Build Coastguard Worker     "   add r12, r12, r4\n"             /* x0 - (..) */\
743*ec779b8eSAndroid Build Coastguard Worker     "   mla r5, r12, r10, r5\n"         /* vl*interp + out[] */\
744*ec779b8eSAndroid Build Coastguard Worker     "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
745*ec779b8eSAndroid Build Coastguard Worker     "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
746*ec779b8eSAndroid Build Coastguard Worker \
747*ec779b8eSAndroid Build Coastguard Worker     "   ldrsh r12, [r0, #+2]\n"         /* in[2*inputIndex+1] */\
748*ec779b8eSAndroid Build Coastguard Worker     "   ldrsh r0, [r0, #-2]\n"          /* in[2*inputIndex-1] */\
749*ec779b8eSAndroid Build Coastguard Worker     "   sub r12, r12, r0\n"             /* in[2*InputIndex] - in[2*InputIndex-2] */\
750*ec779b8eSAndroid Build Coastguard Worker     "   mov r12, r12, lsl #2\n"         /* <<2 */\
751*ec779b8eSAndroid Build Coastguard Worker     "   smulwt r12, r12, r6\n"          /* (x1-x0)*.. */\
752*ec779b8eSAndroid Build Coastguard Worker     "   add r12, r0, r12\n"             /* x0 - (..) */\
753*ec779b8eSAndroid Build Coastguard Worker     "   mla r4, r12, r11, r4\n"         /* vr*interp + out[] */\
754*ec779b8eSAndroid Build Coastguard Worker     "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */\
755*ec779b8eSAndroid Build Coastguard Worker \
756*ec779b8eSAndroid Build Coastguard Worker     "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
757*ec779b8eSAndroid Build Coastguard Worker     "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */
758*ec779b8eSAndroid Build Coastguard Worker 
759*ec779b8eSAndroid Build Coastguard Worker     ST_ONE_FRAME    // frame 1
760*ec779b8eSAndroid Build Coastguard Worker     ST_ONE_FRAME    // frame 1
761*ec779b8eSAndroid Build Coastguard Worker 
762*ec779b8eSAndroid Build Coastguard Worker         "   cmp r7, r3\n"                       // inputIndex - maxInIdx
763*ec779b8eSAndroid Build Coastguard Worker         "   bcc 3b\n"
764*ec779b8eSAndroid Build Coastguard Worker         "4:\n"
765*ec779b8eSAndroid Build Coastguard Worker 
766*ec779b8eSAndroid Build Coastguard Worker         "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
767*ec779b8eSAndroid Build Coastguard Worker         // save modified values
768*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
769*ec779b8eSAndroid Build Coastguard Worker         "   str r6, [r0]\n"                         // phaseFraction
770*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
771*ec779b8eSAndroid Build Coastguard Worker         "   str r7, [r0]\n"                         // inputIndex
772*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" ST_PARAM5 " + 4]\n"     // out
773*ec779b8eSAndroid Build Coastguard Worker         "   sub r8, r0\n"                           // curOut - out
774*ec779b8eSAndroid Build Coastguard Worker         "   asr r8, #2\n"                           // new outputIndex
775*ec779b8eSAndroid Build Coastguard Worker         "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
776*ec779b8eSAndroid Build Coastguard Worker         "   str r8, [r0]\n"                         // save outputIndex
777*ec779b8eSAndroid Build Coastguard Worker 
778*ec779b8eSAndroid Build Coastguard Worker         "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
779*ec779b8eSAndroid Build Coastguard Worker     );
780*ec779b8eSAndroid Build Coastguard Worker }
781*ec779b8eSAndroid Build Coastguard Worker 
782*ec779b8eSAndroid Build Coastguard Worker #endif  // ASM_ARM_RESAMP1
783*ec779b8eSAndroid Build Coastguard Worker 
784*ec779b8eSAndroid Build Coastguard Worker 
785*ec779b8eSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
786*ec779b8eSAndroid Build Coastguard Worker 
787*ec779b8eSAndroid Build Coastguard Worker } // namespace android
788