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