From f8ba6bc80da381e65939c34f3c453abd657152d4 Mon Sep 17 00:00:00 2001
From: philippegorley <philippe.gorley@savoirfairelinux.com>
Date: Thu, 15 Nov 2018 14:48:26 -0500
Subject: [PATCH] audio: clip audio signal when mixing

Blindly adding both signals results in over/underflows which show up in
the signal as noise, avoid that by clamping the result between min and
max for s16 samples.

Change-Id: Ibbb42d87497c662b5ba9085d4c9efb6f1e45a183
---
 src/media/audio/audiobuffer.cpp | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/media/audio/audiobuffer.cpp b/src/media/audio/audiobuffer.cpp
index 289161c591..2c9acffab1 100644
--- a/src/media/audio/audiobuffer.cpp
+++ b/src/media/audio/audiobuffer.cpp
@@ -244,8 +244,16 @@ size_t AudioBuffer::mix(const AudioBuffer& other, bool up /* = true */)
     for (unsigned i = 0; i < chan_num; i++) {
         unsigned src_chan = upmix ? std::min<unsigned>(i, other.samples_.size() - 1) : i;
 
-        for (unsigned j = 0; j < samp_num; j++)
-            samples_[i][j] += other.samples_[src_chan][j];
+        for (unsigned j = 0; j < samp_num; j++) {
+            // clamp result to min/max
+            // result must be larger than 16 bits to check for over/underflow
+            int32_t n = static_cast<int32_t>(samples_[i][j]) + static_cast<int32_t>(other.samples_[src_chan][j]);
+            if (n < std::numeric_limits<AudioSample>::min())
+                n = std::numeric_limits<AudioSample>::min();
+            else if (n > std::numeric_limits<AudioSample>::max())
+                n = std::numeric_limits<AudioSample>::max();
+            samples_[i][j] = n;
+        }
     }
 
     return samp_num;
-- 
GitLab