19a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org/* 29a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. 39a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org * 49a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org * Use of this source code is governed by a BSD-style license 59a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org * that can be found in the LICENSE file in the root of the source 69a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org * tree. An additional intellectual property rights grant can be found 79a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org * in the file PATENTS. All contributing project authors may 89a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org * be found in the AUTHORS file in the root of the source tree. 99a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org */ 109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 11e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/background_noise.h" 129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <assert.h> 143f45c2e0ac4cb280f941efa3a3476895795e3dd6pbos@webrtc.org#include <string.h> // memcpy 159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include <algorithm> // min, max 179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" 19e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/audio_multi_vector.h" 20e5abc854f3dc47de16067c2a41476c39b7626722henrik.lundin@webrtc.org#include "webrtc/modules/audio_coding/neteq/post_decode_vad.h" 219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgnamespace webrtc { 239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 24dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.orgBackgroundNoise::BackgroundNoise(size_t num_channels) 25dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org : num_channels_(num_channels), 26dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org channel_parameters_(new ChannelParameters[num_channels_]), 27d8b9cd100e889aa8b4a7d8b391ebd39a1298913ehenrik.lundin@webrtc.org mode_(NetEq::kBgnOn) { 28dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org Reset(); 29dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org} 30dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org 31dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.orgBackgroundNoise::~BackgroundNoise() {} 32dd1b19d950158fbb1d7e1792c4db95460d5f8c49pbos@webrtc.org 339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::Reset() { 349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org initialized_ = false; 359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org for (size_t channel = 0; channel < num_channels_; ++channel) { 369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org channel_parameters_[channel].Reset(); 379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Keep _bgnMode as it is. 399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 410e9c399746f45ceaf46f12b11ba93c09cca0c2bbhenrik.lundin@webrtc.orgvoid BackgroundNoise::Update(const AudioMultiVector& input, 429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org const PostDecodeVad& vad) { 439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if (vad.running() && vad.active_speech()) { 449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Do not update the background noise parameters if we know that the signal 459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // is active speech. 469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return; 479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t auto_correlation[kMaxLpcOrder + 1]; 509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int16_t fiter_output[kMaxLpcOrder + kResidualLength]; 519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int16_t reflection_coefficients[kMaxLpcOrder]; 529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int16_t lpc_coefficients[kMaxLpcOrder + 1]; 539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) { 559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org ChannelParameters& parameters = channel_parameters_[channel_ix]; 569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0}; 579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder]; 589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org memcpy(temp_signal, 599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org &input[channel_ix][input.Size() - kVecLen], 609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org sizeof(int16_t) * kVecLen); 619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t sample_energy = CalculateAutoCorrelation(temp_signal, kVecLen, 639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org auto_correlation); 649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if ((!vad.running() && 669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org sample_energy < parameters.energy_update_threshold) || 679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org (vad.running() && !vad.active_speech())) { 689a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Generate LPC coefficients. 699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if (auto_correlation[0] > 0) { 709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Regardless of whether the filter is actually updated or not, 719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // update energy threshold levels, since we have in fact observed 729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // a low energy signal. 739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if (sample_energy < parameters.energy_update_threshold) { 749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Never go under 1.0 in average sample energy. 759a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.energy_update_threshold = std::max(sample_energy, 1); 769a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.low_energy_update_threshold = 0; 779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Only update BGN if filter is stable, i.e., if return value from 809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Levinson-Durbin function is 1. 819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients, 829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org reflection_coefficients, 839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org kMaxLpcOrder) != 1) { 849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return; 859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } else { 879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Center value in auto-correlation is not positive. Do not update. 889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return; 899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Generate the CNG gain factor by looking at the energy of the residual. 929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength, 939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org fiter_output, lpc_coefficients, 949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org kMaxLpcOrder + 1, kResidualLength); 959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t residual_energy = WebRtcSpl_DotProductWithScale(fiter_output, 969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org fiter_output, 979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org kResidualLength, 989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 0); 999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Check spectral flatness. 1019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Comparing the residual variance with the input signal variance tells 1029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // if the spectrum is flat or not. 1039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // If 20 * residual_energy >= sample_energy << 6, the spectrum is flat 1049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // enough. Also ensure that the energy is non-zero. 1059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if ((residual_energy * 20 >= (sample_energy << 6)) && 1069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org (sample_energy > 0)) { 1079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Spectrum is flat enough; save filter parameters. 1089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // |temp_signal| + |kVecLen| - |kMaxLpcOrder| points at the first of the 1099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // |kMaxLpcOrder| samples in the residual signal, which will form the 1109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // filter state for the next noise generation. 1119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org SaveParameters(channel_ix, lpc_coefficients, 1129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org temp_signal + kVecLen - kMaxLpcOrder, sample_energy, 1139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org residual_energy); 1149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 1159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } else { 1169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Will only happen if post-decode VAD is disabled and |sample_energy| is 1179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // not low enough. Increase the threshold for update so that it increases 1189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // by a factor 4 in 4 seconds. 1199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org IncrementEnergyThreshold(channel_ix, sample_energy); 1209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 1219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 1229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return; 1239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint32_t BackgroundNoise::Energy(size_t channel) const { 1269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return channel_parameters_[channel].energy; 1289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) { 1319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org channel_parameters_[channel].mute_factor = value; 1339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint16_t BackgroundNoise::MuteFactor(size_t channel) const { 1369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return channel_parameters_[channel].mute_factor; 1389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgconst int16_t* BackgroundNoise::Filter(size_t channel) const { 1419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return channel_parameters_[channel].filter; 1439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgconst int16_t* BackgroundNoise::FilterState(size_t channel) const { 1469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return channel_parameters_[channel].filter_state; 1489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::SetFilterState(size_t channel, const int16_t* input, 1519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org size_t length) { 1529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org length = std::min(length, static_cast<size_t>(kMaxLpcOrder)); 1549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org memcpy(channel_parameters_[channel].filter_state, input, 1559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org length * sizeof(int16_t)); 1569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint16_t BackgroundNoise::Scale(size_t channel) const { 1599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return channel_parameters_[channel].scale; 1619a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1629a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint16_t BackgroundNoise::ScaleShift(size_t channel) const { 1639a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1649a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return channel_parameters_[channel].scale_shift; 1659a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1669a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1679a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgint32_t BackgroundNoise::CalculateAutoCorrelation( 168045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org const int16_t* signal, int length, int32_t* auto_correlation) const { 1699a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int16_t signal_max = WebRtcSpl_MaxAbsValueW16(signal, length); 1709a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int correlation_scale = kLogVecLen - 1719a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org WebRtcSpl_NormW32(signal_max * signal_max); 1729a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org correlation_scale = std::max(0, correlation_scale); 1739a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1749a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org static const int kCorrelationStep = -1; 175045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org WebRtcSpl_CrossCorrelation(auto_correlation, signal, signal, length, 176045e45efeca8776975254550137ec65268aadb54turaj@webrtc.org kMaxLpcOrder + 1, correlation_scale, 1779a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org kCorrelationStep); 1789a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1799a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Number of shifts to normalize energy to energy/sample. 1809a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int energy_sample_shift = kLogVecLen - correlation_scale; 1819a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org return auto_correlation[0] >> energy_sample_shift; 1829a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 1839a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 1849a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::IncrementEnergyThreshold(size_t channel, 1859a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t sample_energy) { 1869a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // TODO(hlundin): Simplify the below threshold update. What this code 1879a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // does is simply "threshold += (increment * threshold) >> 16", but due 1889a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // to the limited-width operations, it is not exactly the same. The 1899a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // difference should be inaudible, but bit-exactness would not be 1909a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // maintained. 1919a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 1929a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org ChannelParameters& parameters = channel_parameters_[channel]; 1939a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t temp_energy = 1949a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org WEBRTC_SPL_MUL_16_16_RSFT(kThresholdIncrement, 1959a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.low_energy_update_threshold, 16); 1969a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org temp_energy += kThresholdIncrement * 1979a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org (parameters.energy_update_threshold & 0xFF); 1989a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org temp_energy += (kThresholdIncrement * 1999a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org ((parameters.energy_update_threshold>>8) & 0xFF)) << 8; 2009a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.low_energy_update_threshold += temp_energy; 2019a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2029a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.energy_update_threshold += kThresholdIncrement * 2039a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org (parameters.energy_update_threshold>>16); 2049a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.energy_update_threshold += 2059a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.low_energy_update_threshold >> 16; 2069a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.low_energy_update_threshold = 2079a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.low_energy_update_threshold & 0x0FFFF; 2089a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2099a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Update maximum energy. 2109a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Decrease by a factor 1/1024 each time. 2119a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.max_energy = parameters.max_energy - 2129a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org (parameters.max_energy >> 10); 2139a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if (sample_energy > parameters.max_energy) { 2149a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.max_energy = sample_energy; 2159a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 2169a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2179a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Set |energy_update_threshold| to no less than 60 dB lower than 2189a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // |max_energy_|. Adding 524288 assures proper rounding. 2199a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20; 2209a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if (energy_update_threshold > parameters.energy_update_threshold) { 2219a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.energy_update_threshold = energy_update_threshold; 2229a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 2239a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 2249a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2259a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.orgvoid BackgroundNoise::SaveParameters(size_t channel, 2269a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org const int16_t* lpc_coefficients, 2279a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org const int16_t* filter_state, 2289a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t sample_energy, 2299a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int32_t residual_energy) { 2309a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(channel < num_channels_); 2319a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org ChannelParameters& parameters = channel_parameters_[channel]; 2329a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org memcpy(parameters.filter, lpc_coefficients, 2339a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org (kMaxLpcOrder+1) * sizeof(int16_t)); 2349a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org memcpy(parameters.filter_state, filter_state, 2359a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org kMaxLpcOrder * sizeof(int16_t)); 2369a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Save energy level and update energy threshold levels. 2379a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Never get under 1.0 in average sample energy. 2389a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.energy = std::max(sample_energy, 1); 2399a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.energy_update_threshold = parameters.energy; 2409a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.low_energy_update_threshold = 0; 2419a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2429a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Normalize residual_energy to 29 or 30 bits before sqrt. 2439a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org int norm_shift = WebRtcSpl_NormW32(residual_energy) - 1; 2449a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org if (norm_shift & 0x1) { 2459a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org norm_shift -= 1; // Even number of shifts required. 2469a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org } 2479a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org assert(norm_shift >= 0); // Should always be positive. 2489a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org residual_energy = residual_energy << norm_shift; 2499a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2509a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Calculate scale and shift factor. 2519a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.scale = WebRtcSpl_SqrtFloor(residual_energy); 2529a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Add 13 to the |scale_shift_|, since the random numbers table is in 2539a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // Q13. 2549a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org // TODO(hlundin): Move the "13" to where the |scale_shift_| is used? 2559a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org parameters.scale_shift = 13 + ((kLogResidualLength + norm_shift) / 2); 2569a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2579a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org initialized_ = true; 2589a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} 2599a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org 2609a400812ca0006d12e538d465ab6728a8ecd07aahenrik.lundin@webrtc.org} // namespace webrtc 261