Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(721)

Unified Diff: webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc

Issue 1177953006: Initial SIE commit: migrating existing code (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc b/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
new file mode 100644
index 0000000000000000000000000000000000000000..e6fc3fa6a73b39aee82ea0e039e2ed6dc70a6f53
--- /dev/null
+++ b/webrtc/modules/audio_processing/intelligibility/intelligibility_utils.cc
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstring>
+
+using std::complex;
+
+namespace {
+
+// Return |current| changed towards |target|, with the change being at most
+// |limit|.
+inline float UpdateFactor(float target, float current, float limit) {
+ float delta = fabsf(target - current);
+ float sign = copysign(1.0f, target - current);
+ return current + sign * fminf(delta, limit);
+}
+
+// std::isfinite for complex numbers.
+inline bool cplxfinite(complex<float> c) {
+ return std::isfinite(c.real()) && std::isfinite(c.imag());
+}
+
+// std::isnormal for complex numbers.
+inline bool cplxnormal(complex<float> c) {
+ return std::isnormal(c.real()) && std::isnormal(c.imag());
+}
+
+// Apply a small fudge to degenerate complex values. The numbers in the array
+// were chosen randomly, so that even a series of all zeroes has some small
+// variability.
+inline complex<float> zerofudge(complex<float> c) {
+ const static complex<float> fudge[7] = {
+ {0.001f, 0.002f}, {0.008f, 0.001f}, {0.003f, 0.008f}, {0.0006f, 0.0009f},
+ {0.001f, 0.004f}, {0.003f, 0.004f}, {0.002f, 0.009f}
+ };
+ static int fudge_index = 0;
+ if (cplxfinite(c) && !cplxnormal(c)) {
+ fudge_index = (fudge_index + 1) % 7;
+ return c + fudge[fudge_index];
+ }
+ return c;
+}
+
+// Incremental mean computation. Return the mean of the series with the
+// mean |mean| with added |data|.
+inline complex<float> NewMean(complex<float> mean, complex<float> data,
+ int count) {
+ return mean + (data - mean) / static_cast<float>(count);
+}
+
+inline void AddToMean(complex<float> data, int count, complex<float>* mean) {
+ (*mean) = NewMean(*mean, data, count);
+}
+
+} // namespace
+
+using std::min;
+
+namespace webrtc {
+
+namespace intelligibility {
+
+static const int kWindowBlockSize = 10;
+
+VarianceArray::VarianceArray(int freqs, StepType type, int window_size,
+ float decay)
+ : running_mean_(new complex<float>[freqs]()),
+ running_mean_sq_(new complex<float>[freqs]()),
+ sub_running_mean_(new complex<float>[freqs]()),
+ sub_running_mean_sq_(new complex<float>[freqs]()),
+ variance_(new float[freqs]()),
+ conj_sum_(new float[freqs]()),
+ freqs_(freqs),
+ window_size_(window_size),
+ decay_(decay),
+ history_cursor_(0),
+ count_(0),
+ array_mean_(0.0f) {
+ history_.reset(new scoped_ptr<complex<float>[]>[freqs_]());
+ for (int i = 0; i < freqs_; ++i) {
+ history_[i].reset(new complex<float>[window_size_]());
+ }
+ subhistory_.reset(new scoped_ptr<complex<float>[]>[freqs_]());
+ for (int i = 0; i < freqs_; ++i) {
+ subhistory_[i].reset(new complex<float>[window_size_]());
+ }
+ subhistory_sq_.reset(new scoped_ptr<complex<float>[]>[freqs_]());
+ for (int i = 0; i < freqs_; ++i) {
+ subhistory_sq_[i].reset(new complex<float>[window_size_]());
+ }
+ switch (type) {
+ case kStepInfinite:
+ step_func_ = &VarianceArray::InfiniteStep;
+ break;
+ case kStepDecaying:
+ step_func_ = &VarianceArray::DecayStep;
+ break;
+ case kStepWindowed:
+ step_func_ = &VarianceArray::WindowedStep;
+ break;
+ case kStepBlocked:
+ step_func_ = &VarianceArray::BlockedStep;
+ break;
+ }
+}
+
+// Compute the variance with Welford's algorithm, adding some fudge to
+// the input in case of all-zeroes.
+void VarianceArray::InfiniteStep(const complex<float>* data, bool skip_fudge) {
+ array_mean_ = 0.0f;
+ ++count_;
+ for (int i = 0; i < freqs_; ++i) {
+ complex<float> sample = data[i];
+ if (!skip_fudge) {
+ sample = zerofudge(sample);
+ }
+ if (count_ == 1) {
+ running_mean_[i] = sample;
+ variance_[i] = 0.0f;
+ } else {
+ float old_sum = conj_sum_[i];
+ complex<float> old_mean = running_mean_[i];
+ running_mean_[i] = old_mean + (sample - old_mean) /
+ static_cast<float>(count_);
+ conj_sum_[i] = (old_sum + std::conj(sample - old_mean) *
+ (sample - running_mean_[i])).real();
+ variance_[i] = conj_sum_[i] / (count_ - 1); // + fudge[fudge_index].real();
+ if (skip_fudge && false) {
+ //variance_[i] -= fudge[fudge_index].real();
+ }
+ }
+ array_mean_ += (variance_[i] - array_mean_) / (i + 1);
+ }
+}
+
+// Compute the variance from the beginning, with exponential decaying of the
+// series data.
+void VarianceArray::DecayStep(const complex<float>* data, bool /*dummy*/) {
+ array_mean_ = 0.0f;
+ ++count_;
+ for (int i = 0; i < freqs_; ++i) {
+ complex<float> sample = data[i];
+ sample = zerofudge(sample);
+
+ if (count_ == 1) {
+ running_mean_[i] = sample;
+ running_mean_sq_[i] = sample * std::conj(sample);
+ variance_[i] = 0.0f;
+ } else {
+ complex<float> prev = running_mean_[i];
+ complex<float> prev2 = running_mean_sq_[i];
+ running_mean_[i] = decay_ * prev + (1.0f - decay_) * sample;
+ running_mean_sq_[i] = decay_ * prev2 +
+ (1.0f - decay_) * sample * std::conj(sample);
+ //variance_[i] = decay_ * variance_[i] + (1.0f - decay_) * (
+ // (sample - running_mean_[i]) * std::conj(sample - running_mean_[i])).real();
+ variance_[i] = (running_mean_sq_[i] - running_mean_[i] * std::conj(running_mean_[i])).real();
+ }
+
+ array_mean_ += (variance_[i] - array_mean_) / (i + 1);
+ }
+}
+
+// Windowed variance computation. On each step, the variances for the
+// window are recomputed from scratch, using Welford's algorithm.
+void VarianceArray::WindowedStep(const complex<float>* data, bool /*dummy*/) {
+ int num = min(count_ + 1, window_size_);
+ array_mean_ = 0.0f;
+ for (int i = 0; i < freqs_; ++i) {
+ complex<float> mean;
+ float conj_sum = 0.0f;
+
+ history_[i][history_cursor_] = data[i];
+
+ mean = history_[i][history_cursor_];
+ variance_[i] = 0.0f;
+ for (int j = 1; j < num; ++j) {
+ complex<float> sample = zerofudge(
+ history_[i][(history_cursor_ + j) % window_size_]);
+ sample = history_[i][(history_cursor_ + j) % window_size_];
+ float old_sum = conj_sum;
+ complex<float> old_mean = mean;
+
+ mean = old_mean + (sample - old_mean) / static_cast<float>(j + 1);
+ conj_sum = (old_sum + std::conj(sample - old_mean) *
+ (sample - mean)).real();
+ variance_[i] = conj_sum / (j);
+ }
+ array_mean_ += (variance_[i] - array_mean_) / (i + 1);
+ }
+ history_cursor_ = (history_cursor_ + 1) % window_size_;
+ ++count_;
+}
+
+// Variance with a window of blocks. Within each block, the variances are
+// recomputed from scratch at every stp, using |Var(X) = E(X^2) - E^2(X)|.
+// Once a block is filled with kWindowBlockSize samples, it is added to the
+// history window and a new block is started. The variances for the window
+// are recomputed from scratch at each of these transitions.
+void VarianceArray::BlockedStep(const complex<float>* data, bool /*dummy*/) {
+ int blocks = min(window_size_, history_cursor_);
+ for (int i = 0; i < freqs_; ++i) {
+ AddToMean(data[i], count_ + 1, &sub_running_mean_[i]);
+ AddToMean(data[i] * std::conj(data[i]), count_ + 1,
+ &sub_running_mean_sq_[i]);
+ subhistory_[i][history_cursor_ % window_size_] = sub_running_mean_[i];
+ subhistory_sq_[i][history_cursor_ % window_size_] = sub_running_mean_sq_[i];
+
+ variance_[i] = (NewMean(running_mean_sq_[i], sub_running_mean_sq_[i],
+ blocks) -
+ NewMean(running_mean_[i], sub_running_mean_[i], blocks) *
+ std::conj(NewMean(running_mean_[i], sub_running_mean_[i],
+ blocks))).real();
+ if (count_ == kWindowBlockSize - 1) {
+ sub_running_mean_[i] = complex<float>(0.0f, 0.0f);
+ sub_running_mean_sq_[i] = complex<float>(0.0f, 0.0f);
+ running_mean_[i] = complex<float>(0.0f, 0.0f);
+ running_mean_sq_[i] = complex<float>(0.0f, 0.0f);
+ for (int j = 0; j < min(window_size_, history_cursor_); ++j) {
+ AddToMean(subhistory_[i][j], j, &running_mean_[i]);
+ AddToMean(subhistory_sq_[i][j], j, &running_mean_sq_[i]);
+ }
+ ++history_cursor_;
+ }
+ }
+ ++count_;
+ if (count_ == kWindowBlockSize) {
+ count_ = 0;
+ }
+}
+
+void VarianceArray::Clear() {
+ memset(running_mean_.get(), 0, sizeof(*running_mean_.get()) * freqs_);
+ memset(running_mean_sq_.get(), 0, sizeof(*running_mean_sq_.get()) * freqs_);
+ memset(variance_.get(), 0, sizeof(*variance_.get()) * freqs_);
+ memset(conj_sum_.get(), 0, sizeof(*conj_sum_.get()) * freqs_);
+ history_cursor_ = 0;
+ count_ = 0;
+ array_mean_ = 0.0f;
+}
+
+void VarianceArray::ApplyScale(float scale) {
+ array_mean_ = 0.0f;
+ for (int i = 0; i < freqs_; ++i) {
+ variance_[i] *= scale * scale;
+ array_mean_ += (variance_[i] - array_mean_) / (i + 1);
+ }
+}
+
+GainApplier::GainApplier(int freqs, float change_limit)
+ : freqs_(freqs),
+ change_limit_(change_limit),
+ target_(new float[freqs]()),
+ current_(new float[freqs]()) {
+ for (int i = 0; i < freqs; ++i) {
+ target_[i] = 1.0f;
+ current_[i] = 1.0f;
+ }
+}
+
+void GainApplier::Apply(const complex<float>* in_block,
+ complex<float>* out_block) {
+ for (int i = 0; i < freqs_; ++i) {
+ float factor = sqrtf(fabsf(current_[i]));
+ if (!std::isnormal(factor)) {
+ factor = 1.0f;
+ }
+ out_block[i] = factor * in_block[i];
+ current_[i] = UpdateFactor(target_[i], current_[i], change_limit_);
+ }
+}
+
+} // namespace intelligibility
+
+} // namespace webrtc
+
« no previous file with comments | « webrtc/modules/audio_processing/intelligibility/intelligibility_utils.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698