• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright (c) 2019 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_processing/ns/signal_model_estimator.h"
12 
13 #include "modules/audio_processing/ns/fast_math.h"
14 
15 namespace webrtc {
16 
17 namespace {
18 
19 constexpr float kOneByFftSizeBy2Plus1 = 1.f / kFftSizeBy2Plus1;
20 
21 // Computes the difference measure between input spectrum and a template/learned
22 // noise spectrum.
ComputeSpectralDiff(rtc::ArrayView<const float,kFftSizeBy2Plus1> conservative_noise_spectrum,rtc::ArrayView<const float,kFftSizeBy2Plus1> signal_spectrum,float signal_spectral_sum,float diff_normalization)23 float ComputeSpectralDiff(
24     rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
25     rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
26     float signal_spectral_sum,
27     float diff_normalization) {
28   // spectral_diff = var(signal_spectrum) - cov(signal_spectrum, magnAvgPause)^2
29   // / var(magnAvgPause)
30 
31   // Compute average quantities.
32   float noise_average = 0.f;
33   for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
34     // Conservative smooth noise spectrum from pause frames.
35     noise_average += conservative_noise_spectrum[i];
36   }
37   noise_average = noise_average * kOneByFftSizeBy2Plus1;
38   float signal_average = signal_spectral_sum * kOneByFftSizeBy2Plus1;
39 
40   // Compute variance and covariance quantities.
41   float covariance = 0.f;
42   float noise_variance = 0.f;
43   float signal_variance = 0.f;
44   for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
45     float signal_diff = signal_spectrum[i] - signal_average;
46     float noise_diff = conservative_noise_spectrum[i] - noise_average;
47     covariance += signal_diff * noise_diff;
48     noise_variance += noise_diff * noise_diff;
49     signal_variance += signal_diff * signal_diff;
50   }
51   covariance *= kOneByFftSizeBy2Plus1;
52   noise_variance *= kOneByFftSizeBy2Plus1;
53   signal_variance *= kOneByFftSizeBy2Plus1;
54 
55   // Update of average magnitude spectrum.
56   float spectral_diff =
57       signal_variance - (covariance * covariance) / (noise_variance + 0.0001f);
58   // Normalize.
59   return spectral_diff / (diff_normalization + 0.0001f);
60 }
61 
62 // Updates the spectral flatness based on the input spectrum.
UpdateSpectralFlatness(rtc::ArrayView<const float,kFftSizeBy2Plus1> signal_spectrum,float signal_spectral_sum,float * spectral_flatness)63 void UpdateSpectralFlatness(
64     rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
65     float signal_spectral_sum,
66     float* spectral_flatness) {
67   RTC_DCHECK(spectral_flatness);
68 
69   // Compute log of ratio of the geometric to arithmetic mean (handle the log(0)
70   // separately).
71   constexpr float kAveraging = 0.3f;
72   float avg_spect_flatness_num = 0.f;
73   for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) {
74     if (signal_spectrum[i] == 0.f) {
75       *spectral_flatness -= kAveraging * (*spectral_flatness);
76       return;
77     }
78   }
79 
80   for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) {
81     avg_spect_flatness_num += LogApproximation(signal_spectrum[i]);
82   }
83 
84   float avg_spect_flatness_denom = signal_spectral_sum - signal_spectrum[0];
85 
86   avg_spect_flatness_denom = avg_spect_flatness_denom * kOneByFftSizeBy2Plus1;
87   avg_spect_flatness_num = avg_spect_flatness_num * kOneByFftSizeBy2Plus1;
88 
89   float spectral_tmp =
90       ExpApproximation(avg_spect_flatness_num) / avg_spect_flatness_denom;
91 
92   // Time-avg update of spectral flatness feature.
93   *spectral_flatness += kAveraging * (spectral_tmp - *spectral_flatness);
94 }
95 
96 // Updates the log LRT measures.
UpdateSpectralLrt(rtc::ArrayView<const float,kFftSizeBy2Plus1> prior_snr,rtc::ArrayView<const float,kFftSizeBy2Plus1> post_snr,rtc::ArrayView<float,kFftSizeBy2Plus1> avg_log_lrt,float * lrt)97 void UpdateSpectralLrt(rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
98                        rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
99                        rtc::ArrayView<float, kFftSizeBy2Plus1> avg_log_lrt,
100                        float* lrt) {
101   RTC_DCHECK(lrt);
102 
103   for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
104     float tmp1 = 1.f + 2.f * prior_snr[i];
105     float tmp2 = 2.f * prior_snr[i] / (tmp1 + 0.0001f);
106     float bessel_tmp = (post_snr[i] + 1.f) * tmp2;
107     avg_log_lrt[i] +=
108         .5f * (bessel_tmp - LogApproximation(tmp1) - avg_log_lrt[i]);
109   }
110 
111   float log_lrt_time_avg_k_sum = 0.f;
112   for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
113     log_lrt_time_avg_k_sum += avg_log_lrt[i];
114   }
115   *lrt = log_lrt_time_avg_k_sum * kOneByFftSizeBy2Plus1;
116 }
117 
118 }  // namespace
119 
SignalModelEstimator()120 SignalModelEstimator::SignalModelEstimator()
121     : prior_model_estimator_(kLtrFeatureThr) {}
122 
AdjustNormalization(int32_t num_analyzed_frames,float signal_energy)123 void SignalModelEstimator::AdjustNormalization(int32_t num_analyzed_frames,
124                                                float signal_energy) {
125   diff_normalization_ *= num_analyzed_frames;
126   diff_normalization_ += signal_energy;
127   diff_normalization_ /= (num_analyzed_frames + 1);
128 }
129 
130 // Update the noise features.
Update(rtc::ArrayView<const float,kFftSizeBy2Plus1> prior_snr,rtc::ArrayView<const float,kFftSizeBy2Plus1> post_snr,rtc::ArrayView<const float,kFftSizeBy2Plus1> conservative_noise_spectrum,rtc::ArrayView<const float,kFftSizeBy2Plus1> signal_spectrum,float signal_spectral_sum,float signal_energy)131 void SignalModelEstimator::Update(
132     rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
133     rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
134     rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
135     rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
136     float signal_spectral_sum,
137     float signal_energy) {
138   // Compute spectral flatness on input spectrum.
139   UpdateSpectralFlatness(signal_spectrum, signal_spectral_sum,
140                          &features_.spectral_flatness);
141 
142   // Compute difference of input spectrum with learned/estimated noise spectrum.
143   float spectral_diff =
144       ComputeSpectralDiff(conservative_noise_spectrum, signal_spectrum,
145                           signal_spectral_sum, diff_normalization_);
146   // Compute time-avg update of difference feature.
147   features_.spectral_diff += 0.3f * (spectral_diff - features_.spectral_diff);
148 
149   signal_energy_sum_ += signal_energy;
150 
151   // Compute histograms for parameter decisions (thresholds and weights for
152   // features). Parameters are extracted periodically.
153   if (--histogram_analysis_counter_ > 0) {
154     histograms_.Update(features_);
155   } else {
156     // Compute model parameters.
157     prior_model_estimator_.Update(histograms_);
158 
159     // Clear histograms for next update.
160     histograms_.Clear();
161 
162     histogram_analysis_counter_ = kFeatureUpdateWindowSize;
163 
164     // Update every window:
165     // Compute normalization for the spectral difference for next estimation.
166     signal_energy_sum_ = signal_energy_sum_ / kFeatureUpdateWindowSize;
167     diff_normalization_ = 0.5f * (signal_energy_sum_ + diff_normalization_);
168     signal_energy_sum_ = 0.f;
169   }
170 
171   // Compute the LRT.
172   UpdateSpectralLrt(prior_snr, post_snr, features_.avg_log_lrt, &features_.lrt);
173 }
174 
175 }  // namespace webrtc
176