Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0d3679e2 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "Add and enable multichannel for audio resampler"

parents 3c643073 075abae2
Loading
Loading
Loading
Loading
+6 −5
Original line number Diff line number Diff line
@@ -259,13 +259,14 @@ AudioResampler::AudioResampler(int bitDepth, int inChannelCount,
            mPhaseFraction(0), mLocalTimeFreq(0),
            mPTS(AudioBufferProvider::kInvalidPTS), mQuality(quality) {
    // sanity check on format
    if ((bitDepth != 16) ||(inChannelCount < 1) || (inChannelCount > 2)) {
        ALOGE("Unsupported sample format, %d bits, %d channels", bitDepth,
                inChannelCount);
        // ALOG_ASSERT(0);
    if ((bitDepth != 16 && (quality < DYN_LOW_QUALITY || bitDepth != 32))
            || inChannelCount < 1
            || inChannelCount > (quality < DYN_LOW_QUALITY ? 2 : 8)) {
        LOG_ALWAYS_FATAL("Unsupported sample format %d quality %d bits, %d channels",
                quality, bitDepth, inChannelCount);
    }
    if (sampleRate <= 0) {
        ALOGE("Unsupported sample rate %d Hz", sampleRate);
        LOG_ALWAYS_FATAL("Unsupported sample rate %d Hz", sampleRate);
    }

    // initialize common members
+72 −34
Original line number Diff line number Diff line
@@ -38,11 +38,6 @@

namespace android {

// generate a unique resample type compile-time constant (constexpr)
#define RESAMPLETYPE(CHANNELS, LOCKED, STRIDE) \
    ((((CHANNELS)-1)&1) | !!(LOCKED)<<1 \
    | ((STRIDE)==8 ? 1 : (STRIDE)==16 ? 2 : 0)<<2)

/*
 * InBuffer is a type agnostic input buffer.
 *
@@ -403,12 +398,76 @@ void AudioResamplerDyn<TC, TI, TO>::setSampleRate(int32_t inSampleRate)
    // determine which resampler to use
    // check if locked phase (works only if mPhaseIncrement has no "fractional phase bits")
    int locked = (mPhaseIncrement << (sizeof(mPhaseIncrement)*8 - c.mShift)) == 0;
    int stride = (c.mHalfNumCoefs&7)==0 ? 16 : (c.mHalfNumCoefs&3)==0 ? 8 : 2;
    if (locked) {
        mPhaseFraction = mPhaseFraction >> c.mShift << c.mShift; // remove fractional phase
    }

    setResampler(RESAMPLETYPE(mChannelCount, locked, stride));
    // stride is the minimum number of filter coefficients processed per loop iteration.
    // We currently only allow a stride of 16 to match with SIMD processing.
    // This means that the filter length must be a multiple of 16,
    // or half the filter length (mHalfNumCoefs) must be a multiple of 8.
    //
    // Note: A stride of 2 is achieved with non-SIMD processing.
    int stride = ((c.mHalfNumCoefs & 7) == 0) ? 16 : 2;
    LOG_ALWAYS_FATAL_IF(stride < 16, "Resampler stride must be 16 or more");
    LOG_ALWAYS_FATAL_IF(mChannelCount > 8 || mChannelCount < 1,
            "Resampler channels(%d) must be between 1 to 8", mChannelCount);
    // stride 16 (falls back to stride 2 for machines that do not support NEON)
    if (locked) {
        switch (mChannelCount) {
        case 1:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
            break;
        case 2:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
            break;
        case 3:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, true, 16>;
            break;
        case 4:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, true, 16>;
            break;
        case 5:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, true, 16>;
            break;
        case 6:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, true, 16>;
            break;
        case 7:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, true, 16>;
            break;
        case 8:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, true, 16>;
            break;
        }
    } else {
        switch (mChannelCount) {
        case 1:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
            break;
        case 2:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
            break;
        case 3:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<3, false, 16>;
            break;
        case 4:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<4, false, 16>;
            break;
        case 5:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<5, false, 16>;
            break;
        case 6:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<6, false, 16>;
            break;
        case 7:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<7, false, 16>;
            break;
        case 8:
            mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<8, false, 16>;
            break;
        }
    }
#ifdef DEBUG_RESAMPLER
    printf("channels:%d  %s  stride:%d  %s  coef:%d  shift:%d\n",
            mChannelCount, locked ? "locked" : "interpolated",
@@ -423,35 +482,13 @@ void AudioResamplerDyn<TC, TI, TO>::resample(int32_t* out, size_t outFrameCount,
    (this->*mResampleFunc)(reinterpret_cast<TO*>(out), outFrameCount, provider);
}

template<typename TC, typename TI, typename TO>
void AudioResamplerDyn<TC, TI, TO>::setResampler(unsigned resampleType)
{
    // stride 16 (falls back to stride 2 for machines that do not support NEON)
    switch (resampleType) {
    case RESAMPLETYPE(1, true, 16):
        mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, true, 16>;
        return;
    case RESAMPLETYPE(2, true, 16):
        mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, true, 16>;
        return;
    case RESAMPLETYPE(1, false, 16):
        mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<1, false, 16>;
        return;
    case RESAMPLETYPE(2, false, 16):
        mResampleFunc = &AudioResamplerDyn<TC, TI, TO>::resample<2, false, 16>;
        return;
    default:
        LOG_ALWAYS_FATAL("Invalid resampler type: %u", resampleType);
        mResampleFunc = NULL;
        return;
    }
}

template<typename TC, typename TI, typename TO>
template<int CHANNELS, bool LOCKED, int STRIDE>
void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
        AudioBufferProvider* provider)
{
    // TODO Mono -> Mono is not supported. OUTPUT_CHANNELS reflects minimum of stereo out.
    const int OUTPUT_CHANNELS = (CHANNELS < 2) ? 2 : CHANNELS;
    const Constants& c(mConstants);
    const TC* const coefs = mConstants.mFirCoefs;
    TI* impulse = mInBuffer.getImpulse();
@@ -459,7 +496,7 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
    uint32_t phaseFraction = mPhaseFraction;
    const uint32_t phaseIncrement = mPhaseIncrement;
    size_t outputIndex = 0;
    size_t outputSampleCount = outFrameCount * 2;   // stereo output
    size_t outputSampleCount = outFrameCount * OUTPUT_CHANNELS;
    const uint32_t phaseWrapLimit = c.mL << c.mShift;
    size_t inFrameCount = (phaseIncrement * (uint64_t)outFrameCount + phaseFraction)
            / phaseWrapLimit;
@@ -490,7 +527,7 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
        while (mBuffer.frameCount == 0 && inFrameCount > 0) {
            mBuffer.frameCount = inFrameCount;
            provider->getNextBuffer(&mBuffer,
                    calculateOutputPTS(outputIndex / 2));
                    calculateOutputPTS(outputIndex / OUTPUT_CHANNELS));
            if (mBuffer.raw == NULL) {
                goto resample_exit;
            }
@@ -538,7 +575,8 @@ void AudioResamplerDyn<TC, TI, TO>::resample(TO* out, size_t outFrameCount,
                    phaseFraction, phaseWrapLimit,
                    coefShift, halfNumCoefs, coefs,
                    impulse, volumeSimd);
            outputIndex += 2;

            outputIndex += OUTPUT_CHANNELS;

            phaseFraction += phaseIncrement;
            while (phaseFraction >= phaseWrapLimit) {
+1 −3
Original line number Diff line number Diff line
@@ -110,12 +110,10 @@ private:
    void createKaiserFir(Constants &c, double stopBandAtten,
            int inSampleRate, int outSampleRate, double tbwCheat);

    void setResampler(unsigned resampleType);

    template<int CHANNELS, bool LOCKED, int STRIDE>
    void resample(TO* out, size_t outFrameCount, AudioBufferProvider* provider);

    // declare a pointer to member function for resample
    // define a pointer to member function type for resample
    typedef void (AudioResamplerDyn<TC, TI, TO>::*resample_ABP_t)(TO* out,
            size_t outFrameCount, AudioBufferProvider* provider);

+51 −14
Original line number Diff line number Diff line
@@ -35,7 +35,8 @@
#include "AudioResampler.h"
#include "test_utils.h"

void resample(void *output, size_t outputFrames, const std::vector<size_t> &outputIncr,
void resample(int channels, void *output,
        size_t outputFrames, const std::vector<size_t> &outputIncr,
        android::AudioBufferProvider *provider, android::AudioResampler *resampler)
{
    for (size_t i = 0, j = 0; i < outputFrames; ) {
@@ -46,7 +47,7 @@ void resample(void *output, size_t outputFrames, const std::vector<size_t> &outp
        if (thisFrames == 0 || thisFrames > outputFrames - i) {
            thisFrames = outputFrames - i;
        }
        resampler->resample((int32_t*) output + 2*i, thisFrames, provider);
        resampler->resample((int32_t*) output + channels*i, thisFrames, provider);
        i += thisFrames;
    }
}
@@ -64,19 +65,26 @@ void buffercmp(const void *reference, const void *test,
    }
}

void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFreq,
void testBufferIncrement(size_t channels, bool useFloat,
        unsigned inputFreq, unsigned outputFreq,
        enum android::AudioResampler::src_quality quality)
{
    const int bits = useFloat ? 32 : 16;
    // create the provider
    std::vector<int> inputIncr;
    SignalProvider provider;
    if (useFloat) {
        provider.setChirp<float>(channels,
                0., outputFreq/2., outputFreq, outputFreq/2000.);
    } else {
        provider.setChirp<int16_t>(channels,
                0., outputFreq/2., outputFreq, outputFreq/2000.);
    }
    provider.setIncr(inputIncr);

    // calculate the output size
    size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
    size_t outputFrameSize = 2 * sizeof(int32_t);
    size_t outputFrameSize = channels * (useFloat ? sizeof(float) : sizeof(int32_t));
    size_t outputSize = outputFrameSize * outputFrames;
    outputSize &= ~7;

@@ -84,7 +92,7 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
    const int volumePrecision = 12; /* typical unity gain */
    android::AudioResampler* resampler;

    resampler = android::AudioResampler::create(16, channels, outputFreq, quality);
    resampler = android::AudioResampler::create(bits, channels, outputFreq, quality);
    resampler->setSampleRate(inputFreq);
    resampler->setVolume(1 << volumePrecision, 1 << volumePrecision);

@@ -92,7 +100,7 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
    std::vector<size_t> refIncr;
    refIncr.push_back(outputFrames);
    void* reference = malloc(outputSize);
    resample(reference, outputFrames, refIncr, &provider, resampler);
    resample(channels, reference, outputFrames, refIncr, &provider, resampler);

    provider.reset();

@@ -101,7 +109,7 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
    resampler->reset();
#else
    delete resampler;
    resampler = android::AudioResampler::create(16, channels, outputFreq, quality);
    resampler = android::AudioResampler::create(bits, channels, outputFreq, quality);
    resampler->setSampleRate(inputFreq);
    resampler->setVolume(1 << volumePrecision, 1 << volumePrecision);
#endif
@@ -112,7 +120,10 @@ void testBufferIncrement(size_t channels, unsigned inputFreq, unsigned outputFre
    outIncr.push_back(2);
    outIncr.push_back(3);
    void* test = malloc(outputSize);
    resample(test, outputFrames, outIncr, &provider, resampler);
    inputIncr.push_back(1);
    inputIncr.push_back(3);
    provider.setIncr(inputIncr);
    resample(channels, test, outputFrames, outIncr, &provider, resampler);

    // check
    buffercmp(reference, test, outputFrameSize, outputFrames);
@@ -155,7 +166,7 @@ void testStopbandDownconversion(size_t channels,

    // calculate the output size
    size_t outputFrames = ((int64_t) provider.getNumFrames() * outputFreq) / inputFreq;
    size_t outputFrameSize = 2 * sizeof(int32_t);
    size_t outputFrameSize = channels * sizeof(int32_t);
    size_t outputSize = outputFrameSize * outputFrames;
    outputSize &= ~7;

@@ -171,7 +182,7 @@ void testStopbandDownconversion(size_t channels,
    std::vector<size_t> refIncr;
    refIncr.push_back(outputFrames);
    void* reference = malloc(outputSize);
    resample(reference, outputFrames, refIncr, &provider, resampler);
    resample(channels, reference, outputFrames, refIncr, &provider, resampler);

    int32_t *out = reinterpret_cast<int32_t *>(reference);

@@ -226,7 +237,7 @@ TEST(audioflinger_resampler, bufferincrement_fixedphase) {
    };

    for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
        testBufferIncrement(2, 48000, 32000, kQualityArray[i]);
        testBufferIncrement(2, false, 48000, 32000, kQualityArray[i]);
    }
}

@@ -243,7 +254,33 @@ TEST(audioflinger_resampler, bufferincrement_interpolatedphase) {
    };

    for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
        testBufferIncrement(2, 22050, 48000, kQualityArray[i]);
        testBufferIncrement(2, false, 22050, 48000, kQualityArray[i]);
    }
}

TEST(audioflinger_resampler, bufferincrement_fixedphase_multi) {
    // only dynamic quality
    static const enum android::AudioResampler::src_quality kQualityArray[] = {
            android::AudioResampler::DYN_LOW_QUALITY,
            android::AudioResampler::DYN_MED_QUALITY,
            android::AudioResampler::DYN_HIGH_QUALITY,
    };

    for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
        testBufferIncrement(4, false, 48000, 32000, kQualityArray[i]);
    }
}

TEST(audioflinger_resampler, bufferincrement_interpolatedphase_multi_float) {
    // only dynamic quality
    static const enum android::AudioResampler::src_quality kQualityArray[] = {
            android::AudioResampler::DYN_LOW_QUALITY,
            android::AudioResampler::DYN_MED_QUALITY,
            android::AudioResampler::DYN_HIGH_QUALITY,
    };

    for (size_t i = 0; i < ARRAY_SIZE(kQualityArray); ++i) {
        testBufferIncrement(8, true, 22050, 48000, kQualityArray[i]);
    }
}