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.cpp263
1 files changed, 66 insertions, 197 deletions
diff --git a/libs/audioflinger/AudioMixer.cpp b/libs/audioflinger/AudioMixer.cpp
index 19a442a..e5985d7 100644
--- a/libs/audioflinger/AudioMixer.cpp
+++ b/libs/audioflinger/AudioMixer.cpp
@@ -38,11 +38,18 @@ static inline int16_t clamp16(int32_t sample)
return sample;
}
+static int32_t seed = 1;
+inline static int32_t prng() {
+ seed = (seed * 12345) + 1103515245;
+ return int32_t(seed & 0xfff);
+}
+
// ----------------------------------------------------------------------------
-AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
- : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate)
+AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate, AudioDSP& dsp)
+ : mActiveTrack(0), mTrackNames(0), mSampleRate(sampleRate), mDsp(dsp)
{
+ mDsp.configure(sampleRate);
mState.enabledTracks= 0;
mState.needsChanged = 0;
mState.frameCount = frameCount;
@@ -202,18 +209,10 @@ status_t AudioMixer::setParameter(int target, int name, int value)
if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
track_t& track = mState.tracks[ mActiveTrack ];
if (track.volume[name-VOLUME0] != value) {
- track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
track.volume[name-VOLUME0] = value;
if (target == VOLUME) {
track.prevVolume[name-VOLUME0] = value << 16;
track.volumeInc[name-VOLUME0] = 0;
- } else {
- int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
- int32_t volInc = d / int32_t(mState.frameCount);
- track.volumeInc[name-VOLUME0] = volInc;
- if (volInc == 0) {
- track.prevVolume[name-VOLUME0] = value << 16;
- }
}
invalidateState(1<<mActiveTrack);
}
@@ -244,15 +243,34 @@ bool AudioMixer::track_t::doesResample() const
return resampler != 0;
}
-inline
-void AudioMixer::track_t::adjustVolumeRamp()
+void AudioMixer::track_t::adjustVolumeRamp(AudioDSP& dsp, size_t frames)
{
- for (int i=0 ; i<2 ; i++) {
- if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
- ((volumeInc[i]<0) && (((prevVolume[i]+volumeInc[i])>>16) <= volume[i]))) {
- volumeInc[i] = 0;
- prevVolume[i] = volume[i]<<16;
+ int32_t dynamicRangeCompressionFactor = dsp.estimateLevel(
+ static_cast<const int16_t*>(in), int32_t(frames), channelCount
+ );
+
+ for (int i = 0; i < 2; i ++) {
+ /* Ramp from current to new volume level if necessary */
+ int32_t desiredVolume = volume[i] * dynamicRangeCompressionFactor;
+ int32_t d = desiredVolume - prevVolume[i];
+
+ /* limit change rate to smooth the compressor. */
+ int32_t volChangeLimit = (prevVolume[i] >> 10);
+
+ volChangeLimit += 1;
+ int32_t volInc = d / int32_t(frames);
+ if (volInc < -(volChangeLimit)) {
+ volInc = -(volChangeLimit);
}
+
+ /* Make ramps up slower, but ramps down fast. */
+ volChangeLimit >>= 3;
+ volChangeLimit -= 1;
+ if (volInc > volChangeLimit) {
+ volInc = volChangeLimit;
+ }
+
+ volumeInc[i] = volInc;
}
}
@@ -267,11 +285,11 @@ status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
void AudioMixer::process(void* output)
{
- mState.hook(&mState, output);
+ mState.hook(&mState, output, mDsp);
}
-void AudioMixer::process__validate(state_t* state, void* output)
+void AudioMixer::process__validate(state_t* state, void* output, AudioDSP& dsp)
{
LOGW_IF(!state->needsChanged,
"in process__validate() but nothing's invalid");
@@ -356,11 +374,6 @@ void AudioMixer::process__validate(state_t* state, void* output)
state->resampleTemp = 0;
}
state->hook = process__genericNoResampling;
- if (all16BitsStereoNoResample && !volumeRamp) {
- if (countActiveTracks == 1) {
- state->hook = process__OneTrack16BitsStereoNoResampling;
- }
- }
}
}
@@ -369,7 +382,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
countActiveTracks, state->enabledTracks,
all16BitsStereoNoResample, resampling, volumeRamp);
- state->hook(state, output);
+ state->hook(state, output, dsp);
// Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
@@ -390,10 +403,6 @@ void AudioMixer::process__validate(state_t* state, void* output)
}
if (allMuted) {
state->hook = process__nop;
- } else if (!resampling && all16BitsStereoNoResample) {
- if (countActiveTracks == 1) {
- state->hook = process__OneTrack16BitsStereoNoResampling;
- }
}
}
}
@@ -481,7 +490,7 @@ int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
}
-void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, AudioDSP& dsp)
{
t->resampler->setSampleRate(t->sampleRate);
@@ -490,7 +499,7 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram
t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
t->resampler->resample(temp, outFrameCount, t->bufferProvider);
- volumeRampStereo(t, out, outFrameCount, temp);
+ volumeRampStereo(t, out, outFrameCount, temp, dsp);
}
// constant gain
@@ -500,12 +509,13 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram
}
}
-void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
+void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, AudioDSP& dsp)
{
}
-void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp)
{
+ t->adjustVolumeRamp(dsp, frameCount);
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
const int32_t vlInc = t->volumeInc[0];
@@ -525,14 +535,14 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
- t->adjustVolumeRamp();
}
-void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp)
{
int16_t const *in = static_cast<int16_t const *>(t->in);
// ramp gain
+ t->adjustVolumeRamp(dsp, frameCount);
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
@@ -552,7 +562,6 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
- t->adjustVolumeRamp();
}
// constant gain
@@ -569,11 +578,12 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount
t->in = in;
}
-void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
+void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, AudioDSP& dsp)
{
int16_t const *in = static_cast<int16_t const *>(t->in);
// ramp gain
+ t->adjustVolumeRamp(dsp, frameCount);
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
@@ -594,7 +604,6 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
- t->adjustVolumeRamp();
}
// constant gain
else {
@@ -612,11 +621,20 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
void AudioMixer::ditherAndClamp(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++;
- int32_t nl = l >> 12;
- int32_t nr = r >> 12;
+
+ /* 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);
*out++ = (r<<16) | (l & 0xFFFF);
@@ -624,7 +642,7 @@ void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
}
// no-op case
-void AudioMixer::process__nop(state_t* state, void* output)
+void AudioMixer::process__nop(state_t* state, void* output, AudioDSP& dsp)
{
// this assumes output 16 bits stereo, no resampling
memset(output, 0, state->frameCount*4);
@@ -645,7 +663,7 @@ void AudioMixer::process__nop(state_t* state, void* output)
}
// generic code without resampling
-void AudioMixer::process__genericNoResampling(state_t* state, void* output)
+void AudioMixer::process__genericNoResampling(state_t* state, void* output, AudioDSP& dsp)
{
int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
@@ -682,7 +700,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
while (outFrames) {
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
if (inFrames) {
- (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
+ (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, dsp);
t.frameCount -= inFrames;
outFrames -= inFrames;
}
@@ -700,6 +718,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
}
}
+ dsp.process(outTemp, BLOCKSIZE);
ditherAndClamp(out, outTemp, BLOCKSIZE);
out += BLOCKSIZE;
numFrames -= BLOCKSIZE;
@@ -717,7 +736,7 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
}
// generic code with resampling
-void AudioMixer::process__genericResampling(state_t* state, void* output)
+void AudioMixer::process__genericResampling(state_t* state, void* output, AudioDSP& dsp)
{
int32_t* const outTemp = state->outputTemp;
const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
@@ -736,7 +755,7 @@ void AudioMixer::process__genericResampling(state_t* state, void* output)
// acquire/release the buffers because it's done by
// the resampler.
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
- (t.hook)(&t, outTemp, numFrames, state->resampleTemp);
+ (t.hook)(&t, outTemp, numFrames, state->resampleTemp, dsp);
} else {
size_t outFrames = numFrames;
@@ -749,167 +768,17 @@ void AudioMixer::process__genericResampling(state_t* state, void* output)
// been enabled for mixing.
if (t.in == NULL) break;
- (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
+ (t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, dsp);
outFrames -= t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
}
}
}
+ dsp.process(outTemp, numFrames);
ditherAndClamp(out, outTemp, numFrames);
}
-// one track, 16 bits stereo without resampling is the most common case
-void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
-{
- const int i = 31 - __builtin_clz(state->enabledTracks);
- const track_t& t = state->tracks[i];
-
- AudioBufferProvider::Buffer& b(t.buffer);
-
- int32_t* out = static_cast<int32_t*>(output);
- size_t numFrames = state->frameCount;
-
- const int16_t vl = t.volume[0];
- const int16_t vr = t.volume[1];
- const uint32_t vrl = t.volumeRL;
- while (numFrames) {
- b.frameCount = numFrames;
- t.bufferProvider->getNextBuffer(&b);
- int16_t const *in = b.i16;
-
- // in == NULL can happen if the track was flushed just after having
- // been enabled for mixing.
- if (in == NULL || ((unsigned long)in & 3)) {
- memset(out, 0, numFrames*MAX_NUM_CHANNELS*sizeof(int16_t));
- LOGE_IF(((unsigned long)in & 3), "process stereo track: input buffer alignment pb: buffer %p track %d, channels %d, needs %08x",
- in, i, t.channelCount, t.needs);
- return;
- }
- size_t outFrames = b.frameCount;
-
- if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
- // volume is boosted, so we might need to clamp even though
- // we process only one track.
- do {
- uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- // clamping...
- l = clamp16(l);
- r = clamp16(r);
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
- } else {
- do {
- uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
- in += 2;
- int32_t l = mulRL(1, rl, vrl) >> 12;
- int32_t r = mulRL(0, rl, vrl) >> 12;
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
- }
- numFrames -= b.frameCount;
- t.bufferProvider->releaseBuffer(&b);
- }
-}
-
-// 2 tracks is also a common case
-void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
-{
- int i;
- uint32_t en = state->enabledTracks;
-
- i = 31 - __builtin_clz(en);
- const track_t& t0 = state->tracks[i];
- AudioBufferProvider::Buffer& b0(t0.buffer);
-
- en &= ~(1<<i);
- i = 31 - __builtin_clz(en);
- const track_t& t1 = state->tracks[i];
- AudioBufferProvider::Buffer& b1(t1.buffer);
-
- int16_t const *in0;
- const int16_t vl0 = t0.volume[0];
- const int16_t vr0 = t0.volume[1];
- size_t frameCount0 = 0;
-
- int16_t const *in1;
- const int16_t vl1 = t1.volume[0];
- const int16_t vr1 = t1.volume[1];
- size_t frameCount1 = 0;
-
- int32_t* out = static_cast<int32_t*>(output);
- size_t numFrames = state->frameCount;
- int16_t const *buff = NULL;
-
-
- while (numFrames) {
-
- if (frameCount0 == 0) {
- b0.frameCount = numFrames;
- t0.bufferProvider->getNextBuffer(&b0);
- if (b0.i16 == NULL) {
- if (buff == NULL) {
- buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
- }
- in0 = buff;
- b0.frameCount = numFrames;
- } else {
- in0 = b0.i16;
- }
- frameCount0 = b0.frameCount;
- }
- if (frameCount1 == 0) {
- b1.frameCount = numFrames;
- t1.bufferProvider->getNextBuffer(&b1);
- if (b1.i16 == NULL) {
- if (buff == NULL) {
- buff = new int16_t[MAX_NUM_CHANNELS * state->frameCount];
- }
- in1 = buff;
- b1.frameCount = numFrames;
- } else {
- in1 = b1.i16;
- }
- frameCount1 = b1.frameCount;
- }
-
- size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
-
- numFrames -= outFrames;
- frameCount0 -= outFrames;
- frameCount1 -= outFrames;
-
- do {
- int32_t l0 = *in0++;
- int32_t r0 = *in0++;
- l0 = mul(l0, vl0);
- r0 = mul(r0, vr0);
- int32_t l = *in1++;
- int32_t r = *in1++;
- l = mulAdd(l, vl1, l0) >> 12;
- r = mulAdd(r, vr1, r0) >> 12;
- // clamping...
- l = clamp16(l);
- r = clamp16(r);
- *out++ = (r<<16) | (l & 0xFFFF);
- } while (--outFrames);
-
- if (frameCount0 == 0) {
- t0.bufferProvider->releaseBuffer(&b0);
- }
- if (frameCount1 == 0) {
- t1.bufferProvider->releaseBuffer(&b1);
- }
- }
-
- if (buff != NULL) {
- delete [] buff;
- }
-}
-
// ----------------------------------------------------------------------------
}; // namespace android