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