Reland "Refactoring of the noise suppressor and adding true multichannel support"

This is a reland of 87a7b82520b83a6cf42da27cdc46142c2eb6248c

Original change's description:
> Refactoring of the noise suppressor and adding true multichannel support
> 
> This CL adds proper multichannel support to the noise suppressor.
> To accomplish that in a safe way, a full refactoring of the noise
> suppressor code has been done.
> 
> Due to floating point precision, the changes made are not entirely
> bitexact. They are, however, very close to being bitexact.
> 
> As a safety measure, the former noise suppressor code is preserved
> and a kill-switch is added to allow revering to the legacy noise
> suppressor in case issues arise.
> 
> Bug: webrtc:10895, b/143344262
> Change-Id: I0b071011b23265ac12e6d4b3956499d122286657
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158407
> Commit-Queue: Per Åhgren <peah@webrtc.org>
> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#29646}

Bug: webrtc:10895, b/143344262
Change-Id: I236f1e67bb0baa4e30908a4cf7a8a7bb55fbced3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158747
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29663}
diff --git a/modules/audio_processing/legacy_noise_suppression.cc b/modules/audio_processing/legacy_noise_suppression.cc
new file mode 100644
index 0000000..b2c8853
--- /dev/null
+++ b/modules/audio_processing/legacy_noise_suppression.cc
@@ -0,0 +1,172 @@
+/*
+ *  Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ *  Use of this source code is governed by a BSD-style license
+ *  that can be found in the LICENSE file in the root of the source
+ *  tree. An additional intellectual property rights grant can be found
+ *  in the file PATENTS.  All contributing project authors may
+ *  be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "modules/audio_processing/legacy_noise_suppression.h"
+
+#include "modules/audio_processing/audio_buffer.h"
+#include "rtc_base/checks.h"
+#if defined(WEBRTC_NS_FLOAT)
+#include "modules/audio_processing/legacy_ns/noise_suppression.h"
+
+#define NS_CREATE WebRtcNs_Create
+#define NS_FREE WebRtcNs_Free
+#define NS_INIT WebRtcNs_Init
+#define NS_SET_POLICY WebRtcNs_set_policy
+typedef NsHandle NsState;
+#elif defined(WEBRTC_NS_FIXED)
+#include "modules/audio_processing/legacy_ns/noise_suppression_x.h"
+
+#define NS_CREATE WebRtcNsx_Create
+#define NS_FREE WebRtcNsx_Free
+#define NS_INIT WebRtcNsx_Init
+#define NS_SET_POLICY WebRtcNsx_set_policy
+typedef NsxHandle NsState;
+#endif
+
+namespace webrtc {
+namespace {
+int NoiseSuppressionLevelToPolicy(NoiseSuppression::Level level) {
+  switch (level) {
+    case NoiseSuppression::Level::kLow:
+      return 0;
+    case NoiseSuppression::Level::kModerate:
+      return 1;
+    case NoiseSuppression::Level::kHigh:
+      return 2;
+    case NoiseSuppression::Level::kVeryHigh:
+      return 3;
+    default:
+      RTC_NOTREACHED();
+  }
+  return 1;
+}
+}  // namespace
+
+class NoiseSuppression::Suppressor {
+ public:
+  explicit Suppressor(int sample_rate_hz) {
+    state_ = NS_CREATE();
+    RTC_CHECK(state_);
+    int error = NS_INIT(state_, sample_rate_hz);
+    RTC_DCHECK_EQ(0, error);
+  }
+  ~Suppressor() { NS_FREE(state_); }
+
+  Suppressor(Suppressor&) = delete;
+  Suppressor& operator=(Suppressor&) = delete;
+
+  NsState* state() { return state_; }
+
+ private:
+  NsState* state_ = nullptr;
+};
+
+NoiseSuppression::NoiseSuppression(size_t channels,
+                                   int sample_rate_hz,
+                                   Level level) {
+  const int policy = NoiseSuppressionLevelToPolicy(level);
+  for (size_t i = 0; i < channels; ++i) {
+    suppressors_.push_back(std::make_unique<Suppressor>(sample_rate_hz));
+    int error = NS_SET_POLICY(suppressors_[i]->state(), policy);
+    RTC_DCHECK_EQ(0, error);
+  }
+}
+
+NoiseSuppression::~NoiseSuppression() {}
+
+void NoiseSuppression::AnalyzeCaptureAudio(AudioBuffer* audio) {
+  RTC_DCHECK(audio);
+#if defined(WEBRTC_NS_FLOAT)
+  RTC_DCHECK_GE(160, audio->num_frames_per_band());
+  RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
+  for (size_t i = 0; i < suppressors_.size(); i++) {
+    WebRtcNs_Analyze(suppressors_[i]->state(),
+                     audio->split_bands_const(i)[kBand0To8kHz]);
+  }
+#endif
+}
+
+void NoiseSuppression::ProcessCaptureAudio(AudioBuffer* audio) {
+  RTC_DCHECK(audio);
+  RTC_DCHECK_GE(160, audio->num_frames_per_band());
+  RTC_DCHECK_EQ(suppressors_.size(), audio->num_channels());
+  for (size_t i = 0; i < suppressors_.size(); i++) {
+#if defined(WEBRTC_NS_FLOAT)
+    WebRtcNs_Process(suppressors_[i]->state(), audio->split_bands_const(i),
+                     audio->num_bands(), audio->split_bands(i));
+#elif defined(WEBRTC_NS_FIXED)
+    int16_t split_band_data[AudioBuffer::kMaxNumBands]
+                           [AudioBuffer::kMaxSplitFrameLength];
+    int16_t* split_bands[AudioBuffer::kMaxNumBands] = {
+        split_band_data[0], split_band_data[1], split_band_data[2]};
+    audio->ExportSplitChannelData(i, split_bands);
+
+    WebRtcNsx_Process(suppressors_[i]->state(), split_bands, audio->num_bands(),
+                      split_bands);
+
+    audio->ImportSplitChannelData(i, split_bands);
+#endif
+  }
+}
+
+float NoiseSuppression::speech_probability() const {
+#if defined(WEBRTC_NS_FLOAT)
+  float probability_average = 0.0f;
+  for (auto& suppressor : suppressors_) {
+    probability_average +=
+        WebRtcNs_prior_speech_probability(suppressor->state());
+  }
+  if (!suppressors_.empty()) {
+    probability_average /= suppressors_.size();
+  }
+  return probability_average;
+#elif defined(WEBRTC_NS_FIXED)
+  // TODO(peah): Returning error code as a float! Remove this.
+  // Currently not available for the fixed point implementation.
+  return AudioProcessing::kUnsupportedFunctionError;
+#endif
+}
+
+std::vector<float> NoiseSuppression::NoiseEstimate() {
+  std::vector<float> noise_estimate;
+#if defined(WEBRTC_NS_FLOAT)
+  const float kNumChannelsFraction = 1.f / suppressors_.size();
+  noise_estimate.assign(WebRtcNs_num_freq(), 0.f);
+  for (auto& suppressor : suppressors_) {
+    const float* noise = WebRtcNs_noise_estimate(suppressor->state());
+    for (size_t i = 0; i < noise_estimate.size(); ++i) {
+      noise_estimate[i] += kNumChannelsFraction * noise[i];
+    }
+  }
+#elif defined(WEBRTC_NS_FIXED)
+  noise_estimate.assign(WebRtcNsx_num_freq(), 0.f);
+  for (auto& suppressor : suppressors_) {
+    int q_noise;
+    const uint32_t* noise =
+        WebRtcNsx_noise_estimate(suppressor->state(), &q_noise);
+    const float kNormalizationFactor =
+        1.f / ((1 << q_noise) * suppressors_.size());
+    for (size_t i = 0; i < noise_estimate.size(); ++i) {
+      noise_estimate[i] += kNormalizationFactor * noise[i];
+    }
+  }
+#endif
+  return noise_estimate;
+}
+
+size_t NoiseSuppression::num_noise_bins() {
+#if defined(WEBRTC_NS_FLOAT)
+  return WebRtcNs_num_freq();
+#elif defined(WEBRTC_NS_FIXED)
+  return WebRtcNsx_num_freq();
+#endif
+}
+
+}  // namespace webrtc