summaryrefslogtreecommitdiffstats
path: root/libs/audioflinger/AudioMixer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/audioflinger/AudioMixer.cpp')
-rw-r--r--libs/audioflinger/AudioMixer.cpp65
1 files changed, 46 insertions, 19 deletions
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 1add9f4..2a4756e 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -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);
}
// ----------------------------------------------------------------------------