blob: ae4645c78e86acd1710ee354ad007d01502a9e0a [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 {
Alessio Bazzica7e53be02019-04-15 12:32:23 +020024namespace {
25
26constexpr size_t kMaxSampleRate = 48000;
27
28} // namespace
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000029
Peter Kastingdce40cf2015-08-24 14:52:23 -070030// static
Alessio Bazzica7e53be02019-04-15 12:32:23 +020031constexpr size_t BackgroundNoise::kMaxLpcOrder;
Peter Kastingdce40cf2015-08-24 14:52:23 -070032
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000033BackgroundNoise::BackgroundNoise(size_t num_channels)
34 : num_channels_(num_channels),
Henrik Lundin67190172018-04-20 15:34:48 +020035 channel_parameters_(new ChannelParameters[num_channels_]) {
pbos@webrtc.org2d1a55c2013-07-31 15:54:00 +000036 Reset();
37}
38
39BackgroundNoise::~BackgroundNoise() {}
40
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000041void BackgroundNoise::Reset() {
42 initialized_ = false;
43 for (size_t channel = 0; channel < num_channels_; ++channel) {
44 channel_parameters_[channel].Reset();
45 }
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000046}
47
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +020048bool BackgroundNoise::Update(const AudioMultiVector& input,
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000049 const PostDecodeVad& vad) {
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +020050 bool filter_params_saved = false;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000051 if (vad.running() && vad.active_speech()) {
52 // Do not update the background noise parameters if we know that the signal
53 // is active speech.
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +020054 return filter_params_saved;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000055 }
56
57 int32_t auto_correlation[kMaxLpcOrder + 1];
58 int16_t fiter_output[kMaxLpcOrder + kResidualLength];
59 int16_t reflection_coefficients[kMaxLpcOrder];
60 int16_t lpc_coefficients[kMaxLpcOrder + 1];
61
62 for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
63 ChannelParameters& parameters = channel_parameters_[channel_ix];
64 int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
65 int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +020066 RTC_DCHECK_GE(input.Size(), kVecLen);
minyue-webrtc79553cb2016-05-10 19:55:56 +020067 input[channel_ix].CopyTo(kVecLen, input.Size() - kVecLen, temp_signal);
Yves Gerey665174f2018-06-19 15:03:05 +020068 int32_t sample_energy =
69 CalculateAutoCorrelation(temp_signal, kVecLen, auto_correlation);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000070
71 if ((!vad.running() &&
Yves Gerey665174f2018-06-19 15:03:05 +020072 sample_energy < parameters.energy_update_threshold) ||
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000073 (vad.running() && !vad.active_speech())) {
74 // Generate LPC coefficients.
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +020075 if (auto_correlation[0] <= 0) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000076 // Center value in auto-correlation is not positive. Do not update.
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +020077 return filter_params_saved;
78 }
79
80 // Regardless of whether the filter is actually updated or not,
81 // update energy threshold levels, since we have in fact observed
82 // a low energy signal.
83 if (sample_energy < parameters.energy_update_threshold) {
84 // Never go under 1.0 in average sample energy.
85 parameters.energy_update_threshold = std::max(sample_energy, 1);
86 parameters.low_energy_update_threshold = 0;
87 }
88
89 // Only update BGN if filter is stable, i.e., if return value from
90 // Levinson-Durbin function is 1.
91 if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
92 reflection_coefficients,
93 kMaxLpcOrder) != 1) {
94 return filter_params_saved;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +000095 }
96
97 // Generate the CNG gain factor by looking at the energy of the residual.
98 WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
99 fiter_output, lpc_coefficients,
100 kMaxLpcOrder + 1, kResidualLength);
Yves Gerey665174f2018-06-19 15:03:05 +0200101 int32_t residual_energy = WebRtcSpl_DotProductWithScale(
102 fiter_output, fiter_output, kResidualLength, 0);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000103
104 // Check spectral flatness.
105 // Comparing the residual variance with the input signal variance tells
106 // if the spectrum is flat or not.
henrik.lundina67e5f52017-03-01 03:06:50 -0800107 // If 5 * residual_energy >= 16 * sample_energy, the spectrum is flat
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000108 // enough. Also ensure that the energy is non-zero.
henrik.lundina67e5f52017-03-01 03:06:50 -0800109 if ((sample_energy > 0) &&
110 (int64_t{5} * residual_energy >= int64_t{16} * sample_energy)) {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000111 // Spectrum is flat enough; save filter parameters.
112 // |temp_signal| + |kVecLen| - |kMaxLpcOrder| points at the first of the
113 // |kMaxLpcOrder| samples in the residual signal, which will form the
114 // filter state for the next noise generation.
115 SaveParameters(channel_ix, lpc_coefficients,
116 temp_signal + kVecLen - kMaxLpcOrder, sample_energy,
117 residual_energy);
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +0200118 filter_params_saved = true;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000119 }
120 } else {
121 // Will only happen if post-decode VAD is disabled and |sample_energy| is
122 // not low enough. Increase the threshold for update so that it increases
123 // by a factor 4 in 4 seconds.
124 IncrementEnergyThreshold(channel_ix, sample_energy);
125 }
126 }
Alessio Bazzica60bfb3d2019-06-28 10:49:39 +0200127 return filter_params_saved;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000128}
129
Alessio Bazzica7e53be02019-04-15 12:32:23 +0200130void BackgroundNoise::GenerateBackgroundNoise(
131 rtc::ArrayView<const int16_t> random_vector,
132 size_t channel,
133 int mute_slope,
134 bool too_many_expands,
135 size_t num_noise_samples,
136 int16_t* buffer) {
137 constexpr size_t kNoiseLpcOrder = kMaxLpcOrder;
138 int16_t scaled_random_vector[kMaxSampleRate / 8000 * 125];
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200139 RTC_DCHECK_LE(num_noise_samples, (kMaxSampleRate / 8000 * 125));
Alessio Bazzica7e53be02019-04-15 12:32:23 +0200140 RTC_DCHECK_GE(random_vector.size(), num_noise_samples);
141 int16_t* noise_samples = &buffer[kNoiseLpcOrder];
142 if (initialized()) {
143 // Use background noise parameters.
144 memcpy(noise_samples - kNoiseLpcOrder, FilterState(channel),
145 sizeof(int16_t) * kNoiseLpcOrder);
146
147 int dc_offset = 0;
148 if (ScaleShift(channel) > 1) {
149 dc_offset = 1 << (ScaleShift(channel) - 1);
150 }
151
152 // Scale random vector to correct energy level.
153 WebRtcSpl_AffineTransformVector(scaled_random_vector, random_vector.data(),
154 Scale(channel), dc_offset,
155 ScaleShift(channel), num_noise_samples);
156
157 WebRtcSpl_FilterARFastQ12(scaled_random_vector, noise_samples,
158 Filter(channel), kNoiseLpcOrder + 1,
159 num_noise_samples);
160
161 SetFilterState(
162 channel,
163 {&(noise_samples[num_noise_samples - kNoiseLpcOrder]), kNoiseLpcOrder});
164
165 // Unmute the background noise.
166 int16_t bgn_mute_factor = MuteFactor(channel);
167 if (bgn_mute_factor < 16384) {
168 WebRtcSpl_AffineTransformVector(noise_samples, noise_samples,
169 bgn_mute_factor, 8192, 14,
170 num_noise_samples);
171 }
172 // Update mute_factor in BackgroundNoise class.
173 SetMuteFactor(channel, bgn_mute_factor);
174 } else {
175 // BGN parameters have not been initialized; use zero noise.
176 memset(noise_samples, 0, sizeof(int16_t) * num_noise_samples);
177 }
178}
179
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000180int32_t BackgroundNoise::Energy(size_t channel) const {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200181 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000182 return channel_parameters_[channel].energy;
183}
184
185void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200186 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000187 channel_parameters_[channel].mute_factor = value;
188}
189
190int16_t BackgroundNoise::MuteFactor(size_t channel) const {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200191 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000192 return channel_parameters_[channel].mute_factor;
193}
194
195const int16_t* BackgroundNoise::Filter(size_t channel) const {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200196 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000197 return channel_parameters_[channel].filter;
198}
199
200const int16_t* BackgroundNoise::FilterState(size_t channel) const {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200201 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000202 return channel_parameters_[channel].filter_state;
203}
204
Yves Gerey665174f2018-06-19 15:03:05 +0200205void BackgroundNoise::SetFilterState(size_t channel,
Alessio Bazzica7e53be02019-04-15 12:32:23 +0200206 rtc::ArrayView<const int16_t> input) {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200207 RTC_DCHECK_LT(channel, num_channels_);
Alessio Bazzica7e53be02019-04-15 12:32:23 +0200208 size_t length = std::min(input.size(), kMaxLpcOrder);
209 memcpy(channel_parameters_[channel].filter_state, input.data(),
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000210 length * sizeof(int16_t));
211}
212
213int16_t BackgroundNoise::Scale(size_t channel) const {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200214 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000215 return channel_parameters_[channel].scale;
216}
217int16_t BackgroundNoise::ScaleShift(size_t channel) const {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200218 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000219 return channel_parameters_[channel].scale_shift;
220}
221
222int32_t BackgroundNoise::CalculateAutoCorrelation(
Yves Gerey665174f2018-06-19 15:03:05 +0200223 const int16_t* signal,
224 size_t length,
225 int32_t* auto_correlation) const {
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000226 static const int kCorrelationStep = -1;
minyue53ff70f2016-05-02 01:50:30 -0700227 const int correlation_scale =
228 CrossCorrelationWithAutoShift(signal, signal, length, kMaxLpcOrder + 1,
229 kCorrelationStep, auto_correlation);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000230
231 // Number of shifts to normalize energy to energy/sample.
232 int energy_sample_shift = kLogVecLen - correlation_scale;
233 return auto_correlation[0] >> energy_sample_shift;
234}
235
236void BackgroundNoise::IncrementEnergyThreshold(size_t channel,
237 int32_t sample_energy) {
238 // TODO(hlundin): Simplify the below threshold update. What this code
239 // does is simply "threshold += (increment * threshold) >> 16", but due
240 // to the limited-width operations, it is not exactly the same. The
241 // difference should be inaudible, but bit-exactness would not be
242 // maintained.
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200243 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000244 ChannelParameters& parameters = channel_parameters_[channel];
245 int32_t temp_energy =
Yves Gerey665174f2018-06-19 15:03:05 +0200246 (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
247 temp_energy +=
248 kThresholdIncrement * (parameters.energy_update_threshold & 0xFF);
249 temp_energy +=
250 (kThresholdIncrement * ((parameters.energy_update_threshold >> 8) & 0xFF))
251 << 8;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000252 parameters.low_energy_update_threshold += temp_energy;
253
Yves Gerey665174f2018-06-19 15:03:05 +0200254 parameters.energy_update_threshold +=
255 kThresholdIncrement * (parameters.energy_update_threshold >> 16);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000256 parameters.energy_update_threshold +=
257 parameters.low_energy_update_threshold >> 16;
258 parameters.low_energy_update_threshold =
259 parameters.low_energy_update_threshold & 0x0FFFF;
260
261 // Update maximum energy.
262 // Decrease by a factor 1/1024 each time.
Yves Gerey665174f2018-06-19 15:03:05 +0200263 parameters.max_energy = parameters.max_energy - (parameters.max_energy >> 10);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000264 if (sample_energy > parameters.max_energy) {
265 parameters.max_energy = sample_energy;
266 }
267
268 // Set |energy_update_threshold| to no less than 60 dB lower than
269 // |max_energy_|. Adding 524288 assures proper rounding.
270 int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
271 if (energy_update_threshold > parameters.energy_update_threshold) {
272 parameters.energy_update_threshold = energy_update_threshold;
273 }
274}
275
276void BackgroundNoise::SaveParameters(size_t channel,
277 const int16_t* lpc_coefficients,
278 const int16_t* filter_state,
279 int32_t sample_energy,
280 int32_t residual_energy) {
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200281 RTC_DCHECK_LT(channel, num_channels_);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000282 ChannelParameters& parameters = channel_parameters_[channel];
283 memcpy(parameters.filter, lpc_coefficients,
Yves Gerey665174f2018-06-19 15:03:05 +0200284 (kMaxLpcOrder + 1) * sizeof(int16_t));
285 memcpy(parameters.filter_state, filter_state, kMaxLpcOrder * sizeof(int16_t));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000286 // Save energy level and update energy threshold levels.
287 // Never get under 1.0 in average sample energy.
288 parameters.energy = std::max(sample_energy, 1);
289 parameters.energy_update_threshold = parameters.energy;
290 parameters.low_energy_update_threshold = 0;
291
292 // Normalize residual_energy to 29 or 30 bits before sqrt.
Peter Kastingb7e50542015-06-11 12:55:50 -0700293 int16_t norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000294 if (norm_shift & 0x1) {
295 norm_shift -= 1; // Even number of shifts required.
296 }
Henrik Lundin3c4ef292015-08-31 10:18:28 +0200297 residual_energy = WEBRTC_SPL_SHIFT_W32(residual_energy, norm_shift);
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000298
299 // Calculate scale and shift factor.
Peter Kastingdce40cf2015-08-24 14:52:23 -0700300 parameters.scale = static_cast<int16_t>(WebRtcSpl_SqrtFloor(residual_energy));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000301 // Add 13 to the |scale_shift_|, since the random numbers table is in
302 // Q13.
303 // TODO(hlundin): Move the "13" to where the |scale_shift_| is used?
Peter Kastingb7e50542015-06-11 12:55:50 -0700304 parameters.scale_shift =
305 static_cast<int16_t>(13 + ((kLogResidualLength + norm_shift) / 2));
henrik.lundin@webrtc.orgd94659d2013-01-29 12:09:21 +0000306
307 initialized_ = true;
308}
309
310} // namespace webrtc