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