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

Commit e636497a authored by Steve Kondik's avatar Steve Kondik Committed by Gerrit Code Review
Browse files

Merge "Add noise-shaped dithering support" into froyo

parents 03965c45 d3fa051b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3399,7 +3399,7 @@ bool AudioFlinger::RecordThread::threadLoop()
                    // ditherAndClamp() works as long as all buffers returned by mActiveTrack->getNextBuffer()
                    // are 32 bit aligned which should be always true.
                    if (mChannelCount == 2 && mReqChannelCount == 1) {
                        AudioMixer::ditherAndClamp(mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
                        AudioMixer::ditherAndClamp(&dither, mRsmpOutBuffer, mRsmpOutBuffer, framesOut);
                        // the resampler always outputs stereo samples: do post stereo to mono conversion
                        int16_t *src = (int16_t *)mRsmpOutBuffer;
                        int16_t *dst = buffer.i16;
@@ -3408,7 +3408,7 @@ bool AudioFlinger::RecordThread::threadLoop()
                            src += 2;
                        }
                    } else {
                        AudioMixer::ditherAndClamp((int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
                        AudioMixer::ditherAndClamp(&dither, (int32_t *)buffer.raw, mRsmpOutBuffer, framesOut);
                    }

                }
+2 −0
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@

#include "AudioBufferProvider.h"
#include "AudioDSP.h"
#include "AudioMixer.h"

namespace android {

@@ -766,6 +767,7 @@ private:
                int                                 mReqChannelCount;
                uint32_t                            mReqSampleRate;
                ssize_t                             mBytesRead;
                dither_t                            dither;
    };

    class RecordHandle : public android::BnAudioRecord {
+46 −19
Original line number Diff line number Diff line
@@ -38,10 +38,10 @@ static inline int16_t clamp16(int32_t sample)
    return sample;
}

inline static int32_t prng() {
    static int32_t seed = 1;
    seed = (seed * 12345) + 1103515245;
    return int32_t(seed & 0xfff);
inline static uint32_t prng() {
    static uint32_t seed = 22222;
    seed = (seed * 196314165) + 907633515;
    return seed >> 20;
}

// ----------------------------------------------------------------------------
@@ -621,24 +621,51 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
    t->in = in;
}

void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
int32_t AudioMixer::lipshitz(int32_t* state, int32_t input)
{
#define COEFF(x) int32_t(x * 4096.0f + 0.5f)
    int32_t output =
          COEFF(-2.033f) * input
        + COEFF(+2.165f) * state[0]
        + COEFF(-1.959f) * state[1]
        + COEFF(+1.590f) * state[2]
        + COEFF(-0.6149f) * state[3];
#undef COEFF

    state[3] = state[2];
    state[2] = state[1];
    state[1] = state[0];
    state[0] = input;

    return output >> 12;
}


void AudioMixer::ditherAndClamp(dither_t* state, int32_t* out, int32_t const *sums, size_t c)
{
    int32_t oldDitherValue = prng();
    for (size_t i=0 ; i<c ; i++) {
        int32_t l = *sums++;
        int32_t r = *sums++;

        /* Apply dither to output. This is the high-passed triangular
         * probability density function, discussed in "A Theory of
         * Nonsubtractive Dither", by Robert A. Wannamaker et al. */
        int32_t ditherValue = prng();
        int32_t dithering = oldDitherValue - ditherValue;
        oldDitherValue = ditherValue;

        int32_t nl = (l + ditherValue) >> 12;
        int32_t nr = (r + ditherValue) >> 12;
        l = clamp16(nl);
        r = clamp16(nr);
        /* Noise-shaped dither function. */

        /* High-passed Triangular PDF according to
         * "A Theory of Nonsubtractive Dither" by Robert Wannamaker et al.
         * Other software seems to prefer (prng() + prng()) >> 1 as the
         * random source, which they highpass, but that distribution is not
         * triangular. */
        int32_t newDither = prng();
        int32_t dithering = newDither - state->oldDither;
        state->oldDither = newDither;

        l += lipshitz(state->lipshitzL, state->errorL) + dithering;
        r += lipshitz(state->lipshitzR, state->errorR) + dithering;
        state->errorL = l & 0xfff;
        state->errorR = r & 0xfff;

        l = clamp16(l >> 12);
        r = clamp16(r >> 12);

        *out++ = (r<<16) | (l & 0xFFFF);
    }
}
@@ -721,7 +748,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output, Audi
        }

        dsp.process(outTemp, BLOCKSIZE);
        ditherAndClamp(out, outTemp, BLOCKSIZE);
        ditherAndClamp(&state->dither, out, outTemp, BLOCKSIZE);
        out += BLOCKSIZE;
        numFrames -= BLOCKSIZE;
    } while (numFrames);
@@ -778,7 +805,7 @@ void AudioMixer::process__genericResampling(state_t* state, void* output, AudioD
    }

    dsp.process(outTemp, numFrames);
    ditherAndClamp(out, outTemp, numFrames);
    ditherAndClamp(&state->dither, out, outTemp, numFrames);
}

// ----------------------------------------------------------------------------
+13 −2
Original line number Diff line number Diff line
@@ -32,6 +32,13 @@ namespace android {
#define LIKELY( exp )       (__builtin_expect( (exp) != 0, true  ))
#define UNLIKELY( exp )     (__builtin_expect( (exp) != 0, false ))

struct dither_t {
    /* Dithering variables */
    int32_t         errorL, errorR;
    int32_t         lipshitzL[4], lipshitzR[4];
    int32_t         oldDither;
};

// ----------------------------------------------------------------------------

class AudioMixer
@@ -86,7 +93,7 @@ public:

    uint32_t    trackNames() const { return mTrackNames; }

    static void ditherAndClamp(int32_t* out, int32_t const *sums, size_t c);
    static void ditherAndClamp(dither_t* dither, int32_t* out, const int32_t* sums, size_t c);

private:
    enum {
@@ -162,7 +169,10 @@ private:
        int32_t         *outputTemp;
        int32_t         *resampleTemp;
        int32_t         reserved[2];
        track_t         tracks[32]; __attribute__((aligned(32)));
        track_t         tracks[32];

        dither_t        dither;
        __attribute__((aligned(32)));
    };

    int             mActiveTrack;
@@ -174,6 +184,7 @@ private:

    void invalidateState(uint32_t mask);

    static int32_t lipshitz(int32_t* state, int32_t input);
    static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, AudioDSP& dsp);
    static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, AudioDSP& dsp);
    static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp);