Chromium Code Reviews| 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) { |
|
turaj
2016/02/12 23:12:35
Can we get rid off this "if(true)"?
aluebs-webrtc
2016/02/13 01:47:49
I did that in the next CL: https://codereview.webr
|
| - 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 { |