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>
2565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResampler.h"
2665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerSinc.h"
2765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#include "AudioResamplerCubic.h"
2865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
290c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#ifdef __arm__
300c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#include <machine/cpu-features.h>
310c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif
320c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang
3365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopiannamespace android {
3465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
350c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
36c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten    #define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
370c0a1c0c37dbd2646a732da706d6777283c83e44Jim Huang#endif // __ARM_HAVE_HALFWORD_MULTIPLY
3865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
3965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
4065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianclass AudioResamplerOrder1 : public AudioResampler {
4165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianpublic:
4265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    AudioResamplerOrder1(int bitDepth, int inChannelCount, int32_t sampleRate) :
43ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        AudioResampler(bitDepth, inChannelCount, sampleRate, LOW_QUALITY), mX0L(0), mX0R(0) {
4465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
4565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    virtual void 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() {}
5565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    void resampleMono16(int32_t* out, size_t outFrameCount,
5665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            AudioBufferProvider* provider);
5765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    void 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
80ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenbool AudioResampler::qualityIsSupported(src_quality quality)
81ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{
82ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    switch (quality) {
83ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case DEFAULT_QUALITY:
84ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case LOW_QUALITY:
85ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten#if 0   // these have not been qualified recently so are not supported unless explicitly requested
86ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case MED_QUALITY:
87ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case HIGH_QUALITY:
88ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten#endif
89ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case VERY_HIGH_QUALITY:
90ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return true;
91ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    default:
92ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return false;
93ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    }
94ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten}
95ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
9665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
9765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
98ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_once_t once_control = PTHREAD_ONCE_INIT;
99ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic AudioResampler::src_quality defaultQuality = AudioResampler::DEFAULT_QUALITY;
10065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
101ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenvoid AudioResampler::init_routine()
102ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{
10365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    char value[PROPERTY_VALUE_MAX];
104ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    if (property_get("af.resampler.quality", value, NULL) > 0) {
105ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        char *endptr;
106ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        unsigned long l = strtoul(value, &endptr, 0);
107ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        if (*endptr == '\0') {
108ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            defaultQuality = (src_quality) l;
109ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            ALOGD("forcing AudioResampler quality to %d", defaultQuality);
110ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            if (defaultQuality < DEFAULT_QUALITY || defaultQuality > VERY_HIGH_QUALITY) {
111ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten                defaultQuality = DEFAULT_QUALITY;
112ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            }
113ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        }
114ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    }
115ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten}
116ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
117ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenuint32_t AudioResampler::qualityMHz(src_quality quality)
118ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten{
119ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    switch (quality) {
120ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    default:
121ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case DEFAULT_QUALITY:
122ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case LOW_QUALITY:
123ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return 3;
124ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case MED_QUALITY:
125ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return 6;
126ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case HIGH_QUALITY:
127ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return 20;
128ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case VERY_HIGH_QUALITY:
129ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        return 34;
13065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
131ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten}
132ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
133c4640c9eef850bb1c754bd6b477f1cc8350c6081Glenn Kastenstatic const uint32_t maxMHz = 130; // an arbitrary number that permits 3 VHQ, should be tunable
134ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
135ac6020508acedd316391dee42329040bf45f8d90Glenn Kastenstatic uint32_t currentMHz = 0;
13665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
137ac6020508acedd316391dee42329040bf45f8d90Glenn KastenAudioResampler* AudioResampler::create(int bitDepth, int inChannelCount,
138ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        int32_t sampleRate, src_quality quality) {
139ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
140ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    bool atFinalQuality;
141ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    if (quality == DEFAULT_QUALITY) {
142ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        // read the resampler default quality property the first time it is needed
143ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        int ok = pthread_once(&once_control, init_routine);
144ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        if (ok != 0) {
145ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            ALOGE("%s pthread_once failed: %d", __func__, ok);
146ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        }
147ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        quality = defaultQuality;
148ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        atFinalQuality = false;
149ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    } else {
150ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        atFinalQuality = true;
151ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    }
152ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
153ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    // naive implementation of CPU load throttling doesn't account for whether resampler is active
154ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    pthread_mutex_lock(&mutex);
155ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    for (;;) {
156ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        uint32_t deltaMHz = qualityMHz(quality);
157ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        uint32_t newMHz = currentMHz + deltaMHz;
158ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        if ((qualityIsSupported(quality) && newMHz <= maxMHz) || atFinalQuality) {
159ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            ALOGV("resampler load %u -> %u MHz due to delta +%u MHz from quality %d",
160ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten                    currentMHz, newMHz, deltaMHz, quality);
161ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            currentMHz = newMHz;
162ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            break;
163ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        }
164ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        // not enough CPU available for proposed quality level, so try next lowest level
165ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        switch (quality) {
166ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        default:
167ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        case DEFAULT_QUALITY:
168ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        case LOW_QUALITY:
169ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            atFinalQuality = true;
170ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            break;
171ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        case MED_QUALITY:
172ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            quality = LOW_QUALITY;
173ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            break;
174ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        case HIGH_QUALITY:
175ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            quality = MED_QUALITY;
176ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            break;
177ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        case VERY_HIGH_QUALITY:
178ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            quality = HIGH_QUALITY;
179ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            break;
180ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        }
181ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    }
182ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    pthread_mutex_unlock(&mutex);
183ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten
184ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    AudioResampler* resampler;
18565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
18665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    switch (quality) {
18765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    default:
188ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    case DEFAULT_QUALITY:
18965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    case LOW_QUALITY:
1903856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Create linear Resampler");
19165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        resampler = new AudioResamplerOrder1(bitDepth, inChannelCount, sampleRate);
19265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        break;
193ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten#if 0   // disabled because it has not been qualified recently, if requested will use default:
19465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    case MED_QUALITY:
1953856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        ALOGV("Create cubic Resampler");
19665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        resampler = new AudioResamplerCubic(bitDepth, inChannelCount, sampleRate);
19765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        break;
19876b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani#endif
19965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    case HIGH_QUALITY:
20076b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani        ALOGV("Create HIGH_QUALITY sinc Resampler");
20165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate);
202ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        break;
20376b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani    case VERY_HIGH_QUALITY:
204ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        ALOGV("Create VERY_HIGH_QUALITY sinc Resampler = %d", quality);
20576b111685010e1fea7c0a865c038aee35507fde4SathishKumar Mani        resampler = new AudioResamplerSinc(bitDepth, inChannelCount, sampleRate, quality);
20665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        break;
20765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
20865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
20965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // initialize resampler
21065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    resampler->init();
21165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    return resampler;
21265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
21365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
21465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianAudioResampler::AudioResampler(int bitDepth, int inChannelCount,
215ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        int32_t sampleRate, src_quality quality) :
21665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mBitDepth(bitDepth), mChannelCount(inChannelCount),
21765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mSampleRate(sampleRate), mInSampleRate(sampleRate), mInputIndex(0),
2184ff14bae91075eb274eb1c2975982358946e7e63John Grossman            mPhaseFraction(0), mLocalTimeFreq(0),
219ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
22065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // sanity check on format
22165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
22229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
22365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                inChannelCount);
224c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block        // ALOG_ASSERT(0);
22565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
226ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    if (sampleRate <= 0) {
227ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten        ALOGE("Unsupported sample rate %d Hz", sampleRate);
228ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    }
22965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
23065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // initialize common members
23165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mVolume[0] = mVolume[1] = 0;
23265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mBuffer.frameCount = 0;
23365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
23465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
23565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
23665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianAudioResampler::~AudioResampler() {
237ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    pthread_mutex_lock(&mutex);
238ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    src_quality quality = getQuality();
239ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    uint32_t deltaMHz = qualityMHz(quality);
240ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    int32_t newMHz = currentMHz - deltaMHz;
241ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    ALOGV("resampler load %u -> %d MHz due to delta -%u MHz from quality %d",
242ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten            currentMHz, newMHz, deltaMHz, quality);
243ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    LOG_ALWAYS_FATAL_IF(newMHz < 0, "negative resampler load %d MHz", newMHz);
244ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    currentMHz = newMHz;
245ac6020508acedd316391dee42329040bf45f8d90Glenn Kasten    pthread_mutex_unlock(&mutex);
24665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
24765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
24865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResampler::setSampleRate(int32_t inSampleRate) {
24965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mInSampleRate = inSampleRate;
25065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mPhaseIncrement = (uint32_t)((kPhaseMultiplier * inSampleRate) / mSampleRate);
25165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
25265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
25365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResampler::setVolume(int16_t left, int16_t right) {
25465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // TODO: Implement anti-zipper filter
25565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mVolume[0] = left;
25665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mVolume[1] = right;
25765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
25865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
2594ff14bae91075eb274eb1c2975982358946e7e63John Grossmanvoid AudioResampler::setLocalTimeFreq(uint64_t freq) {
2604ff14bae91075eb274eb1c2975982358946e7e63John Grossman    mLocalTimeFreq = freq;
2614ff14bae91075eb274eb1c2975982358946e7e63John Grossman}
2624ff14bae91075eb274eb1c2975982358946e7e63John Grossman
2634ff14bae91075eb274eb1c2975982358946e7e63John Grossmanvoid AudioResampler::setPTS(int64_t pts) {
2644ff14bae91075eb274eb1c2975982358946e7e63John Grossman    mPTS = pts;
2654ff14bae91075eb274eb1c2975982358946e7e63John Grossman}
2664ff14bae91075eb274eb1c2975982358946e7e63John Grossman
2674ff14bae91075eb274eb1c2975982358946e7e63John Grossmanint64_t AudioResampler::calculateOutputPTS(int outputFrameIndex) {
2684ff14bae91075eb274eb1c2975982358946e7e63John Grossman
2694ff14bae91075eb274eb1c2975982358946e7e63John Grossman    if (mPTS == AudioBufferProvider::kInvalidPTS) {
2704ff14bae91075eb274eb1c2975982358946e7e63John Grossman        return AudioBufferProvider::kInvalidPTS;
2714ff14bae91075eb274eb1c2975982358946e7e63John Grossman    } else {
2724ff14bae91075eb274eb1c2975982358946e7e63John Grossman        return mPTS + ((outputFrameIndex * mLocalTimeFreq) / mSampleRate);
2734ff14bae91075eb274eb1c2975982358946e7e63John Grossman    }
2744ff14bae91075eb274eb1c2975982358946e7e63John Grossman}
2754ff14bae91075eb274eb1c2975982358946e7e63John Grossman
276243f5f91755c01614a8cafe90b0806396e22d553Eric Laurentvoid AudioResampler::reset() {
277243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent    mInputIndex = 0;
278243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent    mPhaseFraction = 0;
279243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent    mBuffer.frameCount = 0;
280243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent}
281243f5f91755c01614a8cafe90b0806396e22d553Eric Laurent
28265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
28365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
28465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resample(int32_t* out, size_t outFrameCount,
28565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AudioBufferProvider* provider) {
28665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
28765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // should never happen, but we overflow if it does
288c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block    // ALOG_ASSERT(outFrameCount < 32767);
28965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
29065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // select the appropriate resampler
29165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    switch (mChannelCount) {
29265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    case 1:
29365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        resampleMono16(out, outFrameCount, provider);
29465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        break;
29565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    case 2:
29665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        resampleStereo16(out, outFrameCount, provider);
29765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        break;
29865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
29965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
30065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
30165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resampleStereo16(int32_t* out, size_t outFrameCount,
30265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AudioBufferProvider* provider) {
30365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
30465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t vl = mVolume[0];
30565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t vr = mVolume[1];
30665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
30765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t inputIndex = mInputIndex;
30865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t phaseFraction = mPhaseFraction;
30965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t phaseIncrement = mPhaseIncrement;
31065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t outputIndex = 0;
31165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t outputSampleCount = outFrameCount * 2;
31265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
31365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
31490bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
31565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
31665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
31765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    while (outputIndex < outputSampleCount) {
31865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
31965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // buffer is empty, fetch a new one
32065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        while (mBuffer.frameCount == 0) {
32165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mBuffer.frameCount = inFrameCount;
3224ff14bae91075eb274eb1c2975982358946e7e63John Grossman            provider->getNextBuffer(&mBuffer,
3234ff14bae91075eb274eb1c2975982358946e7e63John Grossman                                    calculateOutputPTS(outputIndex / 2));
32465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            if (mBuffer.raw == NULL) {
32565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                goto resampleStereo16_exit;
32665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            }
32765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
32890bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten            // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
32965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            if (mBuffer.frameCount > inputIndex) break;
33065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
33165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            inputIndex -= mBuffer.frameCount;
33265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
33365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
33465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            provider->releaseBuffer(&mBuffer);
335e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten            // mBuffer.frameCount == 0 now so we reload a new buffer
33665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
33765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
33865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int16_t *in = mBuffer.i16;
33965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
34065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // handle boundary case
34165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        while (inputIndex == 0) {
34290bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten            // ALOGE("boundary case");
34365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vl * Interp(mX0L, in[0], phaseFraction);
34465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vr * Interp(mX0R, in[1], phaseFraction);
34565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            Advance(&inputIndex, &phaseFraction, phaseIncrement);
34665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            if (outputIndex == outputSampleCount)
34765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                break;
34865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
34965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
35065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // process input samples
35190bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten        // ALOGE("general case");
35265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
35365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
35465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        if (inputIndex + 2 < mBuffer.frameCount) {
35565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            int32_t* maxOutPt;
35665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            int32_t maxInIdx;
35765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
35865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            maxOutPt = out + (outputSampleCount - 2);   // 2 because 2 frames per loop
35965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            maxInIdx = mBuffer.frameCount - 2;
36065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            AsmStereo16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
36165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                    phaseFraction, phaseIncrement);
36265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
36365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif  // ASM_ARM_RESAMP1
36465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
36565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
36665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vl * Interp(in[inputIndex*2-2],
36765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                    in[inputIndex*2], phaseFraction);
36865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vr * Interp(in[inputIndex*2-1],
36965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                    in[inputIndex*2+1], phaseFraction);
37065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            Advance(&inputIndex, &phaseFraction, phaseIncrement);
37165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
37265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
37390bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten        // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
37465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
37565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // if done with buffer, save samples
37665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        if (inputIndex >= mBuffer.frameCount) {
37765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            inputIndex -= mBuffer.frameCount;
37865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
37929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            // ALOGE("buffer done, new input index %d", inputIndex);
38065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
38165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mX0L = mBuffer.i16[mBuffer.frameCount*2-2];
38265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mX0R = mBuffer.i16[mBuffer.frameCount*2-1];
38365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            provider->releaseBuffer(&mBuffer);
38465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
38565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            // verify that the releaseBuffer resets the buffer frameCount
386c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block            // ALOG_ASSERT(mBuffer.frameCount == 0);
38765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
38865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
38965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
39090bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
39165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
39265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleStereo16_exit:
39365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // save state
39465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mInputIndex = inputIndex;
39565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mPhaseFraction = phaseFraction;
39665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
39765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
39865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::resampleMono16(int32_t* out, size_t outFrameCount,
39965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        AudioBufferProvider* provider) {
40065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
40165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t vl = mVolume[0];
40265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    int32_t vr = mVolume[1];
40365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
40465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t inputIndex = mInputIndex;
40565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t phaseFraction = mPhaseFraction;
40665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    uint32_t phaseIncrement = mPhaseIncrement;
40765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t outputIndex = 0;
40865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t outputSampleCount = outFrameCount * 2;
40965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    size_t inFrameCount = (outFrameCount*mInSampleRate)/mSampleRate;
41065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
41190bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten    // ALOGE("starting resample %d frames, inputIndex=%d, phaseFraction=%d, phaseIncrement=%d",
41265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    //      outFrameCount, inputIndex, phaseFraction, phaseIncrement);
41365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    while (outputIndex < outputSampleCount) {
41465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // buffer is empty, fetch a new one
41565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        while (mBuffer.frameCount == 0) {
41665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mBuffer.frameCount = inFrameCount;
4174ff14bae91075eb274eb1c2975982358946e7e63John Grossman            provider->getNextBuffer(&mBuffer,
4184ff14bae91075eb274eb1c2975982358946e7e63John Grossman                                    calculateOutputPTS(outputIndex / 2));
41965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            if (mBuffer.raw == NULL) {
42065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                mInputIndex = inputIndex;
42165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                mPhaseFraction = phaseFraction;
42265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                goto resampleMono16_exit;
42365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            }
42490bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten            // ALOGE("New buffer fetched: %d frames", mBuffer.frameCount);
42565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            if (mBuffer.frameCount >  inputIndex) break;
42665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
42765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            inputIndex -= mBuffer.frameCount;
42865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mX0L = mBuffer.i16[mBuffer.frameCount-1];
42965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            provider->releaseBuffer(&mBuffer);
43065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            // mBuffer.frameCount == 0 now so we reload a new buffer
43165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
43265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        int16_t *in = mBuffer.i16;
43365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
43465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // handle boundary case
43565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        while (inputIndex == 0) {
43690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten            // ALOGE("boundary case");
43765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            int32_t sample = Interp(mX0L, in[0], phaseFraction);
43865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vl * sample;
43965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vr * sample;
44065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            Advance(&inputIndex, &phaseFraction, phaseIncrement);
44165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            if (outputIndex == outputSampleCount)
44265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                break;
44365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
44465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
44565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // process input samples
44690bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten        // ALOGE("general case");
44765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
44865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
44965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        if (inputIndex + 2 < mBuffer.frameCount) {
45065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            int32_t* maxOutPt;
45165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            int32_t maxInIdx;
45265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
45365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            maxOutPt = out + (outputSampleCount - 2);
45465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            maxInIdx = (int32_t)mBuffer.frameCount - 2;
45565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                AsmMono16Loop(in, maxOutPt, maxInIdx, outputIndex, out, inputIndex, vl, vr,
45665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                        phaseFraction, phaseIncrement);
45765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
45865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif  // ASM_ARM_RESAMP1
45965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
46065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        while (outputIndex < outputSampleCount && inputIndex < mBuffer.frameCount) {
46165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            int32_t sample = Interp(in[inputIndex-1], in[inputIndex],
46265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian                    phaseFraction);
46365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vl * sample;
46465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            out[outputIndex++] += vr * sample;
46565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            Advance(&inputIndex, &phaseFraction, phaseIncrement);
46665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
46765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
46865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
46990bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten        // ALOGE("loop done - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
47065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
47165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // if done with buffer, save samples
47265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        if (inputIndex >= mBuffer.frameCount) {
47365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            inputIndex -= mBuffer.frameCount;
47465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
47529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            // ALOGE("buffer done, new input index %d", inputIndex);
47665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
47765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            mX0L = mBuffer.i16[mBuffer.frameCount-1];
47865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            provider->releaseBuffer(&mBuffer);
47965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
48065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            // verify that the releaseBuffer resets the buffer frameCount
481c1dc1cb1d1eaf84e88669f1a5f22579a0d9237c2Steve Block            // ALOG_ASSERT(mBuffer.frameCount == 0);
48265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        }
48365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    }
48465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
48590bebef5669a9385c706b042d146a31dca2e5d9bGlenn Kasten    // ALOGE("output buffer full - outputIndex=%d, inputIndex=%d", outputIndex, inputIndex);
48665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
48765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias AgopianresampleMono16_exit:
48865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    // save state
48965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mInputIndex = inputIndex;
49065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    mPhaseFraction = phaseFraction;
49165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
49265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
49365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#ifdef ASM_ARM_RESAMP1  // asm optimisation for ResamplerOrder1
49465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
49565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/*******************************************************************
49665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*
49765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   AsmMono16Loop
49865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   asm optimized monotonic loop version; one loop is 2 frames
49965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   Input:
50065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       in : pointer on input samples
50165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       maxOutPt : pointer on first not filled
50265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       maxInIdx : index on first not used
50365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       outputIndex : pointer on current output index
50465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       out : pointer on output buffer
50565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       inputIndex : pointer on current input index
50665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       vl, vr : left and right gain
50765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       phaseFraction : pointer on current phase fraction
50865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       phaseIncrement
50965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   Ouput:
51065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       outputIndex :
51165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       out : updated buffer
51265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       inputIndex : index of next to use
51365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       phaseFraction : phase fraction for next interpolation
51465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*
51565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/
516c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline))
51765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmMono16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
51865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
51965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            uint32_t &phaseFraction, uint32_t phaseIncrement)
52065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
52165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_PARAM5   "36"        // offset of parameter 5 (outputIndex)
52265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
52365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    asm(
52465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, lr}\n"
52565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // get parameters
52665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r6, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
52765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r6, [r6]\n"                         // phaseFraction
52865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r7, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
52965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r7, [r7]\n"                         // inputIndex
53065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r8, [sp, #" MO_PARAM5 " + 4]\n"     // out
53165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
53265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [r0]\n"                         // outputIndex
53365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   add r8, r0, asl #2\n"                   // curOut
53465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r9, [sp, #" MO_PARAM5 " + 24]\n"    // phaseIncrement
53565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r10, [sp, #" MO_PARAM5 " + 12]\n"   // vl
53665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r11, [sp, #" MO_PARAM5 " + 16]\n"   // vr
53765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
53865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r0 pin, x0, Samp
53965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
54065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r1 in
54165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r2 maxOutPt
54265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r3 maxInIdx
54365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
54465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r4 x1, i1, i3, Out1
54565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r5 out0
54665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
54765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r6 frac
54865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r7 inputIndex
54965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r8 curOut
55065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
55165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r9 inc
55265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r10 vl
55365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r11 vr
55465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
55565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r12
55665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r13 sp
55765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r14
55865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
55965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // the following loop works on 2 frames
56065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
561eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "1:\n"
56265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   cmp r8, r2\n"                   // curOut - maxCurOut
563eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "   bcs 2f\n"
56465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
56565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define MO_ONE_FRAME \
56665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r0, r1, r7, asl #1\n"       /* in + inputIndex */\
56765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldrsh r4, [r0]\n"               /* in[inputIndex] */\
56865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
56965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldrsh r0, [r0, #-2]\n"          /* in[inputIndex-1] */\
57065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
57165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   sub r4, r4, r0\n"               /* in[inputIndex] - in[inputIndex-1] */\
57265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   mov r4, r4, lsl #2\n"           /* <<2 */\
57365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
57465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
57565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r0, r0, r4\n"               /* x0 - (..) */\
57665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   mla r5, r0, r10, r5\n"          /* vl*interp + out[] */\
57765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
57865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
57965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   mla r4, r0, r11, r4\n"          /* vr*interp + out[] */\
58065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */\
58165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */
58265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
58365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        MO_ONE_FRAME    // frame 1
58465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        MO_ONE_FRAME    // frame 2
58565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
58665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   cmp r7, r3\n"                   // inputIndex - maxInIdx
587eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "   bcc 1b\n"
588eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "2:\n"
58965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
59065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   bic r6, r6, #0xC0000000\n"             // phaseFraction & ...
59165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // save modified values
59265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" MO_PARAM5 " + 20]\n"    // &phaseFraction
59365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   str r6, [r0]\n"                         // phaseFraction
59465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" MO_PARAM5 " + 8]\n"     // &inputIndex
59565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   str r7, [r0]\n"                         // inputIndex
59665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" MO_PARAM5 " + 4]\n"     // out
59765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   sub r8, r0\n"                           // curOut - out
59865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   asr r8, #2\n"                           // new outputIndex
59965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" MO_PARAM5 " + 0]\n"     // &outputIndex
60065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   str r8, [r0]\n"                         // save outputIndex
60165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
60265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, pc}\n"
60365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    );
60465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
60565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
60665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian/*******************************************************************
60765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*
60865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   AsmStereo16Loop
60965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   asm optimized stereo loop version; one loop is 2 frames
61065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   Input:
61165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       in : pointer on input samples
61265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       maxOutPt : pointer on first not filled
61365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       maxInIdx : index on first not used
61465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       outputIndex : pointer on current output index
61565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       out : pointer on output buffer
61665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       inputIndex : pointer on current input index
61765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       vl, vr : left and right gain
61865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       phaseFraction : pointer on current phase fraction
61965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       phaseIncrement
62065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*   Ouput:
62165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       outputIndex :
62265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       out : updated buffer
62365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       inputIndex : index of next to use
62465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*       phaseFraction : phase fraction for next interpolation
62565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*
62665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian*******************************************************************/
627c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten__attribute__((noinline))
62865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopianvoid AudioResamplerOrder1::AsmStereo16Loop(int16_t *in, int32_t* maxOutPt, int32_t maxInIdx,
62965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            size_t &outputIndex, int32_t* out, size_t &inputIndex, int32_t vl, int32_t vr,
63065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian            uint32_t &phaseFraction, uint32_t phaseIncrement)
63165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian{
63265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_PARAM5    "40"     // offset of parameter 5 (outputIndex)
63365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    asm(
63465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "stmfd  sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
63565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // get parameters
63665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r6, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
63765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r6, [r6]\n"                         // phaseFraction
63865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r7, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
63965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r7, [r7]\n"                         // inputIndex
64065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r8, [sp, #" ST_PARAM5 " + 4]\n"     // out
64165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
64265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [r0]\n"                         // outputIndex
64365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   add r8, r0, asl #2\n"                   // curOut
64465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r9, [sp, #" ST_PARAM5 " + 24]\n"    // phaseIncrement
64565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r10, [sp, #" ST_PARAM5 " + 12]\n"   // vl
64665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r11, [sp, #" ST_PARAM5 " + 16]\n"   // vr
64765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
64865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r0 pin, x0, Samp
64965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
65065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r1 in
65165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r2 maxOutPt
65265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r3 maxInIdx
65365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
65465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r4 x1, i1, i3, out1
65565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r5 out0
65665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
65765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r6 frac
65865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r7 inputIndex
65965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r8 curOut
66065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
66165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r9 inc
66265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r10 vl
66365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r11 vr
66465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
66565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r12 temporary
66665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r13 sp
66765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // r14
66865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
669eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "3:\n"
67065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   cmp r8, r2\n"                   // curOut - maxCurOut
671eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "   bcs 4f\n"
67265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
67365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#define ST_ONE_FRAME \
67465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   bic r6, r6, #0xC0000000\n"      /* phaseFraction & ... */\
67565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\
67665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r0, r1, r7, asl #2\n"       /* in + 2*inputIndex */\
67765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\
67865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldrsh r4, [r0]\n"               /* in[2*inputIndex] */\
67965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldr r5, [r8]\n"                 /* out[outputIndex] */\
68065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldrsh r12, [r0, #-4]\n"         /* in[2*inputIndex-2] */\
68165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   sub r4, r4, r12\n"              /* in[2*InputIndex] - in[2*InputIndex-2] */\
68265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   mov r4, r4, lsl #2\n"           /* <<2 */\
68365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   smulwt r4, r4, r6\n"            /* (x1-x0)*.. */\
68465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r12, r12, r4\n"             /* x0 - (..) */\
68565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   mla r5, r12, r10, r5\n"         /* vl*interp + out[] */\
68665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldr r4, [r8, #4]\n"             /* out[outputIndex+1] */\
68765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   str r5, [r8], #4\n"             /* out[outputIndex++] = ... */\
68865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\
68965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldrsh r12, [r0, #+2]\n"         /* in[2*inputIndex+1] */\
69065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   ldrsh r0, [r0, #-2]\n"          /* in[2*inputIndex-1] */\
69165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   sub r12, r12, r0\n"             /* in[2*InputIndex] - in[2*InputIndex-2] */\
69265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   mov r12, r12, lsl #2\n"         /* <<2 */\
69365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   smulwt r12, r12, r6\n"          /* (x1-x0)*.. */\
69465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r12, r0, r12\n"             /* x0 - (..) */\
69565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   mla r4, r12, r11, r4\n"         /* vr*interp + out[] */\
69665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   str r4, [r8], #4\n"             /* out[outputIndex++] = ... */\
69765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian\
69865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r6, r6, r9\n"               /* phaseFraction + phaseIncrement */\
69965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    "   add r7, r7, r6, lsr #30\n"      /* inputIndex + phaseFraction>>30 */
70065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
70165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    ST_ONE_FRAME    // frame 1
70265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    ST_ONE_FRAME    // frame 1
70365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
70465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   cmp r7, r3\n"                       // inputIndex - maxInIdx
705eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "   bcc 3b\n"
706eb8b914ad9d4331e1cdf4346731770ce69fd0e77Nick Kralevich        "4:\n"
70765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
70865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   bic r6, r6, #0xC0000000\n"              // phaseFraction & ...
70965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        // save modified values
71065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" ST_PARAM5 " + 20]\n"    // &phaseFraction
71165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   str r6, [r0]\n"                         // phaseFraction
71265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" ST_PARAM5 " + 8]\n"     // &inputIndex
71365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   str r7, [r0]\n"                         // inputIndex
71465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" ST_PARAM5 " + 4]\n"     // out
71565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   sub r8, r0\n"                           // curOut - out
71665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   asr r8, #2\n"                           // new outputIndex
71765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldr r0, [sp, #" ST_PARAM5 " + 0]\n"     // &outputIndex
71865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   str r8, [r0]\n"                         // save outputIndex
71965ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
72065ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian        "   ldmfd   sp!, {r4, r5, r6, r7, r8, r9, r10, r11, r12, pc}\n"
72165ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian    );
72265ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian}
72365ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
72465ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian#endif  // ASM_ARM_RESAMP1
72565ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
72665ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
72765ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian// ----------------------------------------------------------------------------
72865ab47156e1c7dfcd8cc4266253a5ff30219e7f0Mathias Agopian
729c23e2f2464eb3748599d47af7d8986b856f3c179Glenn Kasten} // namespace android
730