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

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

Issue 1685703004: Fix and simplify the power estimation in the IntelligibilityEnhancer (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@ie
Patch Set: Address turajs comments Created 4 years, 10 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
Index: webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
diff --git a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc b/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
index 9ed2d07584dec92c49ab31a0a4854f3d56dd8960..b4cf294a9e0170ca769852518795807cb9550782 100644
--- a/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
+++ b/webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.cc
@@ -8,13 +8,6 @@
* be found in the AUTHORS file in the root of the source tree.
*/
-//
-// Implements core class for intelligibility enhancer.
-//
-// Details of the model and algorithm can be found in the original paper:
-// http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=6882788
-//
-
#include "webrtc/modules/audio_processing/intelligibility/intelligibility_enhancer.h"
#include <math.h>
@@ -31,7 +24,7 @@ namespace webrtc {
namespace {
const size_t kErbResolution = 2;
-const int kWindowSizeMs = 2;
+const int kWindowSizeMs = 16;
const int kChunkSizeMs = 10; // Size provided by APM.
const float kClipFreq = 200.0f;
const float kConfigRho = 0.02f; // Default production and interpretation SNR.
@@ -48,35 +41,30 @@ float DotProduct(const float* a, const float* b, size_t length) {
return ret;
}
-// Computes the power across ERB filters from the power spectral density |var|.
+// Computes the power across ERB bands from the power spectral density |pow|.
// Stores it in |result|.
-void FilterVariance(const float* var,
- const std::vector<std::vector<float>>& filter_bank,
- float* result) {
+void MapToErbBands(const float* pow,
+ const std::vector<std::vector<float>>& filter_bank,
+ float* result) {
for (size_t i = 0; i < filter_bank.size(); ++i) {
RTC_DCHECK_GT(filter_bank[i].size(), 0u);
- result[i] = DotProduct(&filter_bank[i][0], var, filter_bank[i].size());
+ result[i] = DotProduct(&filter_bank[i][0], pow, filter_bank[i].size());
}
}
} // namespace
-using std::complex;
-using std::max;
-using std::min;
-using VarianceType = intelligibility::VarianceArray::StepType;
-
IntelligibilityEnhancer::TransformCallback::TransformCallback(
IntelligibilityEnhancer* parent)
: parent_(parent) {
}
void IntelligibilityEnhancer::TransformCallback::ProcessAudioBlock(
- const complex<float>* const* in_block,
+ const std::complex<float>* const* in_block,
size_t in_channels,
size_t frames,
size_t /* out_channels */,
- complex<float>* const* out_block) {
+ std::complex<float>* const* out_block) {
RTC_DCHECK_EQ(parent_->freqs_, frames);
for (size_t i = 0; i < in_channels; ++i) {
parent_->ProcessClearBlock(in_block[i], out_block[i]);
@@ -100,13 +88,10 @@ IntelligibilityEnhancer::IntelligibilityEnhancer(const Config& config)
num_render_channels_(config.num_render_channels),
analysis_rate_(config.analysis_rate),
active_(true),
- clear_variance_(freqs_,
- config.var_type,
- config.var_window_size,
- config.var_decay_rate),
+ clear_power_(freqs_, config.decay_rate),
noise_power_(freqs_, 0.f),
- filtered_clear_var_(new float[bank_size_]),
- filtered_noise_var_(new float[bank_size_]),
+ filtered_clear_pow_(new float[bank_size_]),
+ filtered_noise_pow_(new float[bank_size_]),
center_freqs_(new float[bank_size_]),
render_filter_bank_(CreateErbBank(freqs_)),
rho_(new float[bank_size_]),
@@ -119,12 +104,12 @@ IntelligibilityEnhancer::IntelligibilityEnhancer(const Config& config)
analysis_step_(0) {
RTC_DCHECK_LE(config.rho, 1.0f);
- memset(filtered_clear_var_.get(),
+ memset(filtered_clear_pow_.get(),
0,
- bank_size_ * sizeof(filtered_clear_var_[0]));
- memset(filtered_noise_var_.get(),
+ bank_size_ * sizeof(filtered_clear_pow_[0]));
+ memset(filtered_noise_pow_.get(),
0,
- bank_size_ * sizeof(filtered_noise_var_[0]));
+ bank_size_ * sizeof(filtered_noise_pow_[0]));
// Assumes all rho equal.
for (size_t i = 0; i < bank_size_; ++i) {
@@ -175,8 +160,9 @@ void IntelligibilityEnhancer::ProcessRenderAudio(float* const* audio,
}
}
-void IntelligibilityEnhancer::ProcessClearBlock(const complex<float>* in_block,
- complex<float>* out_block) {
+void IntelligibilityEnhancer::ProcessClearBlock(
+ const std::complex<float>* in_block,
+ std::complex<float>* out_block) {
if (block_count_ < 2) {
memset(out_block, 0, freqs_ * sizeof(*out_block));
++block_count_;
@@ -185,11 +171,9 @@ void IntelligibilityEnhancer::ProcessClearBlock(const complex<float>* in_block,
// TODO(ekm): Use VAD to |Step| and |AnalyzeClearBlock| only if necessary.
if (true) {
- clear_variance_.Step(in_block, false);
+ clear_power_.Step(in_block);
if (block_count_ % analysis_rate_ == analysis_rate_ - 1) {
- const float power_target = std::accumulate(
- clear_variance_.variance(), clear_variance_.variance() + freqs_, 0.f);
- AnalyzeClearBlock(power_target);
+ AnalyzeClearBlock();
++analysis_step_;
}
++block_count_;
@@ -200,23 +184,26 @@ void IntelligibilityEnhancer::ProcessClearBlock(const complex<float>* in_block,
}
}
-void IntelligibilityEnhancer::AnalyzeClearBlock(float power_target) {
- FilterVariance(clear_variance_.variance(),
- render_filter_bank_,
- filtered_clear_var_.get());
- FilterVariance(&noise_power_[0],
- capture_filter_bank_,
- filtered_noise_var_.get());
+void IntelligibilityEnhancer::AnalyzeClearBlock() {
+ const float* clear_power = clear_power_.Power();
+ MapToErbBands(clear_power,
+ render_filter_bank_,
+ filtered_clear_pow_.get());
+ MapToErbBands(&noise_power_[0],
+ capture_filter_bank_,
+ filtered_noise_pow_.get());
SolveForGainsGivenLambda(kLambdaTop, start_freq_, gains_eq_.get());
+ const float power_target = std::accumulate(
+ clear_power, clear_power + freqs_, 0.f);
const float power_top =
- DotProduct(gains_eq_.get(), filtered_clear_var_.get(), bank_size_);
+ DotProduct(gains_eq_.get(), filtered_clear_pow_.get(), bank_size_);
SolveForGainsGivenLambda(kLambdaBot, start_freq_, gains_eq_.get());
const float power_bot =
- DotProduct(gains_eq_.get(), filtered_clear_var_.get(), bank_size_);
+ DotProduct(gains_eq_.get(), filtered_clear_pow_.get(), bank_size_);
if (power_target >= power_bot && power_target <= power_top) {
SolveForLambda(power_target, power_bot, power_top);
UpdateErbGains();
- } // Else experiencing variance underflow, so do nothing.
+ } // Else experiencing power underflow, so do nothing.
}
void IntelligibilityEnhancer::SolveForLambda(float power_target,
@@ -235,7 +222,7 @@ void IntelligibilityEnhancer::SolveForLambda(float power_target,
const float lambda = lambda_bot + (lambda_top - lambda_bot) / 2.0f;
SolveForGainsGivenLambda(lambda, start_freq_, gains_eq_.get());
const float power =
- DotProduct(gains_eq_.get(), filtered_clear_var_.get(), bank_size_);
+ DotProduct(gains_eq_.get(), filtered_clear_pow_.get(), bank_size_);
if (power < power_target) {
lambda_bot = lambda;
} else {
@@ -288,22 +275,22 @@ std::vector<std::vector<float>> IntelligibilityEnhancer::CreateErbBank(
size_t lll, ll, rr, rrr;
static const size_t kOne = 1; // Avoids repeated static_cast<>s below.
lll = static_cast<size_t>(round(
- center_freqs_[max(kOne, i - lf) - 1] * num_freqs /
+ center_freqs_[std::max(kOne, i - lf) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
ll = static_cast<size_t>(round(
- center_freqs_[max(kOne, i) - 1] * num_freqs /
+ center_freqs_[std::max(kOne, i) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
- lll = min(num_freqs, max(lll, kOne)) - 1;
- ll = min(num_freqs, max(ll, kOne)) - 1;
+ lll = std::min(num_freqs, std::max(lll, kOne)) - 1;
+ ll = std::min(num_freqs, std::max(ll, kOne)) - 1;
rrr = static_cast<size_t>(round(
- center_freqs_[min(bank_size_, i + rf) - 1] * num_freqs /
+ center_freqs_[std::min(bank_size_, i + rf) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
rr = static_cast<size_t>(round(
- center_freqs_[min(bank_size_, i + 1) - 1] * num_freqs /
+ center_freqs_[std::min(bank_size_, i + 1) - 1] * num_freqs /
(0.5f * sample_rate_hz_)));
- rrr = min(num_freqs, max(rrr, kOne)) - 1;
- rr = min(num_freqs, max(rr, kOne)) - 1;
+ rrr = std::min(num_freqs, std::max(rrr, kOne)) - 1;
+ rr = std::min(num_freqs, std::max(rr, kOne)) - 1;
float step, element;
@@ -341,8 +328,8 @@ void IntelligibilityEnhancer::SolveForGainsGivenLambda(float lambda,
size_t start_freq,
float* sols) {
bool quadratic = (kConfigRho < 1.0f);
- const float* var_x0 = filtered_clear_var_.get();
- const float* var_n0 = filtered_noise_var_.get();
+ const float* pow_x0 = filtered_clear_pow_.get();
+ const float* pow_n0 = filtered_noise_pow_.get();
for (size_t n = 0; n < start_freq; ++n) {
sols[n] = 1.0f;
@@ -351,11 +338,11 @@ void IntelligibilityEnhancer::SolveForGainsGivenLambda(float lambda,
// Analytic solution for optimal gains. See paper for derivation.
for (size_t n = start_freq - 1; n < bank_size_; ++n) {
float alpha0, beta0, gamma0;
- gamma0 = 0.5f * rho_[n] * var_x0[n] * var_n0[n] +
- lambda * var_x0[n] * var_n0[n] * var_n0[n];
- beta0 = lambda * var_x0[n] * (2 - rho_[n]) * var_x0[n] * var_n0[n];
+ gamma0 = 0.5f * rho_[n] * pow_x0[n] * pow_n0[n] +
+ lambda * pow_x0[n] * pow_n0[n] * pow_n0[n];
+ beta0 = lambda * pow_x0[n] * (2 - rho_[n]) * pow_x0[n] * pow_n0[n];
if (quadratic) {
- alpha0 = lambda * var_x0[n] * (1 - rho_[n]) * var_x0[n] * var_x0[n];
+ alpha0 = lambda * pow_x0[n] * (1 - rho_[n]) * pow_x0[n] * pow_x0[n];
sols[n] =
(-beta0 - sqrtf(beta0 * beta0 - 4 * alpha0 * gamma0)) / (2 * alpha0);
} else {

Powered by Google App Engine
This is Rietveld 408576698