Index: webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
diff --git a/webrtc/modules/audio_processing/echo_detector/echo_detector.cc b/webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
index 3885c1fb0716389c9f6d6293761cefaa9b9db2fa..22d31ea7e9b2ff543364ed3eec06f25807a5fa55 100644 |
--- a/webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
+++ b/webrtc/modules/audio_processing/echo_detector/echo_detector.cc |
@@ -8,21 +8,141 @@ |
* be found in the AUTHORS file in the root of the source tree. |
*/ |
+#include "webrtc/base/checks.h" |
#include "webrtc/modules/audio_processing/echo_detector/echo_detector.h" |
hlundin-webrtc
2016/10/14 08:00:39
Aways include the corresponding .h file before any
ivoc
2016/10/17 16:05:08
Done.
|
+#include <math.h> |
hlundin-webrtc
2016/10/14 08:00:39
System includes go before own project's includes (
ivoc
2016/10/17 16:05:07
Done.
|
+ |
+namespace { |
+ |
+float power(const float* farend, size_t nr_samples) { |
hlundin-webrtc
2016/10/14 08:00:39
Power with capital P.
hlundin-webrtc
2016/10/14 08:00:39
With my suggestion in the previous CL to use Array
peah-webrtc
2016/10/14 08:18:57
It is not superimportant, but if you instead use t
peah-webrtc
2016/10/14 08:18:58
Capital P in the function name.
peah-webrtc
2016/10/14 08:18:58
Since you are using this for both farend and neare
kwiberg-webrtc
2016/10/14 08:58:54
The docs suggest that, unless you ask it nicely fo
hlundin-webrtc
2016/10/14 09:15:28
But the current implementation does float * float
peah-webrtc
2016/10/14 13:39:40
In this case, nr_samples is limited to 160. I real
kwiberg-webrtc
2016/10/14 20:33:33
I was going to say that the current implementation
kwiberg-webrtc
2016/10/14 20:33:33
OK, doing it all in float would simplify things. :
hlundin-webrtc
2016/10/14 21:15:46
It seems to me that storing the intermediate as fl
ivoc
2016/10/17 16:05:07
Thanks for all the comments, this seems to be a po
hlundin-webrtc
2016/10/17 18:49:39
Good call!
|
+ double result = 0.; |
peah-webrtc
2016/10/14 08:18:58
I think you can use float for the power computatio
ivoc
2016/10/17 16:05:07
Done.
|
+ for (size_t i = 0; i < nr_samples; i++) { |
peah-webrtc
2016/10/14 08:18:58
++i is faster
hlundin-webrtc
2016/10/14 21:15:46
Not for a simple scalar. https://google.github.io/
|
+ result += farend[i] * farend[i]; |
+ } |
+ return static_cast<float>(result); |
peah-webrtc
2016/10/14 08:18:58
If you use float, you don't need the cast.
|
+} |
+ |
+} // namespace |
+ |
namespace webrtc { |
-void EchoDetector::BufferFarend(const float* /*farend*/, |
- size_t /*num_samples*/) { |
- // TODO(ivoc): Add implementation. |
+void MeanVarianceEstimator::UpdateEstimate(float value) { |
+ mean_ = (1.f - alpha_) * mean_ + alpha_ * value; |
+ variance_ = |
+ (1.f - alpha_) * variance_ + alpha_ * (value - mean_) * (value - mean_); |
+} |
+ |
+float MeanVarianceEstimator::SigmaEstimate() { |
+ // Variance is >= 0, so this is okay. |
hlundin-webrtc
2016/10/14 08:00:39
DCHECK this assumption.
ivoc
2016/10/17 16:05:08
Done.
|
+ return sqrtf(variance_); |
+} |
+ |
+float MeanVarianceEstimator::MeanEstimate() { |
+ return mean_; |
+} |
+ |
+void MeanVarianceEstimator::Clear() { |
+ mean_ = 0.f; |
+ variance_ = 0.f; |
+} |
+ |
+void CovarianceEstimator::UpdateCovarianceEstimate(float x, |
peah-webrtc
2016/10/14 08:18:58
I don't think that covariance is fully correct her
ivoc
2016/10/17 16:05:07
Done.
|
+ float x_mean, |
+ float x_sigma, |
+ float y, |
+ float y_mean, |
+ float y_sigma) { |
+ covariance_ = |
+ (1.f - alpha_) * covariance_ + alpha_ * (x - x_mean) * (y - y_mean); |
peah-webrtc
2016/10/14 08:18:58
The style guide mentions that abbreviations should
ivoc
2016/10/17 16:05:07
I chose normalized_cross_correlation.
|
+ PCC_ = covariance_ / (x_sigma * y_sigma + .0001f); |
+} |
+ |
+float CovarianceEstimator::PCCEstimate() { |
peah-webrtc
2016/10/14 08:18:58
Please change this method name to avoid the abbrev
ivoc
2016/10/17 16:05:07
Done.
|
+ return PCC_; |
+} |
+ |
+void CovarianceEstimator::Clear() { |
+ covariance_ = 0.f; |
+ PCC_ = 0.f; |
+} |
+ |
+CircularBuffer::CircularBuffer(int size) : buffer_(size), size_(size) {} |
+CircularBuffer::~CircularBuffer() {} |
hlundin-webrtc
2016/10/14 08:00:39
Replace {} with "= default".
peah-webrtc
2016/10/14 08:18:57
Alternatively you can use = default;
ivoc
2016/10/17 16:05:07
Done.
|
+ |
+void CircularBuffer::Insert(float value) { |
+ buffer_[next_insertion_index_] = value; |
peah-webrtc
2016/10/14 08:18:57
Please add a DCHECK that next_insertion_index_ < b
ivoc
2016/10/17 16:05:07
Done.
|
+ next_insertion_index_++; |
peah-webrtc
2016/10/14 08:18:57
++next_insertion_index_ is faster.
ivoc
2016/10/17 16:05:07
For scalars I don't think it is, but you're right
|
+ next_insertion_index_ %= size_; |
peah-webrtc
2016/10/14 08:18:58
buffer_.size() here and elsewhere.
ivoc
2016/10/17 16:05:07
Done.
|
+} |
+ |
+float CircularBuffer::GetValue(int delay) { |
+ RTC_DCHECK(delay >= 0 && delay < size_); |
hlundin-webrtc
2016/10/14 08:00:39
Separate into two DCHECKs to get better printouts.
ivoc
2016/10/17 16:05:07
Since I changed delay to size_t, the >=0 check doe
|
+ const int index = (size_ + next_insertion_index_ - delay - 1) % size_; |
hlundin-webrtc
2016/10/14 08:00:39
size_t
ivoc
2016/10/17 16:05:07
Done.
|
+ return buffer_[index]; |
peah-webrtc
2016/10/14 08:18:58
Please add a DCHECK that index < buffer_.size() an
ivoc
2016/10/17 16:05:07
Done.
|
+} |
+ |
+void CircularBuffer::Clear() { |
+ std::fill(buffer_.begin(), buffer_.end(), 0.f); |
+ next_insertion_index_ = 0; |
+} |
+ |
+EchoDetector::EchoDetector() |
+ : render_buffer_(render_buffer_size_), |
peah-webrtc
2016/10/14 08:18:58
Do you need to have these in the initializer list?
ivoc
2016/10/17 16:05:07
Good idea!
|
+ render_power_(lookback_periods_), |
+ render_power_mean_(lookback_periods_), |
+ render_power_sigma_(lookback_periods_) {} |
+ |
+EchoDetector::~EchoDetector() {} |
hlundin-webrtc
2016/10/14 08:00:39
= default
peah-webrtc
2016/10/14 08:18:58
Alternatively you can use = default;
ivoc
2016/10/17 16:05:07
Done.
|
+ |
+void EchoDetector::BufferFarend(const float* farend, size_t num_samples) { |
peah-webrtc
2016/10/14 08:18:57
After some discussions I think we will be changing
ivoc
2016/10/17 16:05:07
Done.
|
+ float pow = power(farend, num_samples); |
peah-webrtc
2016/10/14 08:18:57
If you change the name of the power method to Powe
ivoc
2016/10/17 16:05:07
Done.
|
+ render_buffer_.Insert(pow); |
+ render_buffer_delay_ = |
+ std::min(render_buffer_delay_ + 1, render_buffer_size_ - 1); |
peah-webrtc
2016/10/14 08:18:57
Why is this minimum needed?
|
+} |
+ |
+void EchoDetector::Process(const float* nearend, size_t num_samples) { |
+ const float cap_pow = power(nearend, num_samples); |
hlundin-webrtc
2016/10/14 08:00:39
cap_* sounds like a value capped by something.
peah-webrtc
2016/10/14 08:18:57
I think that along the style guide abbreviation ru
ivoc
2016/10/17 16:05:08
Done.
|
+ capture_variance_.UpdateEstimate(cap_pow); |
+ const float cap_mean = capture_variance_.MeanEstimate(); |
+ const float cap_sigma = capture_variance_.SigmaEstimate(); |
+ float echo_likelihood = 0.f; |
+ |
+ const float latest_ren_pow = render_buffer_.GetValue(render_buffer_delay_); |
peah-webrtc
2016/10/14 08:18:58
This delay is only used to access the most recentl
ivoc
2016/10/17 16:05:07
As discussed offline, I moved the buffer size into
|
+ render_buffer_delay_ = std::max(0, render_buffer_delay_ - 1); |
+ render_variance_.UpdateEstimate(latest_ren_pow); |
+ render_power_.Insert(latest_ren_pow); |
+ render_power_mean_.Insert(render_variance_.MeanEstimate()); |
+ render_power_sigma_.Insert(render_variance_.SigmaEstimate()); |
+ |
+ for (int delay = 0; delay < lookback_periods_; delay++) { |
hlundin-webrtc
2016/10/14 08:00:39
size_t
peah-webrtc
2016/10/14 08:18:57
size_t ?
peah-webrtc
2016/10/14 08:18:57
size_t
peah-webrtc
2016/10/14 08:18:58
++delay
peah-webrtc
2016/10/14 08:18:58
This name is not fully clear to me. What is meant
peah-webrtc
2016/10/14 08:18:58
Use covariance_.size()
ivoc
2016/10/17 16:05:07
Done.
|
+ const float ren_pow = render_power_.GetValue(delay); |
+ const float ren_mean = render_power_mean_.GetValue(delay); |
+ const float ren_sigma = render_power_sigma_.GetValue(delay); |
+ covariance_[delay].UpdateCovarianceEstimate(cap_pow, cap_mean, cap_sigma, |
+ ren_pow, ren_mean, ren_sigma); |
+ echo_likelihood = |
hlundin-webrtc
2016/10/14 08:00:39
No need for the local variable echo_likelihood. Yo
ivoc
2016/10/17 16:05:08
Done.
|
+ std::max(echo_likelihood, covariance_[delay].PCCEstimate()); |
+ } |
+ echo_likelihood_ = echo_likelihood; |
} |
-void EchoDetector::Process(const float* /*nearend*/, size_t /*num_samples*/) { |
- // TODO(ivoc): Add implementation. |
+void EchoDetector::Initialize(int sample_rate_hz) { |
hlundin-webrtc
2016/10/14 08:00:39
sample_rate_hz not used? Delete it.
ivoc
2016/10/17 16:05:08
Done.
|
+ render_buffer_.Clear(); |
+ render_power_.Clear(); |
+ render_power_mean_.Clear(); |
+ render_power_sigma_.Clear(); |
+ render_variance_.Clear(); |
+ capture_variance_.Clear(); |
+ for (auto& cov : covariance_) { |
+ cov.Clear(); |
+ } |
+ echo_likelihood_ = 0.f; |
} |
-void EchoDetector::Initialize(int /*sample_rate_hz*/) { |
- // TODO(ivoc): Add implementation. |
+float EchoDetector::EchoLikelihood() { |
peah-webrtc
2016/10/14 08:18:57
const
ivoc
2016/10/17 16:05:08
Done.
|
+ return echo_likelihood_; |
} |
} // namespace webrtc |