blob: 08c278e14a7493e45145443933bf548463c2c195 [file] [log] [blame]
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +00001/*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/audio_coding/neteq/background_noise.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000012
13#include <assert.h>
pbos@webrtc.org12dc1a32013-08-05 16:22:53 +000014#include <string.h> // memcpy
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000015
16#include <algorithm> // min, max
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000017
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "common_audio/signal_processing/include/signal_processing_library.h"
19#include "modules/audio_coding/neteq/audio_multi_vector.h"
20#include "modules/audio_coding/neteq/cross_correlation.h"
21#include "modules/audio_coding/neteq/post_decode_vad.h"
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000022
23namespace webrtc {
24
Peter Kastingdce40cf2015-08-24 14:52:23 -070025// static
26const size_t BackgroundNoise::kMaxLpcOrder;
27
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000028BackgroundNoise::BackgroundNoise(size_t num_channels)
29 : num_channels_(num_channels),
Henrik Lundin67190172018-04-20 15:34:48 +020030 channel_parameters_(new ChannelParameters[num_channels_]) {
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000031 Reset();
32}
33
34BackgroundNoise::~BackgroundNoise() {}
35
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000036void BackgroundNoise::Reset() {
37 initialized_ = false;
38 for (size_t channel = 0; channel < num_channels_; ++channel) {
39 channel_parameters_[channel].Reset();
40 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000041}
42
henrik.lundin@webrtc.orgfd11bbf2013-09-30 20:38:44 +000043void BackgroundNoise::Update(const AudioMultiVector& input,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000044 const PostDecodeVad& vad) {
45 if (vad.running() && vad.active_speech()) {
46 // Do not update the background noise parameters if we know that the signal
47 // is active speech.
48 return;
49 }
50
51 int32_t auto_correlation[kMaxLpcOrder + 1];
52 int16_t fiter_output[kMaxLpcOrder + kResidualLength];
53 int16_t reflection_coefficients[kMaxLpcOrder];
54 int16_t lpc_coefficients[kMaxLpcOrder + 1];
55
56 for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
57 ChannelParameters& parameters = channel_parameters_[channel_ix];
58 int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
59 int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
minyue-webrtc79553cb2016-05-10 19:55:56 +020060 input[channel_ix].CopyTo(kVecLen, input.Size() - kVecLen, temp_signal);
Yves Gerey665174f2018-06-19 15:03:05 +020061 int32_t sample_energy =
62 CalculateAutoCorrelation(temp_signal, kVecLen, auto_correlation);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000063
64 if ((!vad.running() &&
Yves Gerey665174f2018-06-19 15:03:05 +020065 sample_energy < parameters.energy_update_threshold) ||
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000066 (vad.running() && !vad.active_speech())) {
67 // Generate LPC coefficients.
68 if (auto_correlation[0] > 0) {
69 // Regardless of whether the filter is actually updated or not,
70 // update energy threshold levels, since we have in fact observed
71 // a low energy signal.
72 if (sample_energy < parameters.energy_update_threshold) {
73 // Never go under 1.0 in average sample energy.
74 parameters.energy_update_threshold = std::max(sample_energy, 1);
75 parameters.low_energy_update_threshold = 0;
76 }
77
78 // Only update BGN if filter is stable, i.e., if return value from
79 // Levinson-Durbin function is 1.
80 if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
81 reflection_coefficients,
82 kMaxLpcOrder) != 1) {
83 return;
84 }
85 } else {
86 // Center value in auto-correlation is not positive. Do not update.
87 return;
88 }
89
90 // Generate the CNG gain factor by looking at the energy of the residual.
91 WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
92 fiter_output, lpc_coefficients,
93 kMaxLpcOrder + 1, kResidualLength);
Yves Gerey665174f2018-06-19 15:03:05 +020094 int32_t residual_energy = WebRtcSpl_DotProductWithScale(
95 fiter_output, fiter_output, kResidualLength, 0);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000096
97 // Check spectral flatness.
98 // Comparing the residual variance with the input signal variance tells
99 // if the spectrum is flat or not.
henrik.lundina67e5f52017-03-01 03:06:50 -0800100 // If 5 * residual_energy >= 16 * sample_energy, the spectrum is flat
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000101 // enough. Also ensure that the energy is non-zero.
henrik.lundina67e5f52017-03-01 03:06:50 -0800102 if ((sample_energy > 0) &&
103 (int64_t{5} * residual_energy >= int64_t{16} * sample_energy)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000104 // Spectrum is flat enough; save filter parameters.
105 // |temp_signal| + |kVecLen| - |kMaxLpcOrder| points at the first of the
106 // |kMaxLpcOrder| samples in the residual signal, which will form the
107 // filter state for the next noise generation.
108 SaveParameters(channel_ix, lpc_coefficients,
109 temp_signal + kVecLen - kMaxLpcOrder, sample_energy,
110 residual_energy);
111 }
112 } else {
113 // Will only happen if post-decode VAD is disabled and |sample_energy| is
114 // not low enough. Increase the threshold for update so that it increases
115 // by a factor 4 in 4 seconds.
116 IncrementEnergyThreshold(channel_ix, sample_energy);
117 }
118 }
119 return;
120}
121
122int32_t BackgroundNoise::Energy(size_t channel) const {
123 assert(channel < num_channels_);
124 return channel_parameters_[channel].energy;
125}
126
127void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
128 assert(channel < num_channels_);
129 channel_parameters_[channel].mute_factor = value;
130}
131
132int16_t BackgroundNoise::MuteFactor(size_t channel) const {
133 assert(channel < num_channels_);
134 return channel_parameters_[channel].mute_factor;
135}
136
137const int16_t* BackgroundNoise::Filter(size_t channel) const {
138 assert(channel < num_channels_);
139 return channel_parameters_[channel].filter;
140}
141
142const int16_t* BackgroundNoise::FilterState(size_t channel) const {
143 assert(channel < num_channels_);
144 return channel_parameters_[channel].filter_state;
145}
146
Yves Gerey665174f2018-06-19 15:03:05 +0200147void BackgroundNoise::SetFilterState(size_t channel,
148 const int16_t* input,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000149 size_t length) {
150 assert(channel < num_channels_);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700151 length = std::min(length, kMaxLpcOrder);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000152 memcpy(channel_parameters_[channel].filter_state, input,
153 length * sizeof(int16_t));
154}
155
156int16_t BackgroundNoise::Scale(size_t channel) const {
157 assert(channel < num_channels_);
158 return channel_parameters_[channel].scale;
159}
160int16_t BackgroundNoise::ScaleShift(size_t channel) const {
161 assert(channel < num_channels_);
162 return channel_parameters_[channel].scale_shift;
163}
164
165int32_t BackgroundNoise::CalculateAutoCorrelation(
Yves Gerey665174f2018-06-19 15:03:05 +0200166 const int16_t* signal,
167 size_t length,
168 int32_t* auto_correlation) const {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000169 static const int kCorrelationStep = -1;
minyue53ff70f2016-05-02 01:50:30 -0700170 const int correlation_scale =
171 CrossCorrelationWithAutoShift(signal, signal, length, kMaxLpcOrder + 1,
172 kCorrelationStep, auto_correlation);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000173
174 // Number of shifts to normalize energy to energy/sample.
175 int energy_sample_shift = kLogVecLen - correlation_scale;
176 return auto_correlation[0] >> energy_sample_shift;
177}
178
179void BackgroundNoise::IncrementEnergyThreshold(size_t channel,
180 int32_t sample_energy) {
181 // TODO(hlundin): Simplify the below threshold update. What this code
182 // does is simply "threshold += (increment * threshold) >> 16", but due
183 // to the limited-width operations, it is not exactly the same. The
184 // difference should be inaudible, but bit-exactness would not be
185 // maintained.
186 assert(channel < num_channels_);
187 ChannelParameters& parameters = channel_parameters_[channel];
188 int32_t temp_energy =
Yves Gerey665174f2018-06-19 15:03:05 +0200189 (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
190 temp_energy +=
191 kThresholdIncrement * (parameters.energy_update_threshold & 0xFF);
192 temp_energy +=
193 (kThresholdIncrement * ((parameters.energy_update_threshold >> 8) & 0xFF))
194 << 8;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000195 parameters.low_energy_update_threshold += temp_energy;
196
Yves Gerey665174f2018-06-19 15:03:05 +0200197 parameters.energy_update_threshold +=
198 kThresholdIncrement * (parameters.energy_update_threshold >> 16);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000199 parameters.energy_update_threshold +=
200 parameters.low_energy_update_threshold >> 16;
201 parameters.low_energy_update_threshold =
202 parameters.low_energy_update_threshold & 0x0FFFF;
203
204 // Update maximum energy.
205 // Decrease by a factor 1/1024 each time.
Yves Gerey665174f2018-06-19 15:03:05 +0200206 parameters.max_energy = parameters.max_energy - (parameters.max_energy >> 10);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000207 if (sample_energy > parameters.max_energy) {
208 parameters.max_energy = sample_energy;
209 }
210
211 // Set |energy_update_threshold| to no less than 60 dB lower than
212 // |max_energy_|. Adding 524288 assures proper rounding.
213 int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
214 if (energy_update_threshold > parameters.energy_update_threshold) {
215 parameters.energy_update_threshold = energy_update_threshold;
216 }
217}
218
219void BackgroundNoise::SaveParameters(size_t channel,
220 const int16_t* lpc_coefficients,
221 const int16_t* filter_state,
222 int32_t sample_energy,
223 int32_t residual_energy) {
224 assert(channel < num_channels_);
225 ChannelParameters& parameters = channel_parameters_[channel];
226 memcpy(parameters.filter, lpc_coefficients,
Yves Gerey665174f2018-06-19 15:03:05 +0200227 (kMaxLpcOrder + 1) * sizeof(int16_t));
228 memcpy(parameters.filter_state, filter_state, kMaxLpcOrder * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000229 // Save energy level and update energy threshold levels.
230 // Never get under 1.0 in average sample energy.
231 parameters.energy = std::max(sample_energy, 1);
232 parameters.energy_update_threshold = parameters.energy;
233 parameters.low_energy_update_threshold = 0;
234
235 // Normalize residual_energy to 29 or 30 bits before sqrt.
Peter Kastingb7e50542015-06-11 12:55:50 -0700236 int16_t norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000237 if (norm_shift & 0x1) {
238 norm_shift -= 1; // Even number of shifts required.
239 }
Henrik Lundin3c4ef292015-08-31 10:18:28 +0200240 residual_energy = WEBRTC_SPL_SHIFT_W32(residual_energy, norm_shift);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000241
242 // Calculate scale and shift factor.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700243 parameters.scale = static_cast<int16_t>(WebRtcSpl_SqrtFloor(residual_energy));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000244 // Add 13 to the |scale_shift_|, since the random numbers table is in
245 // Q13.
246 // TODO(hlundin): Move the "13" to where the |scale_shift_| is used?
Peter Kastingb7e50542015-06-11 12:55:50 -0700247 parameters.scale_shift =
248 static_cast<int16_t>(13 + ((kLogResidualLength + norm_shift) / 2));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000249
250 initialized_ = true;
251}
252
253} // namespace webrtc