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