Loading libs/audioflinger/AudioFlinger.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } } Loading libs/audioflinger/AudioFlinger.h +2 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include "AudioBufferProvider.h" #include "AudioDSP.h" #include "AudioMixer.h" namespace android { Loading Loading @@ -766,6 +767,7 @@ private: int mReqChannelCount; uint32_t mReqSampleRate; ssize_t mBytesRead; dither_t dither; }; class RecordHandle : public android::BnAudioRecord { Loading libs/audioflinger/AudioMixer.cpp +46 −19 Original line number Diff line number Diff line Loading @@ -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; } // ---------------------------------------------------------------------------- Loading Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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); } // ---------------------------------------------------------------------------- Loading libs/audioflinger/AudioMixer.h +13 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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; Loading @@ -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); Loading Loading
libs/audioflinger/AudioFlinger.cpp +2 −2 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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); } } Loading
libs/audioflinger/AudioFlinger.h +2 −0 Original line number Diff line number Diff line Loading @@ -43,6 +43,7 @@ #include "AudioBufferProvider.h" #include "AudioDSP.h" #include "AudioMixer.h" namespace android { Loading Loading @@ -766,6 +767,7 @@ private: int mReqChannelCount; uint32_t mReqSampleRate; ssize_t mBytesRead; dither_t dither; }; class RecordHandle : public android::BnAudioRecord { Loading
libs/audioflinger/AudioMixer.cpp +46 −19 Original line number Diff line number Diff line Loading @@ -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; } // ---------------------------------------------------------------------------- Loading Loading @@ -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); } } Loading Loading @@ -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); Loading Loading @@ -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); } // ---------------------------------------------------------------------------- Loading
libs/audioflinger/AudioMixer.h +13 −2 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 { Loading Loading @@ -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; Loading @@ -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); Loading