tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

noise_suppressor.cc (22353B)


      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_processing/ns/noise_suppressor.h"
     12 
     13 #include <algorithm>
     14 #include <array>
     15 #include <cmath>
     16 #include <cstdlib>
     17 #include <cstring>
     18 #include <memory>
     19 
     20 #include "api/array_view.h"
     21 #include "modules/audio_processing/audio_buffer.h"
     22 #include "modules/audio_processing/ns/fast_math.h"
     23 #include "modules/audio_processing/ns/ns_common.h"
     24 #include "modules/audio_processing/ns/ns_config.h"
     25 #include "modules/audio_processing/ns/suppression_params.h"
     26 #include "rtc_base/checks.h"
     27 
     28 namespace webrtc {
     29 
     30 namespace {
     31 
     32 // Maps sample rate to number of bands.
     33 size_t NumBandsForRate(size_t sample_rate_hz) {
     34  RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
     35             sample_rate_hz == 48000);
     36  return sample_rate_hz / 16000;
     37 }
     38 
     39 // Maximum number of channels for which the channel data is stored on
     40 // the stack. If the number of channels are larger than this, they are stored
     41 // using scratch memory that is pre-allocated on the heap. The reason for this
     42 // partitioning is not to waste heap space for handling the more common numbers
     43 // of channels, while at the same time not limiting the support for higher
     44 // numbers of channels by enforcing the channel data to be stored on the
     45 // stack using a fixed maximum value.
     46 constexpr size_t kMaxNumChannelsOnStack = 2;
     47 
     48 // Chooses the number of channels to store on the heap when that is required due
     49 // to the number of channels being larger than the pre-defined number
     50 // of channels to store on the stack.
     51 size_t NumChannelsOnHeap(size_t num_channels) {
     52  return num_channels > kMaxNumChannelsOnStack ? num_channels : 0;
     53 }
     54 
     55 // Hybrib Hanning and flat window for the filterbank.
     56 constexpr std::array<float, 96> kBlocks160w256FirstHalf = {
     57    0.00000000f, 0.01636173f, 0.03271908f, 0.04906767f, 0.06540313f,
     58    0.08172107f, 0.09801714f, 0.11428696f, 0.13052619f, 0.14673047f,
     59    0.16289547f, 0.17901686f, 0.19509032f, 0.21111155f, 0.22707626f,
     60    0.24298018f, 0.25881905f, 0.27458862f, 0.29028468f, 0.30590302f,
     61    0.32143947f, 0.33688985f, 0.35225005f, 0.36751594f, 0.38268343f,
     62    0.39774847f, 0.41270703f, 0.42755509f, 0.44228869f, 0.45690388f,
     63    0.47139674f, 0.48576339f, 0.50000000f, 0.51410274f, 0.52806785f,
     64    0.54189158f, 0.55557023f, 0.56910015f, 0.58247770f, 0.59569930f,
     65    0.60876143f, 0.62166057f, 0.63439328f, 0.64695615f, 0.65934582f,
     66    0.67155895f, 0.68359230f, 0.69544264f, 0.70710678f, 0.71858162f,
     67    0.72986407f, 0.74095113f, 0.75183981f, 0.76252720f, 0.77301045f,
     68    0.78328675f, 0.79335334f, 0.80320753f, 0.81284668f, 0.82226822f,
     69    0.83146961f, 0.84044840f, 0.84920218f, 0.85772861f, 0.86602540f,
     70    0.87409034f, 0.88192126f, 0.88951608f, 0.89687274f, 0.90398929f,
     71    0.91086382f, 0.91749450f, 0.92387953f, 0.93001722f, 0.93590593f,
     72    0.94154407f, 0.94693013f, 0.95206268f, 0.95694034f, 0.96156180f,
     73    0.96592583f, 0.97003125f, 0.97387698f, 0.97746197f, 0.98078528f,
     74    0.98384601f, 0.98664333f, 0.98917651f, 0.99144486f, 0.99344778f,
     75    0.99518473f, 0.99665524f, 0.99785892f, 0.99879546f, 0.99946459f,
     76    0.99986614f};
     77 
     78 // Applies the filterbank window to a buffer.
     79 void ApplyFilterBankWindow(ArrayView<float, kFftSize> x) {
     80  for (size_t i = 0; i < 96; ++i) {
     81    x[i] = kBlocks160w256FirstHalf[i] * x[i];
     82  }
     83 
     84  for (size_t i = 161, k = 95; i < kFftSize; ++i, --k) {
     85    RTC_DCHECK_NE(0, k);
     86    x[i] = kBlocks160w256FirstHalf[k] * x[i];
     87  }
     88 }
     89 
     90 // Extends a frame with previous data.
     91 void FormExtendedFrame(ArrayView<const float, kNsFrameSize> frame,
     92                       ArrayView<float, kFftSize - kNsFrameSize> old_data,
     93                       ArrayView<float, kFftSize> extended_frame) {
     94  std::copy(old_data.begin(), old_data.end(), extended_frame.begin());
     95  std::copy(frame.begin(), frame.end(),
     96            extended_frame.begin() + old_data.size());
     97  std::copy(extended_frame.end() - old_data.size(), extended_frame.end(),
     98            old_data.begin());
     99 }
    100 
    101 // Uses overlap-and-add to produce an output frame.
    102 void OverlapAndAdd(ArrayView<const float, kFftSize> extended_frame,
    103                   ArrayView<float, kOverlapSize> overlap_memory,
    104                   ArrayView<float, kNsFrameSize> output_frame) {
    105  for (size_t i = 0; i < kOverlapSize; ++i) {
    106    output_frame[i] = overlap_memory[i] + extended_frame[i];
    107  }
    108  std::copy(extended_frame.begin() + kOverlapSize,
    109            extended_frame.begin() + kNsFrameSize,
    110            output_frame.begin() + kOverlapSize);
    111  std::copy(extended_frame.begin() + kNsFrameSize, extended_frame.end(),
    112            overlap_memory.begin());
    113 }
    114 
    115 // Produces a delayed frame.
    116 void DelaySignal(ArrayView<const float, kNsFrameSize> frame,
    117                 ArrayView<float, kFftSize - kNsFrameSize> delay_buffer,
    118                 ArrayView<float, kNsFrameSize> delayed_frame) {
    119  constexpr size_t kSamplesFromFrame = kNsFrameSize - (kFftSize - kNsFrameSize);
    120  std::copy(delay_buffer.begin(), delay_buffer.end(), delayed_frame.begin());
    121  std::copy(frame.begin(), frame.begin() + kSamplesFromFrame,
    122            delayed_frame.begin() + delay_buffer.size());
    123 
    124  std::copy(frame.begin() + kSamplesFromFrame, frame.end(),
    125            delay_buffer.begin());
    126 }
    127 
    128 // Computes the energy of an extended frame.
    129 float ComputeEnergyOfExtendedFrame(ArrayView<const float, kFftSize> x) {
    130  float energy = 0.f;
    131  for (float x_k : x) {
    132    energy += x_k * x_k;
    133  }
    134 
    135  return energy;
    136 }
    137 
    138 // Computes the energy of an extended frame based on its subcomponents.
    139 float ComputeEnergyOfExtendedFrame(
    140    ArrayView<const float, kNsFrameSize> frame,
    141    ArrayView<float, kFftSize - kNsFrameSize> old_data) {
    142  float energy = 0.f;
    143  for (float v : old_data) {
    144    energy += v * v;
    145  }
    146  for (float v : frame) {
    147    energy += v * v;
    148  }
    149 
    150  return energy;
    151 }
    152 
    153 // Computes the magnitude spectrum based on an FFT output.
    154 void ComputeMagnitudeSpectrum(
    155    ArrayView<const float, kFftSize> real,
    156    ArrayView<const float, kFftSize> imag,
    157    ArrayView<float, kFftSizeBy2Plus1> signal_spectrum) {
    158  signal_spectrum[0] = fabsf(real[0]) + 1.f;
    159  signal_spectrum[kFftSizeBy2Plus1 - 1] =
    160      fabsf(real[kFftSizeBy2Plus1 - 1]) + 1.f;
    161 
    162  for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) {
    163    signal_spectrum[i] =
    164        SqrtFastApproximation(real[i] * real[i] + imag[i] * imag[i]) + 1.f;
    165  }
    166 }
    167 
    168 // Compute prior and post SNR.
    169 void ComputeSnr(ArrayView<const float, kFftSizeBy2Plus1> filter,
    170                ArrayView<const float> prev_signal_spectrum,
    171                ArrayView<const float> signal_spectrum,
    172                ArrayView<const float> prev_noise_spectrum,
    173                ArrayView<const float> noise_spectrum,
    174                ArrayView<float> prior_snr,
    175                ArrayView<float> post_snr) {
    176  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
    177    // Previous post SNR.
    178    // Previous estimate: based on previous frame with gain filter.
    179    float prev_estimate = prev_signal_spectrum[i] /
    180                          (prev_noise_spectrum[i] + 0.0001f) * filter[i];
    181    // Post SNR.
    182    if (signal_spectrum[i] > noise_spectrum[i]) {
    183      post_snr[i] = signal_spectrum[i] / (noise_spectrum[i] + 0.0001f) - 1.f;
    184    } else {
    185      post_snr[i] = 0.f;
    186    }
    187    // The directed decision estimate of the prior SNR is a sum the current and
    188    // previous estimates.
    189    prior_snr[i] = 0.98f * prev_estimate + (1.f - 0.98f) * post_snr[i];
    190  }
    191 }
    192 
    193 // Computes the attenuating gain for the noise suppression of the upper bands.
    194 float ComputeUpperBandsGain(
    195    float minimum_attenuating_gain,
    196    ArrayView<const float, kFftSizeBy2Plus1> filter,
    197    ArrayView<const float> speech_probability,
    198    ArrayView<const float, kFftSizeBy2Plus1> prev_analysis_signal_spectrum,
    199    ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum) {
    200  // Average speech prob and filter gain for the end of the lowest band.
    201  constexpr int kNumAvgBins = 32;
    202  constexpr float kOneByNumAvgBins = 1.f / kNumAvgBins;
    203 
    204  float avg_prob_speech = 0.f;
    205  float avg_filter_gain = 0.f;
    206  for (size_t i = kFftSizeBy2Plus1 - kNumAvgBins - 1; i < kFftSizeBy2Plus1 - 1;
    207       i++) {
    208    avg_prob_speech += speech_probability[i];
    209    avg_filter_gain += filter[i];
    210  }
    211  avg_prob_speech = avg_prob_speech * kOneByNumAvgBins;
    212  avg_filter_gain = avg_filter_gain * kOneByNumAvgBins;
    213 
    214  // If the speech was suppressed by a component between Analyze and Process, an
    215  // example being by an AEC, it should not be considered speech for the purpose
    216  // of high band suppression. To that end, the speech probability is scaled
    217  // accordingly.
    218  float sum_analysis_spectrum = 0.f;
    219  float sum_processing_spectrum = 0.f;
    220  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
    221    sum_analysis_spectrum += prev_analysis_signal_spectrum[i];
    222    sum_processing_spectrum += signal_spectrum[i];
    223  }
    224 
    225  // The magnitude spectrum computation enforces the spectrum to be strictly
    226  // positive.
    227  RTC_DCHECK_GT(sum_analysis_spectrum, 0.f);
    228  avg_prob_speech *= sum_processing_spectrum / sum_analysis_spectrum;
    229 
    230  // Compute gain based on speech probability.
    231  float gain =
    232      0.5f * (1.f + static_cast<float>(tanh(2.f * avg_prob_speech - 1.f)));
    233 
    234  // Combine gain with low band gain.
    235  if (avg_prob_speech >= 0.5f) {
    236    gain = 0.25f * gain + 0.75f * avg_filter_gain;
    237  } else {
    238    gain = 0.5f * gain + 0.5f * avg_filter_gain;
    239  }
    240 
    241  // Make sure gain is within flooring range.
    242  return std::min(std::max(gain, minimum_attenuating_gain), 1.f);
    243 }
    244 
    245 }  // namespace
    246 
    247 NoiseSuppressor::ChannelState::ChannelState(
    248    const SuppressionParams& suppression_params,
    249    size_t num_bands)
    250    : wiener_filter(suppression_params),
    251      noise_estimator(suppression_params),
    252      process_delay_memory(num_bands > 1 ? num_bands - 1 : 0) {
    253  analyze_analysis_memory.fill(0.f);
    254  prev_analysis_signal_spectrum.fill(1.f);
    255  process_analysis_memory.fill(0.f);
    256  process_synthesis_memory.fill(0.f);
    257  for (auto& d : process_delay_memory) {
    258    d.fill(0.f);
    259  }
    260 }
    261 
    262 NoiseSuppressor::NoiseSuppressor(const NsConfig& config,
    263                                 size_t sample_rate_hz,
    264                                 size_t num_channels)
    265    : num_bands_(NumBandsForRate(sample_rate_hz)),
    266      num_channels_(num_channels),
    267      suppression_params_(config.target_level),
    268      filter_bank_states_heap_(NumChannelsOnHeap(num_channels_)),
    269      upper_band_gains_heap_(NumChannelsOnHeap(num_channels_)),
    270      energies_before_filtering_heap_(NumChannelsOnHeap(num_channels_)),
    271      gain_adjustments_heap_(NumChannelsOnHeap(num_channels_)),
    272      channels_(num_channels_) {
    273  for (size_t ch = 0; ch < num_channels_; ++ch) {
    274    channels_[ch] =
    275        std::make_unique<ChannelState>(suppression_params_, num_bands_);
    276  }
    277 }
    278 
    279 void NoiseSuppressor::AggregateWienerFilters(
    280    ArrayView<float, kFftSizeBy2Plus1> filter) const {
    281  ArrayView<const float, kFftSizeBy2Plus1> filter0 =
    282      channels_[0]->wiener_filter.get_filter();
    283  std::copy(filter0.begin(), filter0.end(), filter.begin());
    284 
    285  for (size_t ch = 1; ch < num_channels_; ++ch) {
    286    ArrayView<const float, kFftSizeBy2Plus1> filter_ch =
    287        channels_[ch]->wiener_filter.get_filter();
    288 
    289    for (size_t k = 0; k < kFftSizeBy2Plus1; ++k) {
    290      filter[k] = std::min(filter[k], filter_ch[k]);
    291    }
    292  }
    293 }
    294 
    295 void NoiseSuppressor::Analyze(const AudioBuffer& audio) {
    296  // Prepare the noise estimator for the analysis stage.
    297  for (size_t ch = 0; ch < num_channels_; ++ch) {
    298    channels_[ch]->noise_estimator.PrepareAnalysis();
    299  }
    300 
    301  // Check for zero frames.
    302  bool zero_frame = true;
    303  for (size_t ch = 0; ch < num_channels_; ++ch) {
    304    ArrayView<const float, kNsFrameSize> y_band0(
    305        &audio.split_bands_const(ch)[0][0], kNsFrameSize);
    306    float energy = ComputeEnergyOfExtendedFrame(
    307        y_band0, channels_[ch]->analyze_analysis_memory);
    308    if (energy > 0.f) {
    309      zero_frame = false;
    310      break;
    311    }
    312  }
    313 
    314  if (zero_frame) {
    315    // We want to avoid updating statistics in this case:
    316    // Updating feature statistics when we have zeros only will cause
    317    // thresholds to move towards zero signal situations. This in turn has the
    318    // effect that once the signal is "turned on" (non-zero values) everything
    319    // will be treated as speech and there is no noise suppression effect.
    320    // Depending on the duration of the inactive signal it takes a
    321    // considerable amount of time for the system to learn what is noise and
    322    // what is speech.
    323    return;
    324  }
    325 
    326  // Only update analysis counter for frames that are properly analyzed.
    327  if (++num_analyzed_frames_ < 0) {
    328    num_analyzed_frames_ = 0;
    329  }
    330 
    331  // Analyze all channels.
    332  for (size_t ch = 0; ch < num_channels_; ++ch) {
    333    std::unique_ptr<ChannelState>& ch_p = channels_[ch];
    334    ArrayView<const float, kNsFrameSize> y_band0(
    335        &audio.split_bands_const(ch)[0][0], kNsFrameSize);
    336 
    337    // Form an extended frame and apply analysis filter bank windowing.
    338    std::array<float, kFftSize> extended_frame;
    339    FormExtendedFrame(y_band0, ch_p->analyze_analysis_memory, extended_frame);
    340    ApplyFilterBankWindow(extended_frame);
    341 
    342    // Compute the magnitude spectrum.
    343    std::array<float, kFftSize> real;
    344    std::array<float, kFftSize> imag;
    345    fft_.Fft(extended_frame, real, imag);
    346 
    347    std::array<float, kFftSizeBy2Plus1> signal_spectrum;
    348    ComputeMagnitudeSpectrum(real, imag, signal_spectrum);
    349 
    350    // Compute energies.
    351    float signal_energy = 0.f;
    352    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
    353      signal_energy += real[i] * real[i] + imag[i] * imag[i];
    354    }
    355    signal_energy /= kFftSizeBy2Plus1;
    356 
    357    float signal_spectral_sum = 0.f;
    358    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
    359      signal_spectral_sum += signal_spectrum[i];
    360    }
    361 
    362    // Estimate the noise spectra and the probability estimates of speech
    363    // presence.
    364    ch_p->noise_estimator.PreUpdate(num_analyzed_frames_, signal_spectrum,
    365                                    signal_spectral_sum);
    366 
    367    std::array<float, kFftSizeBy2Plus1> post_snr;
    368    std::array<float, kFftSizeBy2Plus1> prior_snr;
    369    ComputeSnr(ch_p->wiener_filter.get_filter(),
    370               ch_p->prev_analysis_signal_spectrum, signal_spectrum,
    371               ch_p->noise_estimator.get_prev_noise_spectrum(),
    372               ch_p->noise_estimator.get_noise_spectrum(), prior_snr, post_snr);
    373 
    374    ch_p->speech_probability_estimator.Update(
    375        num_analyzed_frames_, prior_snr, post_snr,
    376        ch_p->noise_estimator.get_conservative_noise_spectrum(),
    377        signal_spectrum, signal_spectral_sum, signal_energy);
    378 
    379    ch_p->noise_estimator.PostUpdate(
    380        ch_p->speech_probability_estimator.get_probability(), signal_spectrum);
    381 
    382    // Store the magnitude spectrum to make it avalilable for the process
    383    // method.
    384    std::copy(signal_spectrum.begin(), signal_spectrum.end(),
    385              ch_p->prev_analysis_signal_spectrum.begin());
    386  }
    387 }
    388 
    389 void NoiseSuppressor::Process(AudioBuffer* audio) {
    390  // Select the space for storing data during the processing.
    391  std::array<FilterBankState, kMaxNumChannelsOnStack> filter_bank_states_stack;
    392  ArrayView<FilterBankState> filter_bank_states(filter_bank_states_stack.data(),
    393                                                num_channels_);
    394  std::array<float, kMaxNumChannelsOnStack> upper_band_gains_stack;
    395  ArrayView<float> upper_band_gains(upper_band_gains_stack.data(),
    396                                    num_channels_);
    397  std::array<float, kMaxNumChannelsOnStack> energies_before_filtering_stack;
    398  ArrayView<float> energies_before_filtering(
    399      energies_before_filtering_stack.data(), num_channels_);
    400  std::array<float, kMaxNumChannelsOnStack> gain_adjustments_stack;
    401  ArrayView<float> gain_adjustments(gain_adjustments_stack.data(),
    402                                    num_channels_);
    403  if (NumChannelsOnHeap(num_channels_) > 0) {
    404    // If the stack-allocated space is too small, use the heap for storing the
    405    // data.
    406    filter_bank_states = ArrayView<FilterBankState>(
    407        filter_bank_states_heap_.data(), num_channels_);
    408    upper_band_gains =
    409        ArrayView<float>(upper_band_gains_heap_.data(), num_channels_);
    410    energies_before_filtering =
    411        ArrayView<float>(energies_before_filtering_heap_.data(), num_channels_);
    412    gain_adjustments =
    413        ArrayView<float>(gain_adjustments_heap_.data(), num_channels_);
    414  }
    415 
    416  // Compute the suppression filters for all channels.
    417  for (size_t ch = 0; ch < num_channels_; ++ch) {
    418    // Form an extended frame and apply analysis filter bank windowing.
    419    ArrayView<float, kNsFrameSize> y_band0(&audio->split_bands(ch)[0][0],
    420                                           kNsFrameSize);
    421 
    422    FormExtendedFrame(y_band0, channels_[ch]->process_analysis_memory,
    423                      filter_bank_states[ch].extended_frame);
    424 
    425    ApplyFilterBankWindow(filter_bank_states[ch].extended_frame);
    426 
    427    energies_before_filtering[ch] =
    428        ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame);
    429 
    430    // Perform filter bank analysis and compute the magnitude spectrum.
    431    fft_.Fft(filter_bank_states[ch].extended_frame, filter_bank_states[ch].real,
    432             filter_bank_states[ch].imag);
    433 
    434    std::array<float, kFftSizeBy2Plus1> signal_spectrum;
    435    ComputeMagnitudeSpectrum(filter_bank_states[ch].real,
    436                             filter_bank_states[ch].imag, signal_spectrum);
    437 
    438    // Compute the frequency domain gain filter for noise attenuation.
    439    channels_[ch]->wiener_filter.Update(
    440        num_analyzed_frames_,
    441        channels_[ch]->noise_estimator.get_noise_spectrum(),
    442        channels_[ch]->noise_estimator.get_prev_noise_spectrum(),
    443        channels_[ch]->noise_estimator.get_parametric_noise_spectrum(),
    444        signal_spectrum);
    445 
    446    if (num_bands_ > 1) {
    447      // Compute the time-domain gain for attenuating the noise in the upper
    448      // bands.
    449 
    450      upper_band_gains[ch] = ComputeUpperBandsGain(
    451          suppression_params_.minimum_attenuating_gain,
    452          channels_[ch]->wiener_filter.get_filter(),
    453          channels_[ch]->speech_probability_estimator.get_probability(),
    454          channels_[ch]->prev_analysis_signal_spectrum, signal_spectrum);
    455    }
    456  }
    457 
    458  // Only do the below processing if the output of the audio processing module
    459  // is used.
    460  if (!capture_output_used_) {
    461    return;
    462  }
    463 
    464  // Aggregate the Wiener filters for all channels.
    465  std::array<float, kFftSizeBy2Plus1> filter_data;
    466  ArrayView<const float, kFftSizeBy2Plus1> filter = filter_data;
    467  if (num_channels_ == 1) {
    468    filter = channels_[0]->wiener_filter.get_filter();
    469  } else {
    470    AggregateWienerFilters(filter_data);
    471  }
    472 
    473  for (size_t ch = 0; ch < num_channels_; ++ch) {
    474    // Apply the filter to the lower band.
    475    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
    476      filter_bank_states[ch].real[i] *= filter[i];
    477      filter_bank_states[ch].imag[i] *= filter[i];
    478    }
    479  }
    480 
    481  // Perform filter bank synthesis
    482  for (size_t ch = 0; ch < num_channels_; ++ch) {
    483    fft_.Ifft(filter_bank_states[ch].real, filter_bank_states[ch].imag,
    484              filter_bank_states[ch].extended_frame);
    485  }
    486 
    487  for (size_t ch = 0; ch < num_channels_; ++ch) {
    488    const float energy_after_filtering =
    489        ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame);
    490 
    491    // Apply synthesis window.
    492    ApplyFilterBankWindow(filter_bank_states[ch].extended_frame);
    493 
    494    // Compute the adjustment of the noise attenuation filter based on the
    495    // effect of the attenuation.
    496    gain_adjustments[ch] =
    497        channels_[ch]->wiener_filter.ComputeOverallScalingFactor(
    498            num_analyzed_frames_,
    499            channels_[ch]->speech_probability_estimator.get_prior_probability(),
    500            energies_before_filtering[ch], energy_after_filtering);
    501  }
    502 
    503  // Select and apply adjustment of the noise attenuation filter based on the
    504  // effect of the attenuation.
    505  float gain_adjustment = gain_adjustments[0];
    506  for (size_t ch = 1; ch < num_channels_; ++ch) {
    507    gain_adjustment = std::min(gain_adjustment, gain_adjustments[ch]);
    508  }
    509  for (size_t ch = 0; ch < num_channels_; ++ch) {
    510    for (size_t i = 0; i < kFftSize; ++i) {
    511      filter_bank_states[ch].extended_frame[i] =
    512          gain_adjustment * filter_bank_states[ch].extended_frame[i];
    513    }
    514  }
    515 
    516  // Use overlap-and-add to form the output frame of the lowest band.
    517  for (size_t ch = 0; ch < num_channels_; ++ch) {
    518    ArrayView<float, kNsFrameSize> y_band0(&audio->split_bands(ch)[0][0],
    519                                           kNsFrameSize);
    520    OverlapAndAdd(filter_bank_states[ch].extended_frame,
    521                  channels_[ch]->process_synthesis_memory, y_band0);
    522  }
    523 
    524  if (num_bands_ > 1) {
    525    // Select the noise attenuating gain to apply to the upper band.
    526    float upper_band_gain = upper_band_gains[0];
    527    for (size_t ch = 1; ch < num_channels_; ++ch) {
    528      upper_band_gain = std::min(upper_band_gain, upper_band_gains[ch]);
    529    }
    530 
    531    // Process the upper bands.
    532    for (size_t ch = 0; ch < num_channels_; ++ch) {
    533      for (size_t b = 1; b < num_bands_; ++b) {
    534        // Delay the upper bands to match the delay of the filterbank applied to
    535        // the lowest band.
    536        ArrayView<float, kNsFrameSize> y_band(&audio->split_bands(ch)[b][0],
    537                                              kNsFrameSize);
    538        std::array<float, kNsFrameSize> delayed_frame;
    539        DelaySignal(y_band, channels_[ch]->process_delay_memory[b - 1],
    540                    delayed_frame);
    541 
    542        // Apply the time-domain noise-attenuating gain.
    543        for (size_t j = 0; j < kNsFrameSize; j++) {
    544          y_band[j] = upper_band_gain * delayed_frame[j];
    545        }
    546      }
    547    }
    548  }
    549 
    550  // Limit the output the allowed range.
    551  for (size_t ch = 0; ch < num_channels_; ++ch) {
    552    for (size_t b = 0; b < num_bands_; ++b) {
    553      ArrayView<float, kNsFrameSize> y_band(&audio->split_bands(ch)[b][0],
    554                                            kNsFrameSize);
    555      for (size_t j = 0; j < kNsFrameSize; j++) {
    556        y_band[j] = std::min(std::max(y_band[j], -32768.f), 32767.f);
    557      }
    558    }
    559  }
    560 }
    561 
    562 }  // namespace webrtc