xref: /aosp_15_r20/external/webrtc/modules/audio_coding/neteq/background_noise.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1 /*
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 
11 #include "modules/audio_coding/neteq/background_noise.h"
12 
13 #include <string.h>  // memcpy
14 
15 #include <algorithm>  // min, max
16 
17 #include "common_audio/signal_processing/include/signal_processing_library.h"
18 #include "modules/audio_coding/neteq/audio_multi_vector.h"
19 #include "modules/audio_coding/neteq/cross_correlation.h"
20 #include "modules/audio_coding/neteq/post_decode_vad.h"
21 
22 namespace webrtc {
23 namespace {
24 
25 constexpr size_t kMaxSampleRate = 48000;
26 
27 }  // namespace
28 
29 // static
30 constexpr size_t BackgroundNoise::kMaxLpcOrder;
31 
BackgroundNoise(size_t num_channels)32 BackgroundNoise::BackgroundNoise(size_t num_channels)
33     : num_channels_(num_channels),
34       channel_parameters_(new ChannelParameters[num_channels_]) {
35   Reset();
36 }
37 
~BackgroundNoise()38 BackgroundNoise::~BackgroundNoise() {}
39 
Reset()40 void BackgroundNoise::Reset() {
41   initialized_ = false;
42   for (size_t channel = 0; channel < num_channels_; ++channel) {
43     channel_parameters_[channel].Reset();
44   }
45 }
46 
Update(const AudioMultiVector & input,const PostDecodeVad & vad)47 bool BackgroundNoise::Update(const AudioMultiVector& input,
48                              const PostDecodeVad& vad) {
49   bool filter_params_saved = false;
50   if (vad.running() && vad.active_speech()) {
51     // Do not update the background noise parameters if we know that the signal
52     // is active speech.
53     return filter_params_saved;
54   }
55 
56   int32_t auto_correlation[kMaxLpcOrder + 1];
57   int16_t fiter_output[kMaxLpcOrder + kResidualLength];
58   int16_t reflection_coefficients[kMaxLpcOrder];
59   int16_t lpc_coefficients[kMaxLpcOrder + 1];
60 
61   for (size_t channel_ix = 0; channel_ix < num_channels_; ++channel_ix) {
62     ChannelParameters& parameters = channel_parameters_[channel_ix];
63     int16_t temp_signal_array[kVecLen + kMaxLpcOrder] = {0};
64     int16_t* temp_signal = &temp_signal_array[kMaxLpcOrder];
65     RTC_DCHECK_GE(input.Size(), kVecLen);
66     input[channel_ix].CopyTo(kVecLen, input.Size() - kVecLen, temp_signal);
67     int32_t sample_energy =
68         CalculateAutoCorrelation(temp_signal, kVecLen, auto_correlation);
69 
70     if ((!vad.running() &&
71          sample_energy < parameters.energy_update_threshold) ||
72         (vad.running() && !vad.active_speech())) {
73       // Generate LPC coefficients.
74       if (auto_correlation[0] <= 0) {
75         // Center value in auto-correlation is not positive. Do not update.
76         return filter_params_saved;
77       }
78 
79       // Regardless of whether the filter is actually updated or not,
80       // update energy threshold levels, since we have in fact observed
81       // a low energy signal.
82       if (sample_energy < parameters.energy_update_threshold) {
83         // Never go under 1.0 in average sample energy.
84         parameters.energy_update_threshold = std::max(sample_energy, 1);
85         parameters.low_energy_update_threshold = 0;
86       }
87 
88       // Only update BGN if filter is stable, i.e., if return value from
89       // Levinson-Durbin function is 1.
90       if (WebRtcSpl_LevinsonDurbin(auto_correlation, lpc_coefficients,
91                                    reflection_coefficients,
92                                    kMaxLpcOrder) != 1) {
93         return filter_params_saved;
94       }
95 
96       // Generate the CNG gain factor by looking at the energy of the residual.
97       WebRtcSpl_FilterMAFastQ12(temp_signal + kVecLen - kResidualLength,
98                                 fiter_output, lpc_coefficients,
99                                 kMaxLpcOrder + 1, kResidualLength);
100       int32_t residual_energy = WebRtcSpl_DotProductWithScale(
101           fiter_output, fiter_output, kResidualLength, 0);
102 
103       // Check spectral flatness.
104       // Comparing the residual variance with the input signal variance tells
105       // if the spectrum is flat or not.
106       // If 5 * residual_energy >= 16 * sample_energy, the spectrum is flat
107       // enough.  Also ensure that the energy is non-zero.
108       if ((sample_energy > 0) &&
109           (int64_t{5} * residual_energy >= int64_t{16} * sample_energy)) {
110         // Spectrum is flat enough; save filter parameters.
111         // `temp_signal` + `kVecLen` - `kMaxLpcOrder` points at the first of the
112         // `kMaxLpcOrder` samples in the residual signal, which will form the
113         // filter state for the next noise generation.
114         SaveParameters(channel_ix, lpc_coefficients,
115                        temp_signal + kVecLen - kMaxLpcOrder, sample_energy,
116                        residual_energy);
117         filter_params_saved = true;
118       }
119     } else {
120       // Will only happen if post-decode VAD is disabled and `sample_energy` is
121       // not low enough. Increase the threshold for update so that it increases
122       // by a factor 4 in 4 seconds.
123       IncrementEnergyThreshold(channel_ix, sample_energy);
124     }
125   }
126   return filter_params_saved;
127 }
128 
GenerateBackgroundNoise(rtc::ArrayView<const int16_t> random_vector,size_t channel,int mute_slope,bool too_many_expands,size_t num_noise_samples,int16_t * buffer)129 void BackgroundNoise::GenerateBackgroundNoise(
130     rtc::ArrayView<const int16_t> random_vector,
131     size_t channel,
132     int mute_slope,
133     bool too_many_expands,
134     size_t num_noise_samples,
135     int16_t* buffer) {
136   constexpr size_t kNoiseLpcOrder = kMaxLpcOrder;
137   int16_t scaled_random_vector[kMaxSampleRate / 8000 * 125];
138   RTC_DCHECK_LE(num_noise_samples, (kMaxSampleRate / 8000 * 125));
139   RTC_DCHECK_GE(random_vector.size(), num_noise_samples);
140   int16_t* noise_samples = &buffer[kNoiseLpcOrder];
141   if (initialized()) {
142     // Use background noise parameters.
143     memcpy(noise_samples - kNoiseLpcOrder, FilterState(channel),
144            sizeof(int16_t) * kNoiseLpcOrder);
145 
146     int dc_offset = 0;
147     if (ScaleShift(channel) > 1) {
148       dc_offset = 1 << (ScaleShift(channel) - 1);
149     }
150 
151     // Scale random vector to correct energy level.
152     WebRtcSpl_AffineTransformVector(scaled_random_vector, random_vector.data(),
153                                     Scale(channel), dc_offset,
154                                     ScaleShift(channel), num_noise_samples);
155 
156     WebRtcSpl_FilterARFastQ12(scaled_random_vector, noise_samples,
157                               Filter(channel), kNoiseLpcOrder + 1,
158                               num_noise_samples);
159 
160     SetFilterState(
161         channel,
162         {&(noise_samples[num_noise_samples - kNoiseLpcOrder]), kNoiseLpcOrder});
163 
164     // Unmute the background noise.
165     int16_t bgn_mute_factor = MuteFactor(channel);
166     if (bgn_mute_factor < 16384) {
167       WebRtcSpl_AffineTransformVector(noise_samples, noise_samples,
168                                       bgn_mute_factor, 8192, 14,
169                                       num_noise_samples);
170     }
171     // Update mute_factor in BackgroundNoise class.
172     SetMuteFactor(channel, bgn_mute_factor);
173   } else {
174     // BGN parameters have not been initialized; use zero noise.
175     memset(noise_samples, 0, sizeof(int16_t) * num_noise_samples);
176   }
177 }
178 
Energy(size_t channel) const179 int32_t BackgroundNoise::Energy(size_t channel) const {
180   RTC_DCHECK_LT(channel, num_channels_);
181   return channel_parameters_[channel].energy;
182 }
183 
SetMuteFactor(size_t channel,int16_t value)184 void BackgroundNoise::SetMuteFactor(size_t channel, int16_t value) {
185   RTC_DCHECK_LT(channel, num_channels_);
186   channel_parameters_[channel].mute_factor = value;
187 }
188 
MuteFactor(size_t channel) const189 int16_t BackgroundNoise::MuteFactor(size_t channel) const {
190   RTC_DCHECK_LT(channel, num_channels_);
191   return channel_parameters_[channel].mute_factor;
192 }
193 
Filter(size_t channel) const194 const int16_t* BackgroundNoise::Filter(size_t channel) const {
195   RTC_DCHECK_LT(channel, num_channels_);
196   return channel_parameters_[channel].filter;
197 }
198 
FilterState(size_t channel) const199 const int16_t* BackgroundNoise::FilterState(size_t channel) const {
200   RTC_DCHECK_LT(channel, num_channels_);
201   return channel_parameters_[channel].filter_state;
202 }
203 
SetFilterState(size_t channel,rtc::ArrayView<const int16_t> input)204 void BackgroundNoise::SetFilterState(size_t channel,
205                                      rtc::ArrayView<const int16_t> input) {
206   RTC_DCHECK_LT(channel, num_channels_);
207   size_t length = std::min(input.size(), kMaxLpcOrder);
208   memcpy(channel_parameters_[channel].filter_state, input.data(),
209          length * sizeof(int16_t));
210 }
211 
Scale(size_t channel) const212 int16_t BackgroundNoise::Scale(size_t channel) const {
213   RTC_DCHECK_LT(channel, num_channels_);
214   return channel_parameters_[channel].scale;
215 }
ScaleShift(size_t channel) const216 int16_t BackgroundNoise::ScaleShift(size_t channel) const {
217   RTC_DCHECK_LT(channel, num_channels_);
218   return channel_parameters_[channel].scale_shift;
219 }
220 
CalculateAutoCorrelation(const int16_t * signal,size_t length,int32_t * auto_correlation) const221 int32_t BackgroundNoise::CalculateAutoCorrelation(
222     const int16_t* signal,
223     size_t length,
224     int32_t* auto_correlation) const {
225   static const int kCorrelationStep = -1;
226   const int correlation_scale =
227       CrossCorrelationWithAutoShift(signal, signal, length, kMaxLpcOrder + 1,
228                                     kCorrelationStep, auto_correlation);
229 
230   // Number of shifts to normalize energy to energy/sample.
231   int energy_sample_shift = kLogVecLen - correlation_scale;
232   return auto_correlation[0] >> energy_sample_shift;
233 }
234 
IncrementEnergyThreshold(size_t channel,int32_t sample_energy)235 void BackgroundNoise::IncrementEnergyThreshold(size_t channel,
236                                                int32_t sample_energy) {
237   // TODO(hlundin): Simplify the below threshold update. What this code
238   // does is simply "threshold += (increment * threshold) >> 16", but due
239   // to the limited-width operations, it is not exactly the same. The
240   // difference should be inaudible, but bit-exactness would not be
241   // maintained.
242   RTC_DCHECK_LT(channel, num_channels_);
243   ChannelParameters& parameters = channel_parameters_[channel];
244   int32_t temp_energy =
245       (kThresholdIncrement * parameters.low_energy_update_threshold) >> 16;
246   temp_energy +=
247       kThresholdIncrement * (parameters.energy_update_threshold & 0xFF);
248   temp_energy +=
249       (kThresholdIncrement * ((parameters.energy_update_threshold >> 8) & 0xFF))
250       << 8;
251   parameters.low_energy_update_threshold += temp_energy;
252 
253   parameters.energy_update_threshold +=
254       kThresholdIncrement * (parameters.energy_update_threshold >> 16);
255   parameters.energy_update_threshold +=
256       parameters.low_energy_update_threshold >> 16;
257   parameters.low_energy_update_threshold =
258       parameters.low_energy_update_threshold & 0x0FFFF;
259 
260   // Update maximum energy.
261   // Decrease by a factor 1/1024 each time.
262   parameters.max_energy = parameters.max_energy - (parameters.max_energy >> 10);
263   if (sample_energy > parameters.max_energy) {
264     parameters.max_energy = sample_energy;
265   }
266 
267   // Set `energy_update_threshold` to no less than 60 dB lower than
268   // `max_energy_`. Adding 524288 assures proper rounding.
269   int32_t energy_update_threshold = (parameters.max_energy + 524288) >> 20;
270   if (energy_update_threshold > parameters.energy_update_threshold) {
271     parameters.energy_update_threshold = energy_update_threshold;
272   }
273 }
274 
SaveParameters(size_t channel,const int16_t * lpc_coefficients,const int16_t * filter_state,int32_t sample_energy,int32_t residual_energy)275 void BackgroundNoise::SaveParameters(size_t channel,
276                                      const int16_t* lpc_coefficients,
277                                      const int16_t* filter_state,
278                                      int32_t sample_energy,
279                                      int32_t residual_energy) {
280   RTC_DCHECK_LT(channel, num_channels_);
281   ChannelParameters& parameters = channel_parameters_[channel];
282   memcpy(parameters.filter, lpc_coefficients,
283          (kMaxLpcOrder + 1) * sizeof(int16_t));
284   memcpy(parameters.filter_state, filter_state, kMaxLpcOrder * sizeof(int16_t));
285   // Save energy level and update energy threshold levels.
286   // Never get under 1.0 in average sample energy.
287   parameters.energy = std::max(sample_energy, 1);
288   parameters.energy_update_threshold = parameters.energy;
289   parameters.low_energy_update_threshold = 0;
290 
291   // Normalize residual_energy to 29 or 30 bits before sqrt.
292   int16_t norm_shift = WebRtcSpl_NormW32(residual_energy) - 1;
293   if (norm_shift & 0x1) {
294     norm_shift -= 1;  // Even number of shifts required.
295   }
296   residual_energy = WEBRTC_SPL_SHIFT_W32(residual_energy, norm_shift);
297 
298   // Calculate scale and shift factor.
299   parameters.scale = static_cast<int16_t>(WebRtcSpl_SqrtFloor(residual_energy));
300   // Add 13 to the `scale_shift_`, since the random numbers table is in
301   // Q13.
302   // TODO(hlundin): Move the "13" to where the `scale_shift_` is used?
303   parameters.scale_shift =
304       static_cast<int16_t>(13 + ((kLogResidualLength + norm_shift) / 2));
305 
306   initialized_ = true;
307 }
308 
309 }  // namespace webrtc
310