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/BUILD.gn b/modules/BUILD.gn
index ece91af..4fe4db5 100644
--- a/modules/BUILD.gn
+++ b/modules/BUILD.gn
@@ -229,6 +229,7 @@
       "audio_mixer:audio_mixer_unittests",
       "audio_processing:audio_processing_unittests",
       "audio_processing/aec3:aec3_unittests",
+      "audio_processing/ns:ns_unittests",
       "congestion_controller:congestion_controller_unittests",
       "pacing:pacing_unittests",
       "remote_bitrate_estimator:remote_bitrate_estimator_unittests",
diff --git a/modules/audio_processing/BUILD.gn b/modules/audio_processing/BUILD.gn
index f270416..57b49b2 100644
--- a/modules/audio_processing/BUILD.gn
+++ b/modules/audio_processing/BUILD.gn
@@ -132,10 +132,10 @@
     "gain_controller2.h",
     "include/aec_dump.cc",
     "include/aec_dump.h",
+    "legacy_noise_suppression.cc",
+    "legacy_noise_suppression.h",
     "level_estimator.cc",
     "level_estimator.h",
-    "noise_suppression.cc",
-    "noise_suppression.h",
     "render_queue_item_verifier.h",
     "residual_echo_detector.cc",
     "residual_echo_detector.h",
@@ -199,6 +199,7 @@
     "agc2:adaptive_digital",
     "agc2:fixed_digital",
     "agc2:gain_applier",
+    "ns",
     "vad",
     "//third_party/abseil-cpp/absl/types:optional",
   ]
@@ -287,29 +288,29 @@
 rtc_source_set("audio_processing_c") {
   visibility = [ ":*" ]  # Only targets in this file can depend on this.
   sources = [
-    "ns/windows_private.h",
+    "legacy_ns/windows_private.h",
   ]
 
   if (rtc_prefer_fixed_point) {
     sources += [
-      "ns/noise_suppression_x.c",
-      "ns/noise_suppression_x.h",
-      "ns/nsx_core.c",
-      "ns/nsx_core.h",
-      "ns/nsx_defines.h",
+      "legacy_ns/noise_suppression_x.c",
+      "legacy_ns/noise_suppression_x.h",
+      "legacy_ns/nsx_core.c",
+      "legacy_ns/nsx_core.h",
+      "legacy_ns/nsx_defines.h",
     ]
     if (current_cpu == "mipsel") {
-      sources += [ "ns/nsx_core_mips.c" ]
+      sources += [ "legacy_ns/nsx_core_mips.c" ]
     } else {
-      sources += [ "ns/nsx_core_c.c" ]
+      sources += [ "legacy_ns/nsx_core_c.c" ]
     }
   } else {
     sources += [
-      "ns/defines.h",
-      "ns/noise_suppression.c",
-      "ns/noise_suppression.h",
-      "ns/ns_core.c",
-      "ns/ns_core.h",
+      "legacy_ns/defines.h",
+      "legacy_ns/noise_suppression.c",
+      "legacy_ns/noise_suppression.h",
+      "legacy_ns/ns_core.c",
+      "legacy_ns/ns_core.h",
     ]
   }
 
@@ -324,7 +325,7 @@
   ]
 
   if (rtc_build_with_neon) {
-    sources += [ "ns/nsx_core_neon.c" ]
+    sources += [ "legacy_ns/nsx_core_neon.c" ]
 
     if (current_cpu != "arm64") {
       # Enable compilation for the NEON instruction set.
@@ -507,8 +508,8 @@
         "echo_detector/normalized_covariance_estimator_unittest.cc",
         "gain_control_unittest.cc",
         "high_pass_filter_unittest.cc",
+        "legacy_noise_suppression_unittest.cc",
         "level_estimator_unittest.cc",
-        "noise_suppression_unittest.cc",
         "residual_echo_detector_unittest.cc",
         "rms_level_unittest.cc",
         "test/debug_dump_replayer.cc",
diff --git a/modules/audio_processing/audio_processing_impl.cc b/modules/audio_processing/audio_processing_impl.cc
index f9e7bce..4573aed 100644
--- a/modules/audio_processing/audio_processing_impl.cc
+++ b/modules/audio_processing/audio_processing_impl.cc
@@ -70,6 +70,11 @@
          sample_rate_hz == AudioProcessing::kSampleRate48kHz;
 }
 
+// Checks whether the legacy ns functionality should be enforced.
+bool DetectLegacyNsEnforcement() {
+  return field_trial::IsEnabled("WebRTC-NewNoiseSuppressionKillSwitch");
+}
+
 // Identify the native processing rate that best handles a sample rate.
 int SuitableProcessRate(int minimum_rate,
                         int max_splitting_rate,
@@ -306,6 +311,7 @@
     std::unique_ptr<CustomAudioAnalyzer> capture_analyzer)
     : data_dumper_(
           new ApmDataDumper(rtc::AtomicOps::Increment(&instance_count_))),
+      enforced_usage_of_legacy_ns_(DetectLegacyNsEnforcement()),
       capture_runtime_settings_(kRuntimeSettingQueueSize),
       render_runtime_settings_(kRuntimeSettingQueueSize),
       capture_runtime_settings_enqueuer_(&capture_runtime_settings_),
@@ -1303,9 +1309,14 @@
   if (submodules_.high_pass_filter) {
     submodules_.high_pass_filter->Process(capture_buffer);
   }
+
   RETURN_ON_ERR(submodules_.gain_control->AnalyzeCaptureAudio(capture_buffer));
+  RTC_DCHECK(
+      !(submodules_.legacy_noise_suppressor && submodules_.noise_suppressor));
   if (submodules_.noise_suppressor) {
-    submodules_.noise_suppressor->AnalyzeCaptureAudio(capture_buffer);
+    submodules_.noise_suppressor->Analyze(*capture_buffer);
+  } else if (submodules_.legacy_noise_suppressor) {
+    submodules_.legacy_noise_suppressor->AnalyzeCaptureAudio(capture_buffer);
   }
 
   if (submodules_.echo_control_mobile) {
@@ -1316,8 +1327,10 @@
     }
 
     if (submodules_.noise_suppressor) {
+      submodules_.noise_suppressor->Process(capture_buffer);
+    } else if (submodules_.legacy_noise_suppressor) {
       submodules_.echo_control_mobile->CopyLowPassReference(capture_buffer);
-      submodules_.noise_suppressor->ProcessCaptureAudio(capture_buffer);
+      submodules_.legacy_noise_suppressor->ProcessCaptureAudio(capture_buffer);
     }
 
     RETURN_ON_ERR(submodules_.echo_control_mobile->ProcessCaptureAudio(
@@ -1344,7 +1357,9 @@
     }
 
     if (submodules_.noise_suppressor) {
-      submodules_.noise_suppressor->ProcessCaptureAudio(capture_buffer);
+      submodules_.noise_suppressor->Process(capture_buffer);
+    } else if (submodules_.legacy_noise_suppressor) {
+      submodules_.legacy_noise_suppressor->ProcessCaptureAudio(capture_buffer);
     }
   }
 
@@ -1726,9 +1741,9 @@
   return submodule_states_.Update(
       config_.high_pass_filter.enabled, !!submodules_.echo_cancellation,
       !!submodules_.echo_control_mobile, config_.residual_echo_detector.enabled,
-      !!submodules_.noise_suppressor, submodules_.gain_control->is_enabled(),
-      config_.gain_controller2.enabled, config_.pre_amplifier.enabled,
-      capture_nonlocked_.echo_controller_enabled,
+      !!submodules_.legacy_noise_suppressor || !!submodules_.noise_suppressor,
+      submodules_.gain_control->is_enabled(), config_.gain_controller2.enabled,
+      config_.pre_amplifier.enabled, capture_nonlocked_.echo_controller_enabled,
       config_.voice_detection.enabled, capture_.transient_suppressor_enabled);
 }
 
@@ -1868,13 +1883,42 @@
 }
 
 void AudioProcessingImpl::InitializeNoiseSuppressor() {
+  submodules_.legacy_noise_suppressor.reset();
+  submodules_.noise_suppressor.reset();
+
   if (config_.noise_suppression.enabled) {
-    auto ns_level =
-        NsConfigLevelToInterfaceLevel(config_.noise_suppression.level);
-    submodules_.noise_suppressor = std::make_unique<NoiseSuppression>(
-        num_proc_channels(), proc_sample_rate_hz(), ns_level);
-  } else {
-    submodules_.noise_suppressor.reset();
+    const bool use_legacy_ns =
+        config_.noise_suppression.use_legacy_ns || enforced_usage_of_legacy_ns_;
+
+    if (!use_legacy_ns) {
+      auto map_level =
+          [](AudioProcessing::Config::NoiseSuppression::Level level) {
+            using NoiseSuppresionConfig =
+                AudioProcessing::Config::NoiseSuppression;
+            switch (level) {
+              case NoiseSuppresionConfig::kLow:
+                return NsConfig::SuppressionLevel::k6dB;
+              case NoiseSuppresionConfig::kModerate:
+                return NsConfig::SuppressionLevel::k12dB;
+              case NoiseSuppresionConfig::kHigh:
+                return NsConfig::SuppressionLevel::k18dB;
+              case NoiseSuppresionConfig::kVeryHigh:
+                return NsConfig::SuppressionLevel::k21dB;
+              default:
+                RTC_NOTREACHED();
+            }
+          };
+
+      NsConfig cfg;
+      cfg.target_level = map_level(config_.noise_suppression.level);
+      submodules_.noise_suppressor = std::make_unique<NoiseSuppressor>(
+          cfg, proc_sample_rate_hz(), num_proc_channels());
+    } else {
+      auto ns_level =
+          NsConfigLevelToInterfaceLevel(config_.noise_suppression.level);
+      submodules_.legacy_noise_suppressor = std::make_unique<NoiseSuppression>(
+          num_proc_channels(), proc_sample_rate_hz(), ns_level);
+    }
   }
 }
 
diff --git a/modules/audio_processing/audio_processing_impl.h b/modules/audio_processing/audio_processing_impl.h
index eb1fe7f..3e1b466 100644
--- a/modules/audio_processing/audio_processing_impl.h
+++ b/modules/audio_processing/audio_processing_impl.h
@@ -29,8 +29,9 @@
 #include "modules/audio_processing/include/aec_dump.h"
 #include "modules/audio_processing/include/audio_processing.h"
 #include "modules/audio_processing/include/audio_processing_statistics.h"
+#include "modules/audio_processing/legacy_noise_suppression.h"
 #include "modules/audio_processing/level_estimator.h"
-#include "modules/audio_processing/noise_suppression.h"
+#include "modules/audio_processing/ns/noise_suppressor.h"
 #include "modules/audio_processing/render_queue_item_verifier.h"
 #include "modules/audio_processing/residual_echo_detector.h"
 #include "modules/audio_processing/rms_level.h"
@@ -150,6 +151,7 @@
 
   std::unique_ptr<ApmDataDumper> data_dumper_;
   static int instance_count_;
+  const bool enforced_usage_of_legacy_ns_;
 
   SwapQueue<RuntimeSetting> capture_runtime_settings_;
   SwapQueue<RuntimeSetting> render_runtime_settings_;
@@ -343,7 +345,8 @@
     std::unique_ptr<EchoCancellationImpl> echo_cancellation;
     std::unique_ptr<EchoControl> echo_controller;
     std::unique_ptr<EchoControlMobileImpl> echo_control_mobile;
-    std::unique_ptr<NoiseSuppression> noise_suppressor;
+    std::unique_ptr<NoiseSuppression> legacy_noise_suppressor;
+    std::unique_ptr<NoiseSuppressor> noise_suppressor;
     std::unique_ptr<TransientSuppressor> transient_suppressor;
     std::unique_ptr<CustomProcessing> capture_post_processor;
     std::unique_ptr<CustomProcessing> render_pre_processor;
diff --git a/modules/audio_processing/audio_processing_unittest.cc b/modules/audio_processing/audio_processing_unittest.cc
index 1aac2cf..094823d 100644
--- a/modules/audio_processing/audio_processing_unittest.cc
+++ b/modules/audio_processing/audio_processing_unittest.cc
@@ -2145,30 +2145,30 @@
                       std::make_tuple(44100, 16000, 32000, 16000, 19, 20),
                       std::make_tuple(44100, 16000, 16000, 16000, 19, 0),
 
-                      std::make_tuple(32000, 48000, 48000, 48000, 35, 0),
+                      std::make_tuple(32000, 48000, 48000, 48000, 28, 0),
                       std::make_tuple(32000, 48000, 32000, 48000, 65, 30),
-                      std::make_tuple(32000, 48000, 16000, 48000, 40, 20),
+                      std::make_tuple(32000, 48000, 16000, 48000, 30, 20),
                       std::make_tuple(32000, 44100, 48000, 44100, 20, 20),
                       std::make_tuple(32000, 44100, 32000, 44100, 20, 15),
                       std::make_tuple(32000, 44100, 16000, 44100, 20, 15),
-                      std::make_tuple(32000, 32000, 48000, 32000, 35, 35),
+                      std::make_tuple(32000, 32000, 48000, 32000, 29, 35),
                       std::make_tuple(32000, 32000, 32000, 32000, 0, 0),
-                      std::make_tuple(32000, 32000, 16000, 32000, 40, 20),
+                      std::make_tuple(32000, 32000, 16000, 32000, 32, 20),
                       std::make_tuple(32000, 16000, 48000, 16000, 20, 20),
                       std::make_tuple(32000, 16000, 32000, 16000, 20, 20),
                       std::make_tuple(32000, 16000, 16000, 16000, 20, 0),
 
-                      std::make_tuple(16000, 48000, 48000, 48000, 25, 0),
+                      std::make_tuple(16000, 48000, 48000, 48000, 24, 0),
                       std::make_tuple(16000, 48000, 32000, 48000, 25, 30),
                       std::make_tuple(16000, 48000, 16000, 48000, 25, 20),
                       std::make_tuple(16000, 44100, 48000, 44100, 15, 20),
                       std::make_tuple(16000, 44100, 32000, 44100, 15, 15),
                       std::make_tuple(16000, 44100, 16000, 44100, 15, 15),
-                      std::make_tuple(16000, 32000, 48000, 32000, 25, 35),
+                      std::make_tuple(16000, 32000, 48000, 32000, 24, 35),
                       std::make_tuple(16000, 32000, 32000, 32000, 25, 0),
                       std::make_tuple(16000, 32000, 16000, 32000, 25, 20),
-                      std::make_tuple(16000, 16000, 48000, 16000, 35, 20),
-                      std::make_tuple(16000, 16000, 32000, 16000, 35, 20),
+                      std::make_tuple(16000, 16000, 48000, 16000, 30, 20),
+                      std::make_tuple(16000, 16000, 32000, 16000, 30, 20),
                       std::make_tuple(16000, 16000, 16000, 16000, 0, 0)));
 #endif
 
diff --git a/modules/audio_processing/include/audio_processing.h b/modules/audio_processing/include/audio_processing.h
index f516015..8c46155 100644
--- a/modules/audio_processing/include/audio_processing.h
+++ b/modules/audio_processing/include/audio_processing.h
@@ -285,6 +285,8 @@
       bool enabled = false;
       enum Level { kLow, kModerate, kHigh, kVeryHigh };
       Level level = kModerate;
+      // Recommended not to use. Will be removed in the future.
+      bool use_legacy_ns = false;
     } noise_suppression;
 
     // Enables reporting of |voice_detected| in webrtc::AudioProcessingStats.
diff --git a/modules/audio_processing/noise_suppression.cc b/modules/audio_processing/legacy_noise_suppression.cc
similarity index 96%
rename from modules/audio_processing/noise_suppression.cc
rename to modules/audio_processing/legacy_noise_suppression.cc
index b8ddd30..b2c8853 100644
--- a/modules/audio_processing/noise_suppression.cc
+++ b/modules/audio_processing/legacy_noise_suppression.cc
@@ -8,12 +8,12 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "modules/audio_processing/noise_suppression.h"
+#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/ns/noise_suppression.h"
+#include "modules/audio_processing/legacy_ns/noise_suppression.h"
 
 #define NS_CREATE WebRtcNs_Create
 #define NS_FREE WebRtcNs_Free
@@ -21,7 +21,7 @@
 #define NS_SET_POLICY WebRtcNs_set_policy
 typedef NsHandle NsState;
 #elif defined(WEBRTC_NS_FIXED)
-#include "modules/audio_processing/ns/noise_suppression_x.h"
+#include "modules/audio_processing/legacy_ns/noise_suppression_x.h"
 
 #define NS_CREATE WebRtcNsx_Create
 #define NS_FREE WebRtcNsx_Free
diff --git a/modules/audio_processing/noise_suppression.h b/modules/audio_processing/legacy_noise_suppression.h
similarity index 90%
rename from modules/audio_processing/noise_suppression.h
rename to modules/audio_processing/legacy_noise_suppression.h
index df5aed4..c2435db 100644
--- a/modules/audio_processing/noise_suppression.h
+++ b/modules/audio_processing/legacy_noise_suppression.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_H_
-#define MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_H_
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NOISE_SUPPRESSION_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NOISE_SUPPRESSION_H_
 
 #include <memory>
 #include <vector>
@@ -54,4 +54,4 @@
 };
 }  // namespace webrtc
 
-#endif  // MODULES_AUDIO_PROCESSING_NOISE_SUPPRESSION_H_
+#endif  // MODULES_AUDIO_PROCESSING_LEGACY_NOISE_SUPPRESSION_H_
diff --git a/modules/audio_processing/noise_suppression_unittest.cc b/modules/audio_processing/legacy_noise_suppression_unittest.cc
similarity index 95%
rename from modules/audio_processing/noise_suppression_unittest.cc
rename to modules/audio_processing/legacy_noise_suppression_unittest.cc
index 649fc93..57deedb 100644
--- a/modules/audio_processing/noise_suppression_unittest.cc
+++ b/modules/audio_processing/legacy_noise_suppression_unittest.cc
@@ -11,7 +11,7 @@
 
 #include "api/array_view.h"
 #include "modules/audio_processing/audio_buffer.h"
-#include "modules/audio_processing/noise_suppression.h"
+#include "modules/audio_processing/legacy_noise_suppression.h"
 #include "modules/audio_processing/test/audio_buffer_tools.h"
 #include "modules/audio_processing/test/bitexactness_tools.h"
 #include "test/gtest.h"
@@ -90,7 +90,7 @@
 
 }  // namespace
 
-TEST(NoiseSuppresionBitExactnessTest, Mono8kHzLow) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Mono8kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {1432.341431f, 3321.919922f,
@@ -113,7 +113,7 @@
                       kOutputReference);
 }
 
-TEST(NoiseSuppresionBitExactnessTest, Mono16kHzLow) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Mono16kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {2534.461914f, 6277.638672f,
@@ -136,7 +136,7 @@
                       kOutputReference);
 }
 
-TEST(NoiseSuppresionBitExactnessTest, Mono32kHzLow) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Mono32kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {2540.059082f, 6317.822754f,
@@ -159,7 +159,7 @@
                       kOutputReference);
 }
 
-TEST(NoiseSuppresionBitExactnessTest, Mono48kHzLow) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Mono48kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {2135.292480f, 6692.695801f,
@@ -182,7 +182,7 @@
                       kOutputReference);
 }
 
-TEST(NoiseSuppresionBitExactnessTest, Stereo16kHzLow) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Stereo16kHzLow) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {9992.127930f, 12689.569336f,
@@ -208,7 +208,7 @@
                       kOutputReference);
 }
 
-TEST(NoiseSuppresionBitExactnessTest, Mono16kHzModerate) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Mono16kHzModerate) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {2057.085938f, 7601.055176f,
@@ -231,7 +231,7 @@
                       kOutputReference);
 }
 
-TEST(NoiseSuppresionBitExactnessTest, Mono16kHzHigh) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Mono16kHzHigh) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {2095.148193f, 7698.553711f,
@@ -254,7 +254,7 @@
                       kOutputReference);
 }
 
-TEST(NoiseSuppresionBitExactnessTest, Mono16kHzVeryHigh) {
+TEST(LegacyNoiseSuppresionBitExactnessTest, Mono16kHzVeryHigh) {
 #if defined(WEBRTC_ARCH_ARM64)
   const float kSpeechProbabilityReference = -4.0f;
   const float kNoiseEstimateReference[] = {2677.733398f, 6186.987305f,
diff --git a/modules/audio_processing/legacy_ns/defines.h b/modules/audio_processing/legacy_ns/defines.h
new file mode 100644
index 0000000..02e0318
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/defines.h
@@ -0,0 +1,52 @@
+/*
+ *  Copyright (c) 2011 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NS_DEFINES_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_DEFINES_H_
+
+#define BLOCKL_MAX 160        // max processing block length: 160
+#define ANAL_BLOCKL_MAX 256   // max analysis block length: 256
+#define HALF_ANAL_BLOCKL 129  // half max analysis block length + 1
+#define NUM_HIGH_BANDS_MAX 2  // max number of high bands: 2
+
+#define QUANTILE 0.25f
+
+#define SIMULT 3
+#define END_STARTUP_LONG 200
+#define END_STARTUP_SHORT 50
+#define FACTOR 40.f
+#define WIDTH 0.01f
+
+// Length of fft work arrays.
+#define IP_LENGTH \
+  (ANAL_BLOCKL_MAX >> 1)  // must be at least ceil(2 + sqrt(ANAL_BLOCKL_MAX/2))
+#define W_LENGTH (ANAL_BLOCKL_MAX >> 1)
+
+// PARAMETERS FOR NEW METHOD
+#define DD_PR_SNR 0.98f        // DD update of prior SNR
+#define LRT_TAVG 0.5f          // tavg parameter for LRT (previously 0.90)
+#define SPECT_FL_TAVG 0.30f    // tavg parameter for spectral flatness measure
+#define SPECT_DIFF_TAVG 0.30f  // tavg parameter for spectral difference measure
+#define PRIOR_UPDATE 0.1f      // update parameter of prior model
+#define NOISE_UPDATE 0.9f      // update parameter for noise
+#define SPEECH_UPDATE 0.99f    // update parameter when likely speech
+#define WIDTH_PR_MAP 4.0f      // width parameter in sigmoid map for prior model
+#define LRT_FEATURE_THR 0.5f   // default threshold for LRT feature
+#define SF_FEATURE_THR 0.5f  // default threshold for Spectral Flatness feature
+#define SD_FEATURE_THR \
+  0.5f  // default threshold for Spectral Difference feature
+#define PROB_RANGE \
+  0.2f                     // probability threshold for noise state in
+                           // speech/noise likelihood
+#define HIST_PAR_EST 1000  // histogram size for estimation of parameters
+#define GAMMA_PAUSE 0.05f  // update for conservative noise estimate
+//
+#define B_LIM 0.5f  // threshold in final energy gain factor calculation
+#endif              // MODULES_AUDIO_PROCESSING_LEGACY_NS_DEFINES_H_
diff --git a/modules/audio_processing/ns/noise_suppression.c b/modules/audio_processing/legacy_ns/noise_suppression.c
similarity index 91%
rename from modules/audio_processing/ns/noise_suppression.c
rename to modules/audio_processing/legacy_ns/noise_suppression.c
index e21416f..8b95640 100644
--- a/modules/audio_processing/ns/noise_suppression.c
+++ b/modules/audio_processing/legacy_ns/noise_suppression.c
@@ -8,14 +8,14 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "modules/audio_processing/ns/noise_suppression.h"
+#include "modules/audio_processing/legacy_ns/noise_suppression.h"
 
 #include <stdlib.h>
 #include <string.h>
 
 #include "common_audio/signal_processing/include/signal_processing_library.h"
-#include "modules/audio_processing/ns/defines.h"
-#include "modules/audio_processing/ns/ns_core.h"
+#include "modules/audio_processing/legacy_ns/defines.h"
+#include "modules/audio_processing/legacy_ns/ns_core.h"
 
 NsHandle* WebRtcNs_Create() {
   NoiseSuppressionC* self = malloc(sizeof(NoiseSuppressionC));
diff --git a/modules/audio_processing/ns/noise_suppression.h b/modules/audio_processing/legacy_ns/noise_suppression.h
similarity index 94%
rename from modules/audio_processing/ns/noise_suppression.h
rename to modules/audio_processing/legacy_ns/noise_suppression.h
index 0775ffa..01f04cc 100644
--- a/modules/audio_processing/ns/noise_suppression.h
+++ b/modules/audio_processing/legacy_ns/noise_suppression.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_H_
-#define MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_H_
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -131,4 +131,4 @@
 }
 #endif
 
-#endif  // MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_H_
+#endif  // MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_H_
diff --git a/modules/audio_processing/ns/noise_suppression_x.c b/modules/audio_processing/legacy_ns/noise_suppression_x.c
similarity index 85%
rename from modules/audio_processing/ns/noise_suppression_x.c
rename to modules/audio_processing/legacy_ns/noise_suppression_x.c
index c6faf75..faa866e 100644
--- a/modules/audio_processing/ns/noise_suppression_x.c
+++ b/modules/audio_processing/legacy_ns/noise_suppression_x.c
@@ -8,13 +8,13 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "modules/audio_processing/ns/noise_suppression_x.h"
+#include "modules/audio_processing/legacy_ns/noise_suppression_x.h"
 
 #include <stdlib.h>
 
 #include "common_audio/signal_processing/include/real_fft.h"
-#include "modules/audio_processing/ns/nsx_core.h"
-#include "modules/audio_processing/ns/nsx_defines.h"
+#include "modules/audio_processing/legacy_ns/nsx_core.h"
+#include "modules/audio_processing/legacy_ns/nsx_defines.h"
 
 NsxHandle* WebRtcNsx_Create() {
   NoiseSuppressionFixedC* self = malloc(sizeof(NoiseSuppressionFixedC));
@@ -37,9 +37,9 @@
 }
 
 void WebRtcNsx_Process(NsxHandle* nsxInst,
-                      const short* const* speechFrame,
+                      const int16_t* const* speechFrame,
                       int num_bands,
-                      short* const* outFrame) {
+                      int16_t* const* outFrame) {
   WebRtcNsx_ProcessCore((NoiseSuppressionFixedC*)nsxInst, speechFrame,
                         num_bands, outFrame);
 }
diff --git a/modules/audio_processing/ns/noise_suppression_x.h b/modules/audio_processing/legacy_ns/noise_suppression_x.h
similarity index 90%
rename from modules/audio_processing/ns/noise_suppression_x.h
rename to modules/audio_processing/legacy_ns/noise_suppression_x.h
index 972784e..572db41 100644
--- a/modules/audio_processing/ns/noise_suppression_x.h
+++ b/modules/audio_processing/legacy_ns/noise_suppression_x.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_X_H_
-#define MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_X_H_
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_X_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_X_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -78,9 +78,9 @@
  *      - outFrame      : Pointer to output frame for each band
  */
 void WebRtcNsx_Process(NsxHandle* nsxInst,
-                       const short* const* speechFrame,
+                       const int16_t* const* speechFrame,
                        int num_bands,
-                       short* const* outFrame);
+                       int16_t* const* outFrame);
 
 /* Returns a pointer to the noise estimate per frequency bin. The number of
  * frequency bins can be provided using WebRtcNsx_num_freq().
@@ -109,4 +109,4 @@
 }
 #endif
 
-#endif  // MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSION_X_H_
+#endif  // MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_X_H_
diff --git a/modules/audio_processing/ns/ns_core.c b/modules/audio_processing/legacy_ns/ns_core.c
similarity index 99%
rename from modules/audio_processing/ns/ns_core.c
rename to modules/audio_processing/legacy_ns/ns_core.c
index bc5dd6d..b5dc829 100644
--- a/modules/audio_processing/ns/ns_core.c
+++ b/modules/audio_processing/legacy_ns/ns_core.c
@@ -15,9 +15,9 @@
 #include "rtc_base/checks.h"
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 #include "common_audio/third_party/fft4g/fft4g.h"
-#include "modules/audio_processing/ns/noise_suppression.h"
-#include "modules/audio_processing/ns/ns_core.h"
-#include "modules/audio_processing/ns/windows_private.h"
+#include "modules/audio_processing/legacy_ns/noise_suppression.h"
+#include "modules/audio_processing/legacy_ns/ns_core.h"
+#include "modules/audio_processing/legacy_ns/windows_private.h"
 
 // Set Feature Extraction Parameters.
 static void set_feature_extraction_parameters(NoiseSuppressionC* self) {
diff --git a/modules/audio_processing/ns/ns_core.h b/modules/audio_processing/legacy_ns/ns_core.h
similarity index 96%
rename from modules/audio_processing/ns/ns_core.h
rename to modules/audio_processing/legacy_ns/ns_core.h
index e90b8ce..7a3b0a4 100644
--- a/modules/audio_processing/ns/ns_core.h
+++ b/modules/audio_processing/legacy_ns/ns_core.h
@@ -8,10 +8,10 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef MODULES_AUDIO_PROCESSING_NS_NS_CORE_H_
-#define MODULES_AUDIO_PROCESSING_NS_NS_CORE_H_
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NS_NS_CORE_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NS_CORE_H_
 
-#include "modules/audio_processing/ns/defines.h"
+#include "modules/audio_processing/legacy_ns/defines.h"
 
 typedef struct NSParaExtract_ {
   // Bin size of histogram.
@@ -46,7 +46,6 @@
   // Criteria of weight of histogram peak to accept/reject feature.
   int thresWeightSpecFlat;
   int thresWeightSpecDiff;
-
 } NSParaExtract;
 
 typedef struct NoiseSuppressionC_ {
@@ -186,4 +185,4 @@
 #ifdef __cplusplus
 }
 #endif
-#endif  // MODULES_AUDIO_PROCESSING_NS_NS_CORE_H_
+#endif  // MODULES_AUDIO_PROCESSING_LEGACY_NS_NS_CORE_H_
diff --git a/modules/audio_processing/legacy_ns/nsx_core.c b/modules/audio_processing/legacy_ns/nsx_core.c
new file mode 100644
index 0000000..aa1e73b
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/nsx_core.c
@@ -0,0 +1,2154 @@
+/*
+ *  Copyright (c) 2012 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_ns/noise_suppression_x.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "common_audio/signal_processing/include/real_fft.h"
+#include "modules/audio_processing/legacy_ns/nsx_core.h"
+#include "rtc_base/checks.h"
+#include "system_wrappers/include/cpu_features_wrapper.h"
+
+#if defined(WEBRTC_HAS_NEON)
+/* Tables are defined in ARM assembly files. */
+extern const int16_t WebRtcNsx_kLogTable[9];
+extern const int16_t WebRtcNsx_kCounterDiv[201];
+extern const int16_t WebRtcNsx_kLogTableFrac[256];
+#else
+static const int16_t WebRtcNsx_kLogTable[9] = {0,   177,  355,  532, 710,
+                                               887, 1065, 1242, 1420};
+
+static const int16_t WebRtcNsx_kCounterDiv[201] = {
+    32767, 16384, 10923, 8192, 6554, 5461, 4681, 4096, 3641, 3277, 2979, 2731,
+    2521,  2341,  2185,  2048, 1928, 1820, 1725, 1638, 1560, 1489, 1425, 1365,
+    1311,  1260,  1214,  1170, 1130, 1092, 1057, 1024, 993,  964,  936,  910,
+    886,   862,   840,   819,  799,  780,  762,  745,  728,  712,  697,  683,
+    669,   655,   643,   630,  618,  607,  596,  585,  575,  565,  555,  546,
+    537,   529,   520,   512,  504,  496,  489,  482,  475,  468,  462,  455,
+    449,   443,   437,   431,  426,  420,  415,  410,  405,  400,  395,  390,
+    386,   381,   377,   372,  368,  364,  360,  356,  352,  349,  345,  341,
+    338,   334,   331,   328,  324,  321,  318,  315,  312,  309,  306,  303,
+    301,   298,   295,   293,  290,  287,  285,  282,  280,  278,  275,  273,
+    271,   269,   266,   264,  262,  260,  258,  256,  254,  252,  250,  248,
+    246,   245,   243,   241,  239,  237,  236,  234,  232,  231,  229,  228,
+    226,   224,   223,   221,  220,  218,  217,  216,  214,  213,  211,  210,
+    209,   207,   206,   205,  204,  202,  201,  200,  199,  197,  196,  195,
+    194,   193,   192,   191,  189,  188,  187,  186,  185,  184,  183,  182,
+    181,   180,   179,   178,  177,  176,  175,  174,  173,  172,  172,  171,
+    170,   169,   168,   167,  166,  165,  165,  164,  163};
+
+static const int16_t WebRtcNsx_kLogTableFrac[256] = {
+    0,   1,   3,   4,   6,   7,   9,   10,  11,  13,  14,  16,  17,  18,  20,
+    21,  22,  24,  25,  26,  28,  29,  30,  32,  33,  34,  36,  37,  38,  40,
+    41,  42,  44,  45,  46,  47,  49,  50,  51,  52,  54,  55,  56,  57,  59,
+    60,  61,  62,  63,  65,  66,  67,  68,  69,  71,  72,  73,  74,  75,  77,
+    78,  79,  80,  81,  82,  84,  85,  86,  87,  88,  89,  90,  92,  93,  94,
+    95,  96,  97,  98,  99,  100, 102, 103, 104, 105, 106, 107, 108, 109, 110,
+    111, 112, 113, 114, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126,
+    127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141,
+    142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 155,
+    156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 169,
+    170, 171, 172, 173, 174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 183,
+    184, 185, 185, 186, 187, 188, 189, 190, 191, 192, 192, 193, 194, 195, 196,
+    197, 198, 198, 199, 200, 201, 202, 203, 203, 204, 205, 206, 207, 208, 208,
+    209, 210, 211, 212, 212, 213, 214, 215, 216, 216, 217, 218, 219, 220, 220,
+    221, 222, 223, 224, 224, 225, 226, 227, 228, 228, 229, 230, 231, 231, 232,
+    233, 234, 234, 235, 236, 237, 238, 238, 239, 240, 241, 241, 242, 243, 244,
+    244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 252, 252, 253, 254, 255,
+    255};
+#endif  // WEBRTC_HAS_NEON
+
+// Skip first frequency bins during estimation. (0 <= value < 64)
+static const size_t kStartBand = 5;
+
+// hybrib Hanning & flat window
+static const int16_t kBlocks80w128x[128] = {
+    0,     536,   1072,  1606,  2139,  2669,  3196,  3720,  4240,  4756,  5266,
+    5771,  6270,  6762,  7246,  7723,  8192,  8652,  9102,  9543,  9974,  10394,
+    10803, 11200, 11585, 11958, 12318, 12665, 12998, 13318, 13623, 13913, 14189,
+    14449, 14694, 14924, 15137, 15334, 15515, 15679, 15826, 15956, 16069, 16165,
+    16244, 16305, 16349, 16375, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16375, 16349, 16305, 16244, 16165, 16069, 15956,
+    15826, 15679, 15515, 15334, 15137, 14924, 14694, 14449, 14189, 13913, 13623,
+    13318, 12998, 12665, 12318, 11958, 11585, 11200, 10803, 10394, 9974,  9543,
+    9102,  8652,  8192,  7723,  7246,  6762,  6270,  5771,  5266,  4756,  4240,
+    3720,  3196,  2669,  2139,  1606,  1072,  536};
+
+// hybrib Hanning & flat window
+static const int16_t kBlocks160w256x[256] = {
+    0,     268,   536,   804,   1072,  1339,  1606,  1872,  2139,  2404,  2669,
+    2933,  3196,  3459,  3720,  3981,  4240,  4499,  4756,  5012,  5266,  5520,
+    5771,  6021,  6270,  6517,  6762,  7005,  7246,  7486,  7723,  7959,  8192,
+    8423,  8652,  8878,  9102,  9324,  9543,  9760,  9974,  10185, 10394, 10600,
+    10803, 11003, 11200, 11394, 11585, 11773, 11958, 12140, 12318, 12493, 12665,
+    12833, 12998, 13160, 13318, 13472, 13623, 13770, 13913, 14053, 14189, 14321,
+    14449, 14574, 14694, 14811, 14924, 15032, 15137, 15237, 15334, 15426, 15515,
+    15599, 15679, 15754, 15826, 15893, 15956, 16015, 16069, 16119, 16165, 16207,
+    16244, 16277, 16305, 16329, 16349, 16364, 16375, 16382, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
+    16384, 16384, 16384, 16384, 16384, 16384, 16384, 16382, 16375, 16364, 16349,
+    16329, 16305, 16277, 16244, 16207, 16165, 16119, 16069, 16015, 15956, 15893,
+    15826, 15754, 15679, 15599, 15515, 15426, 15334, 15237, 15137, 15032, 14924,
+    14811, 14694, 14574, 14449, 14321, 14189, 14053, 13913, 13770, 13623, 13472,
+    13318, 13160, 12998, 12833, 12665, 12493, 12318, 12140, 11958, 11773, 11585,
+    11394, 11200, 11003, 10803, 10600, 10394, 10185, 9974,  9760,  9543,  9324,
+    9102,  8878,  8652,  8423,  8192,  7959,  7723,  7486,  7246,  7005,  6762,
+    6517,  6270,  6021,  5771,  5520,  5266,  5012,  4756,  4499,  4240,  3981,
+    3720,  3459,  3196,  2933,  2669,  2404,  2139,  1872,  1606,  1339,  1072,
+    804,   536,   268};
+
+// Gain factor1 table: Input value in Q8 and output value in Q13
+// original floating point code
+//  if (gain > blim) {
+//    factor1 = 1.0 + 1.3 * (gain - blim);
+//    if (gain * factor1 > 1.0) {
+//      factor1 = 1.0 / gain;
+//    }
+//  } else {
+//    factor1 = 1.0;
+//  }
+static const int16_t kFactor1Table[257] = {
+    8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,
+    8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,
+    8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,
+    8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,
+    8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,
+    8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8192,  8233,
+    8274,  8315,  8355,  8396,  8436,  8475,  8515,  8554,  8592,  8631,  8669,
+    8707,  8745,  8783,  8820,  8857,  8894,  8931,  8967,  9003,  9039,  9075,
+    9111,  9146,  9181,  9216,  9251,  9286,  9320,  9354,  9388,  9422,  9456,
+    9489,  9523,  9556,  9589,  9622,  9655,  9687,  9719,  9752,  9784,  9816,
+    9848,  9879,  9911,  9942,  9973,  10004, 10035, 10066, 10097, 10128, 10158,
+    10188, 10218, 10249, 10279, 10308, 10338, 10368, 10397, 10426, 10456, 10485,
+    10514, 10543, 10572, 10600, 10629, 10657, 10686, 10714, 10742, 10770, 10798,
+    10826, 10854, 10882, 10847, 10810, 10774, 10737, 10701, 10666, 10631, 10596,
+    10562, 10527, 10494, 10460, 10427, 10394, 10362, 10329, 10297, 10266, 10235,
+    10203, 10173, 10142, 10112, 10082, 10052, 10023, 9994,  9965,  9936,  9908,
+    9879,  9851,  9824,  9796,  9769,  9742,  9715,  9689,  9662,  9636,  9610,
+    9584,  9559,  9534,  9508,  9484,  9459,  9434,  9410,  9386,  9362,  9338,
+    9314,  9291,  9268,  9245,  9222,  9199,  9176,  9154,  9132,  9110,  9088,
+    9066,  9044,  9023,  9002,  8980,  8959,  8939,  8918,  8897,  8877,  8857,
+    8836,  8816,  8796,  8777,  8757,  8738,  8718,  8699,  8680,  8661,  8642,
+    8623,  8605,  8586,  8568,  8550,  8532,  8514,  8496,  8478,  8460,  8443,
+    8425,  8408,  8391,  8373,  8356,  8339,  8323,  8306,  8289,  8273,  8256,
+    8240,  8224,  8208,  8192};
+
+// For Factor2 tables
+// original floating point code
+// if (gain > blim) {
+//   factor2 = 1.0;
+// } else {
+//   factor2 = 1.0 - 0.3 * (blim - gain);
+//   if (gain <= inst->denoiseBound) {
+//     factor2 = 1.0 - 0.3 * (blim - inst->denoiseBound);
+//   }
+// }
+//
+// Gain factor table: Input value in Q8 and output value in Q13
+static const int16_t kFactor2Aggressiveness1[257] = {
+    7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577,
+    7577, 7577, 7577, 7577, 7577, 7596, 7614, 7632, 7650, 7667, 7683, 7699,
+    7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, 7858, 7871,
+    7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
+    8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143,
+    8152, 8162, 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192};
+
+// Gain factor table: Input value in Q8 and output value in Q13
+static const int16_t kFactor2Aggressiveness2[257] = {
+    7270, 7270, 7270, 7270, 7270, 7306, 7339, 7369, 7397, 7424, 7448, 7472,
+    7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, 7650, 7667, 7683, 7699,
+    7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, 7858, 7871,
+    7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
+    8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143,
+    8152, 8162, 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192};
+
+// Gain factor table: Input value in Q8 and output value in Q13
+static const int16_t kFactor2Aggressiveness3[257] = {
+    7184, 7184, 7184, 7229, 7270, 7306, 7339, 7369, 7397, 7424, 7448, 7472,
+    7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632, 7650, 7667, 7683, 7699,
+    7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845, 7858, 7871,
+    7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
+    8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143,
+    8152, 8162, 8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
+    8192, 8192, 8192, 8192, 8192};
+
+// sum of log2(i) from table index to inst->anaLen2 in Q5
+// Note that the first table value is invalid, since log2(0) = -infinity
+static const int16_t kSumLogIndex[66] = {
+    0,     22917, 22917, 22885, 22834, 22770, 22696, 22613, 22524, 22428,
+    22326, 22220, 22109, 21994, 21876, 21754, 21629, 21501, 21370, 21237,
+    21101, 20963, 20822, 20679, 20535, 20388, 20239, 20089, 19937, 19783,
+    19628, 19470, 19312, 19152, 18991, 18828, 18664, 18498, 18331, 18164,
+    17994, 17824, 17653, 17480, 17306, 17132, 16956, 16779, 16602, 16423,
+    16243, 16063, 15881, 15699, 15515, 15331, 15146, 14960, 14774, 14586,
+    14398, 14209, 14019, 13829, 13637, 13445};
+
+// sum of log2(i)^2 from table index to inst->anaLen2 in Q2
+// Note that the first table value is invalid, since log2(0) = -infinity
+static const int16_t kSumSquareLogIndex[66] = {
+    0,     16959, 16959, 16955, 16945, 16929, 16908, 16881, 16850, 16814,
+    16773, 16729, 16681, 16630, 16575, 16517, 16456, 16392, 16325, 16256,
+    16184, 16109, 16032, 15952, 15870, 15786, 15700, 15612, 15521, 15429,
+    15334, 15238, 15140, 15040, 14938, 14834, 14729, 14622, 14514, 14404,
+    14292, 14179, 14064, 13947, 13830, 13710, 13590, 13468, 13344, 13220,
+    13094, 12966, 12837, 12707, 12576, 12444, 12310, 12175, 12039, 11902,
+    11763, 11624, 11483, 11341, 11198, 11054};
+
+// log2(table index) in Q12
+// Note that the first table value is invalid, since log2(0) = -infinity
+static const int16_t kLogIndex[129] = {
+    0,     0,     4096,  6492,  8192,  9511,  10588, 11499, 12288, 12984, 13607,
+    14170, 14684, 15157, 15595, 16003, 16384, 16742, 17080, 17400, 17703, 17991,
+    18266, 18529, 18780, 19021, 19253, 19476, 19691, 19898, 20099, 20292, 20480,
+    20662, 20838, 21010, 21176, 21338, 21496, 21649, 21799, 21945, 22087, 22226,
+    22362, 22495, 22625, 22752, 22876, 22998, 23117, 23234, 23349, 23462, 23572,
+    23680, 23787, 23892, 23994, 24095, 24195, 24292, 24388, 24483, 24576, 24668,
+    24758, 24847, 24934, 25021, 25106, 25189, 25272, 25354, 25434, 25513, 25592,
+    25669, 25745, 25820, 25895, 25968, 26041, 26112, 26183, 26253, 26322, 26390,
+    26458, 26525, 26591, 26656, 26721, 26784, 26848, 26910, 26972, 27033, 27094,
+    27154, 27213, 27272, 27330, 27388, 27445, 27502, 27558, 27613, 27668, 27722,
+    27776, 27830, 27883, 27935, 27988, 28039, 28090, 28141, 28191, 28241, 28291,
+    28340, 28388, 28437, 28484, 28532, 28579, 28626, 28672};
+
+// determinant of estimation matrix in Q0 corresponding to the log2 tables above
+// Note that the first table value is invalid, since log2(0) = -infinity
+static const int16_t kDeterminantEstMatrix[66] = {
+    0,     29814, 25574, 22640, 20351, 18469, 16873, 15491, 14277, 13199, 12233,
+    11362, 10571, 9851,  9192,  8587,  8030,  7515,  7038,  6596,  6186,  5804,
+    5448,  5115,  4805,  4514,  4242,  3988,  3749,  3524,  3314,  3116,  2930,
+    2755,  2590,  2435,  2289,  2152,  2022,  1900,  1785,  1677,  1575,  1478,
+    1388,  1302,  1221,  1145,  1073,  1005,  942,   881,   825,   771,   721,
+    674,   629,   587,   547,   510,   475,   442,   411,   382,   355,   330};
+
+// Update the noise estimation information.
+static void UpdateNoiseEstimate(NoiseSuppressionFixedC* inst, int offset) {
+  int32_t tmp32no1 = 0;
+  int32_t tmp32no2 = 0;
+  int16_t tmp16 = 0;
+  const int16_t kExp2Const = 11819;  // Q13
+
+  size_t i = 0;
+
+  tmp16 =
+      WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset, inst->magnLen);
+  // Guarantee a Q-domain as high as possible and still fit in int16
+  inst->qNoise =
+      14 - (int)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(kExp2Const, tmp16, 21);
+  for (i = 0; i < inst->magnLen; i++) {
+    // inst->quantile[i]=exp(inst->lquantile[offset+i]);
+    // in Q21
+    tmp32no2 = kExp2Const * inst->noiseEstLogQuantile[offset + i];
+    tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF));  // 2^21 + frac
+    tmp16 = (int16_t)(tmp32no2 >> 21);
+    tmp16 -= 21;                     // shift 21 to get result in Q0
+    tmp16 += (int16_t)inst->qNoise;  // shift to get result in Q(qNoise)
+    if (tmp16 < 0) {
+      tmp32no1 >>= -tmp16;
+    } else {
+      tmp32no1 <<= tmp16;
+    }
+    inst->noiseEstQuantile[i] = WebRtcSpl_SatW32ToW16(tmp32no1);
+  }
+}
+
+// Noise Estimation
+static void NoiseEstimationC(NoiseSuppressionFixedC* inst,
+                             uint16_t* magn,
+                             uint32_t* noise,
+                             int16_t* q_noise) {
+  int16_t lmagn[HALF_ANAL_BLOCKL], counter, countDiv;
+  int16_t countProd, delta, zeros, frac;
+  int16_t log2, tabind, logval, tmp16, tmp16no1, tmp16no2;
+  const int16_t log2_const = 22713;  // Q15
+  const int16_t width_factor = 21845;
+
+  size_t i, s, offset;
+
+  tabind = inst->stages - inst->normData;
+  RTC_DCHECK_LT(tabind, 9);
+  RTC_DCHECK_GT(tabind, -9);
+  if (tabind < 0) {
+    logval = -WebRtcNsx_kLogTable[-tabind];
+  } else {
+    logval = WebRtcNsx_kLogTable[tabind];
+  }
+
+  // lmagn(i)=log(magn(i))=log(2)*log2(magn(i))
+  // magn is in Q(-stages), and the real lmagn values are:
+  // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages)
+  // lmagn in Q8
+  for (i = 0; i < inst->magnLen; i++) {
+    if (magn[i]) {
+      zeros = WebRtcSpl_NormU32((uint32_t)magn[i]);
+      frac = (int16_t)((((uint32_t)magn[i] << zeros) & 0x7FFFFFFF) >> 23);
+      // log2(magn(i))
+      RTC_DCHECK_LT(frac, 256);
+      log2 = (int16_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]);
+      // log2(magn(i))*log(2)
+      lmagn[i] = (int16_t)((log2 * log2_const) >> 15);
+      // + log(2^stages)
+      lmagn[i] += logval;
+    } else {
+      lmagn[i] = logval;  // 0;
+    }
+  }
+
+  // loop over simultaneous estimates
+  for (s = 0; s < SIMULT; s++) {
+    offset = s * inst->magnLen;
+
+    // Get counter values from state
+    counter = inst->noiseEstCounter[s];
+    RTC_DCHECK_LT(counter, 201);
+    countDiv = WebRtcNsx_kCounterDiv[counter];
+    countProd = (int16_t)(counter * countDiv);
+
+    // quant_est(...)
+    for (i = 0; i < inst->magnLen; i++) {
+      // compute delta
+      if (inst->noiseEstDensity[offset + i] > 512) {
+        // Get the value for delta by shifting intead of dividing.
+        int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i]);
+        delta = (int16_t)(FACTOR_Q16 >> (14 - factor));
+      } else {
+        delta = FACTOR_Q7;
+        if (inst->blockIndex < END_STARTUP_LONG) {
+          // Smaller step size during startup. This prevents from using
+          // unrealistic values causing overflow.
+          delta = FACTOR_Q7_STARTUP;
+        }
+      }
+
+      // update log quantile estimate
+      tmp16 = (int16_t)((delta * countDiv) >> 14);
+      if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) {
+        // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2
+        // CounterDiv=1/(inst->counter[s]+1) in Q15
+        tmp16 += 2;
+        inst->noiseEstLogQuantile[offset + i] += tmp16 / 4;
+      } else {
+        tmp16 += 1;
+        // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2
+        // TODO(bjornv): investigate why we need to truncate twice.
+        tmp16no2 = (int16_t)((tmp16 / 2) * 3 / 2);
+        inst->noiseEstLogQuantile[offset + i] -= tmp16no2;
+        if (inst->noiseEstLogQuantile[offset + i] < logval) {
+          // This is the smallest fixed point representation we can
+          // have, hence we limit the output.
+          inst->noiseEstLogQuantile[offset + i] = logval;
+        }
+      }
+
+      // update density estimate
+      if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i]) <
+          WIDTH_Q8) {
+        tmp16no1 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
+            inst->noiseEstDensity[offset + i], countProd, 15);
+        tmp16no2 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(width_factor,
+                                                                 countDiv, 15);
+        inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2;
+      }
+    }  // end loop over magnitude spectrum
+
+    if (counter >= END_STARTUP_LONG) {
+      inst->noiseEstCounter[s] = 0;
+      if (inst->blockIndex >= END_STARTUP_LONG) {
+        UpdateNoiseEstimate(inst, offset);
+      }
+    }
+    inst->noiseEstCounter[s]++;
+
+  }  // end loop over simultaneous estimates
+
+  // Sequentially update the noise during startup
+  if (inst->blockIndex < END_STARTUP_LONG) {
+    UpdateNoiseEstimate(inst, offset);
+  }
+
+  for (i = 0; i < inst->magnLen; i++) {
+    noise[i] = (uint32_t)(inst->noiseEstQuantile[i]);  // Q(qNoise)
+  }
+  (*q_noise) = (int16_t)inst->qNoise;
+}
+
+// Filter the data in the frequency domain, and create spectrum.
+static void PrepareSpectrumC(NoiseSuppressionFixedC* inst, int16_t* freq_buf) {
+  size_t i = 0, j = 0;
+
+  for (i = 0; i < inst->magnLen; i++) {
+    inst->real[i] =
+        (int16_t)((inst->real[i] * (int16_t)(inst->noiseSupFilter[i])) >>
+                  14);  // Q(normData-stages)
+    inst->imag[i] =
+        (int16_t)((inst->imag[i] * (int16_t)(inst->noiseSupFilter[i])) >>
+                  14);  // Q(normData-stages)
+  }
+
+  freq_buf[0] = inst->real[0];
+  freq_buf[1] = -inst->imag[0];
+  for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
+    freq_buf[j] = inst->real[i];
+    freq_buf[j + 1] = -inst->imag[i];
+  }
+  freq_buf[inst->anaLen] = inst->real[inst->anaLen2];
+  freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2];
+}
+
+// Denormalize the real-valued signal |in|, the output from inverse FFT.
+static void DenormalizeC(NoiseSuppressionFixedC* inst,
+                         int16_t* in,
+                         int factor) {
+  size_t i = 0;
+  int32_t tmp32 = 0;
+  for (i = 0; i < inst->anaLen; i += 1) {
+    tmp32 = WEBRTC_SPL_SHIFT_W32((int32_t)in[i], factor - inst->normData);
+    inst->real[i] = WebRtcSpl_SatW32ToW16(tmp32);  // Q0
+  }
+}
+
+// For the noise supression process, synthesis, read out fully processed
+// segment, and update synthesis buffer.
+static void SynthesisUpdateC(NoiseSuppressionFixedC* inst,
+                             int16_t* out_frame,
+                             int16_t gain_factor) {
+  size_t i = 0;
+  int16_t tmp16a = 0;
+  int16_t tmp16b = 0;
+  int32_t tmp32 = 0;
+
+  // synthesis
+  for (i = 0; i < inst->anaLen; i++) {
+    tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
+        inst->window[i], inst->real[i], 14);  // Q0, window in Q14
+    tmp32 =
+        WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13);  // Q0
+    // Down shift with rounding
+    tmp16b = WebRtcSpl_SatW32ToW16(tmp32);  // Q0
+    inst->synthesisBuffer[i] = WebRtcSpl_AddSatW16(inst->synthesisBuffer[i],
+                                                   tmp16b);  // Q0
+  }
+
+  // read out fully processed segment
+  for (i = 0; i < inst->blockLen10ms; i++) {
+    out_frame[i] = inst->synthesisBuffer[i];  // Q0
+  }
+
+  // update synthesis buffer
+  memcpy(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
+         (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->synthesisBuffer));
+  WebRtcSpl_ZerosArrayW16(
+      inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms,
+      inst->blockLen10ms);
+}
+
+// Update analysis buffer for lower band, and window data before FFT.
+static void AnalysisUpdateC(NoiseSuppressionFixedC* inst,
+                            int16_t* out,
+                            int16_t* new_speech) {
+  size_t i = 0;
+
+  // For lower band update analysis buffer.
+  memcpy(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms,
+         (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->analysisBuffer));
+  memcpy(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms, new_speech,
+         inst->blockLen10ms * sizeof(*inst->analysisBuffer));
+
+  // Window data before FFT.
+  for (i = 0; i < inst->anaLen; i++) {
+    out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
+        inst->window[i], inst->analysisBuffer[i], 14);  // Q0
+  }
+}
+
+// Normalize the real-valued signal |in|, the input to forward FFT.
+static void NormalizeRealBufferC(NoiseSuppressionFixedC* inst,
+                                 const int16_t* in,
+                                 int16_t* out) {
+  size_t i = 0;
+  RTC_DCHECK_GE(inst->normData, 0);
+  for (i = 0; i < inst->anaLen; ++i) {
+    out[i] = in[i] << inst->normData;  // Q(normData)
+  }
+}
+
+// Declare function pointers.
+NoiseEstimation WebRtcNsx_NoiseEstimation;
+PrepareSpectrum WebRtcNsx_PrepareSpectrum;
+SynthesisUpdate WebRtcNsx_SynthesisUpdate;
+AnalysisUpdate WebRtcNsx_AnalysisUpdate;
+Denormalize WebRtcNsx_Denormalize;
+NormalizeRealBuffer WebRtcNsx_NormalizeRealBuffer;
+
+#if defined(WEBRTC_HAS_NEON)
+// Initialize function pointers for ARM Neon platform.
+static void WebRtcNsx_InitNeon(void) {
+  WebRtcNsx_NoiseEstimation = WebRtcNsx_NoiseEstimationNeon;
+  WebRtcNsx_PrepareSpectrum = WebRtcNsx_PrepareSpectrumNeon;
+  WebRtcNsx_SynthesisUpdate = WebRtcNsx_SynthesisUpdateNeon;
+  WebRtcNsx_AnalysisUpdate = WebRtcNsx_AnalysisUpdateNeon;
+}
+#endif
+
+#if defined(MIPS32_LE)
+// Initialize function pointers for MIPS platform.
+static void WebRtcNsx_InitMips(void) {
+  WebRtcNsx_PrepareSpectrum = WebRtcNsx_PrepareSpectrum_mips;
+  WebRtcNsx_SynthesisUpdate = WebRtcNsx_SynthesisUpdate_mips;
+  WebRtcNsx_AnalysisUpdate = WebRtcNsx_AnalysisUpdate_mips;
+  WebRtcNsx_NormalizeRealBuffer = WebRtcNsx_NormalizeRealBuffer_mips;
+#if defined(MIPS_DSP_R1_LE)
+  WebRtcNsx_Denormalize = WebRtcNsx_Denormalize_mips;
+#endif
+}
+#endif
+
+void WebRtcNsx_CalcParametricNoiseEstimate(NoiseSuppressionFixedC* inst,
+                                           int16_t pink_noise_exp_avg,
+                                           int32_t pink_noise_num_avg,
+                                           int freq_index,
+                                           uint32_t* noise_estimate,
+                                           uint32_t* noise_estimate_avg) {
+  int32_t tmp32no1 = 0;
+  int32_t tmp32no2 = 0;
+
+  int16_t int_part = 0;
+  int16_t frac_part = 0;
+
+  // Use pink noise estimate
+  // noise_estimate = 2^(pinkNoiseNumerator + pinkNoiseExp * log2(j))
+  RTC_DCHECK_GE(freq_index, 0);
+  RTC_DCHECK_LT(freq_index, 129);
+  tmp32no2 = (pink_noise_exp_avg * kLogIndex[freq_index]) >> 15;  // Q11
+  tmp32no1 = pink_noise_num_avg - tmp32no2;                       // Q11
+
+  // Calculate output: 2^tmp32no1
+  // Output in Q(minNorm-stages)
+  tmp32no1 += (inst->minNorm - inst->stages) << 11;
+  if (tmp32no1 > 0) {
+    int_part = (int16_t)(tmp32no1 >> 11);
+    frac_part = (int16_t)(tmp32no1 & 0x000007ff);  // Q11
+    // Piecewise linear approximation of 'b' in
+    // 2^(int_part+frac_part) = 2^int_part * (1 + b)
+    // 'b' is given in Q11 and below stored in frac_part.
+    if (frac_part >> 10) {
+      // Upper fractional part
+      tmp32no2 = (2048 - frac_part) * 1244;  // Q21
+      tmp32no2 = 2048 - (tmp32no2 >> 10);
+    } else {
+      // Lower fractional part
+      tmp32no2 = (frac_part * 804) >> 10;
+    }
+    // Shift fractional part to Q(minNorm-stages)
+    tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, int_part - 11);
+    *noise_estimate_avg = (1 << int_part) + (uint32_t)tmp32no2;
+    // Scale up to initMagnEst, which is not block averaged
+    *noise_estimate = (*noise_estimate_avg) * (uint32_t)(inst->blockIndex + 1);
+  }
+}
+
+// Initialize state
+int32_t WebRtcNsx_InitCore(NoiseSuppressionFixedC* inst, uint32_t fs) {
+  int i;
+
+  // check for valid pointer
+  if (inst == NULL) {
+    return -1;
+  }
+  //
+
+  // Initialization of struct
+  if (fs == 8000 || fs == 16000 || fs == 32000 || fs == 48000) {
+    inst->fs = fs;
+  } else {
+    return -1;
+  }
+
+  if (fs == 8000) {
+    inst->blockLen10ms = 80;
+    inst->anaLen = 128;
+    inst->stages = 7;
+    inst->window = kBlocks80w128x;
+    inst->thresholdLogLrt = 131072;  // default threshold for LRT feature
+    inst->maxLrt = 0x0040000;
+    inst->minLrt = 52429;
+  } else {
+    inst->blockLen10ms = 160;
+    inst->anaLen = 256;
+    inst->stages = 8;
+    inst->window = kBlocks160w256x;
+    inst->thresholdLogLrt = 212644;  // default threshold for LRT feature
+    inst->maxLrt = 0x0080000;
+    inst->minLrt = 104858;
+  }
+  inst->anaLen2 = inst->anaLen / 2;
+  inst->magnLen = inst->anaLen2 + 1;
+
+  if (inst->real_fft != NULL) {
+    WebRtcSpl_FreeRealFFT(inst->real_fft);
+  }
+  inst->real_fft = WebRtcSpl_CreateRealFFT(inst->stages);
+  if (inst->real_fft == NULL) {
+    return -1;
+  }
+
+  WebRtcSpl_ZerosArrayW16(inst->analysisBuffer, ANAL_BLOCKL_MAX);
+  WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer, ANAL_BLOCKL_MAX);
+
+  // for HB processing
+  WebRtcSpl_ZerosArrayW16(inst->dataBufHBFX[0],
+                          NUM_HIGH_BANDS_MAX * ANAL_BLOCKL_MAX);
+  // for quantile noise estimation
+  WebRtcSpl_ZerosArrayW16(inst->noiseEstQuantile, HALF_ANAL_BLOCKL);
+  for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
+    inst->noiseEstLogQuantile[i] = 2048;  // Q8
+    inst->noiseEstDensity[i] = 153;       // Q9
+  }
+  for (i = 0; i < SIMULT; i++) {
+    inst->noiseEstCounter[i] = (int16_t)(END_STARTUP_LONG * (i + 1)) / SIMULT;
+  }
+
+  // Initialize suppression filter with ones
+  WebRtcSpl_MemSetW16((int16_t*)inst->noiseSupFilter, 16384, HALF_ANAL_BLOCKL);
+
+  // Set the aggressiveness: default
+  inst->aggrMode = 0;
+
+  // initialize variables for new method
+  inst->priorNonSpeechProb =
+      8192;  // Q14(0.5) prior probability for speech/noise
+  for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
+    inst->prevMagnU16[i] = 0;
+    inst->prevNoiseU32[i] = 0;      // previous noise-spectrum
+    inst->logLrtTimeAvgW32[i] = 0;  // smooth LR ratio
+    inst->avgMagnPause[i] = 0;      // conservative noise spectrum estimate
+    inst->initMagnEst[i] = 0;       // initial average magnitude spectrum
+  }
+
+  // feature quantities
+  inst->thresholdSpecDiff =
+      50;  // threshold for difference feature: determined on-line
+  inst->thresholdSpecFlat = 20480;  // threshold for flatness: determined
+                                    // on-line
+  inst->featureLogLrt =
+      inst->thresholdLogLrt;  // average LRT factor (= threshold)
+  inst->featureSpecFlat =
+      inst->thresholdSpecFlat;  // spectral flatness (= threshold)
+  inst->featureSpecDiff =
+      inst->thresholdSpecDiff;  // spectral difference (= threshold)
+  inst->weightLogLrt = 6;       // default weighting par for LRT feature
+  inst->weightSpecFlat =
+      0;  // default weighting par for spectral flatness feature
+  inst->weightSpecDiff =
+      0;  // default weighting par for spectral difference feature
+
+  inst->curAvgMagnEnergy = 0;  // window time-average of input magnitude
+                               // spectrum
+  inst->timeAvgMagnEnergy = 0;     // normalization for spectral difference
+  inst->timeAvgMagnEnergyTmp = 0;  // normalization for spectral difference
+
+  // histogram quantities: used to estimate/update thresholds for features
+  WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
+  WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
+  WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
+
+  inst->blockIndex = -1;  // frame counter
+
+  // inst->modelUpdate    = 500;   //window for update
+  inst->modelUpdate = (1 << STAT_UPDATES);  // window for update
+  inst->cntThresUpdate = 0;  // counter feature thresholds updates
+
+  inst->sumMagn = 0;
+  inst->magnEnergy = 0;
+  inst->prevQMagn = 0;
+  inst->qNoise = 0;
+  inst->prevQNoise = 0;
+
+  inst->energyIn = 0;
+  inst->scaleEnergyIn = 0;
+
+  inst->whiteNoiseLevel = 0;
+  inst->pinkNoiseNumerator = 0;
+  inst->pinkNoiseExp = 0;
+  inst->minNorm = 15;  // Start with full scale
+  inst->zeroInputSignal = 0;
+
+  // default mode
+  WebRtcNsx_set_policy_core(inst, 0);
+
+#ifdef NS_FILEDEBUG
+  inst->infile = fopen("indebug.pcm", "wb");
+  inst->outfile = fopen("outdebug.pcm", "wb");
+  inst->file1 = fopen("file1.pcm", "wb");
+  inst->file2 = fopen("file2.pcm", "wb");
+  inst->file3 = fopen("file3.pcm", "wb");
+  inst->file4 = fopen("file4.pcm", "wb");
+  inst->file5 = fopen("file5.pcm", "wb");
+#endif
+
+  // Initialize function pointers.
+  WebRtcNsx_NoiseEstimation = NoiseEstimationC;
+  WebRtcNsx_PrepareSpectrum = PrepareSpectrumC;
+  WebRtcNsx_SynthesisUpdate = SynthesisUpdateC;
+  WebRtcNsx_AnalysisUpdate = AnalysisUpdateC;
+  WebRtcNsx_Denormalize = DenormalizeC;
+  WebRtcNsx_NormalizeRealBuffer = NormalizeRealBufferC;
+
+#if defined(WEBRTC_HAS_NEON)
+  WebRtcNsx_InitNeon();
+#endif
+
+#if defined(MIPS32_LE)
+  WebRtcNsx_InitMips();
+#endif
+
+  inst->initFlag = 1;
+
+  return 0;
+}
+
+int WebRtcNsx_set_policy_core(NoiseSuppressionFixedC* inst, int mode) {
+  // allow for modes:0,1,2,3
+  if (mode < 0 || mode > 3) {
+    return -1;
+  }
+
+  inst->aggrMode = mode;
+  if (mode == 0) {
+    inst->overdrive = 256;      // Q8(1.0)
+    inst->denoiseBound = 8192;  // Q14(0.5)
+    inst->gainMap = 0;          // No gain compensation
+  } else if (mode == 1) {
+    inst->overdrive = 256;      // Q8(1.0)
+    inst->denoiseBound = 4096;  // Q14(0.25)
+    inst->factor2Table = kFactor2Aggressiveness1;
+    inst->gainMap = 1;
+  } else if (mode == 2) {
+    inst->overdrive = 282;      // ~= Q8(1.1)
+    inst->denoiseBound = 2048;  // Q14(0.125)
+    inst->factor2Table = kFactor2Aggressiveness2;
+    inst->gainMap = 1;
+  } else if (mode == 3) {
+    inst->overdrive = 320;      // Q8(1.25)
+    inst->denoiseBound = 1475;  // ~= Q14(0.09)
+    inst->factor2Table = kFactor2Aggressiveness3;
+    inst->gainMap = 1;
+  }
+  return 0;
+}
+
+// Extract thresholds for feature parameters
+// histograms are computed over some window_size (given by window_pars)
+// thresholds and weights are extracted every window
+// flag 0 means update histogram only, flag 1 means compute the
+// thresholds/weights threshold and weights are returned in:
+// inst->priorModelPars
+void WebRtcNsx_FeatureParameterExtraction(NoiseSuppressionFixedC* inst,
+                                          int flag) {
+  uint32_t tmpU32;
+  uint32_t histIndex;
+  uint32_t posPeak1SpecFlatFX, posPeak2SpecFlatFX;
+  uint32_t posPeak1SpecDiffFX, posPeak2SpecDiffFX;
+
+  int32_t tmp32;
+  int32_t fluctLrtFX, thresFluctLrtFX;
+  int32_t avgHistLrtFX, avgSquareHistLrtFX, avgHistLrtComplFX;
+
+  int16_t j;
+  int16_t numHistLrt;
+
+  int i;
+  int useFeatureSpecFlat, useFeatureSpecDiff, featureSum;
+  int maxPeak1, maxPeak2;
+  int weightPeak1SpecFlat, weightPeak2SpecFlat;
+  int weightPeak1SpecDiff, weightPeak2SpecDiff;
+
+  // update histograms
+  if (!flag) {
+    // LRT
+    // Type casting to UWord32 is safe since negative values will not be wrapped
+    // to larger values than HIST_PAR_EST
+    histIndex = (uint32_t)(inst->featureLogLrt);
+    if (histIndex < HIST_PAR_EST) {
+      inst->histLrt[histIndex]++;
+    }
+    // Spectral flatness
+    // (inst->featureSpecFlat*20)>>10 = (inst->featureSpecFlat*5)>>8
+    histIndex = (inst->featureSpecFlat * 5) >> 8;
+    if (histIndex < HIST_PAR_EST) {
+      inst->histSpecFlat[histIndex]++;
+    }
+    // Spectral difference
+    histIndex = HIST_PAR_EST;
+    if (inst->timeAvgMagnEnergy > 0) {
+      // Guard against division by zero
+      // If timeAvgMagnEnergy == 0 we have no normalizing statistics and
+      // therefore can't update the histogram
+      histIndex = ((inst->featureSpecDiff * 5) >> inst->stages) /
+                  inst->timeAvgMagnEnergy;
+    }
+    if (histIndex < HIST_PAR_EST) {
+      inst->histSpecDiff[histIndex]++;
+    }
+  }
+
+  // extract parameters for speech/noise probability
+  if (flag) {
+    useFeatureSpecDiff = 1;
+    // for LRT feature:
+    // compute the average over inst->featureExtractionParams.rangeAvgHistLrt
+    avgHistLrtFX = 0;
+    avgSquareHistLrtFX = 0;
+    numHistLrt = 0;
+    for (i = 0; i < BIN_SIZE_LRT; i++) {
+      j = (2 * i + 1);
+      tmp32 = inst->histLrt[i] * j;
+      avgHistLrtFX += tmp32;
+      numHistLrt += inst->histLrt[i];
+      avgSquareHistLrtFX += tmp32 * j;
+    }
+    avgHistLrtComplFX = avgHistLrtFX;
+    for (; i < HIST_PAR_EST; i++) {
+      j = (2 * i + 1);
+      tmp32 = inst->histLrt[i] * j;
+      avgHistLrtComplFX += tmp32;
+      avgSquareHistLrtFX += tmp32 * j;
+    }
+    fluctLrtFX =
+        avgSquareHistLrtFX * numHistLrt - avgHistLrtFX * avgHistLrtComplFX;
+    thresFluctLrtFX = THRES_FLUCT_LRT * numHistLrt;
+    // get threshold for LRT feature:
+    tmpU32 = (FACTOR_1_LRT_DIFF * (uint32_t)avgHistLrtFX);
+    if ((fluctLrtFX < thresFluctLrtFX) || (numHistLrt == 0) ||
+        (tmpU32 > (uint32_t)(100 * numHistLrt))) {
+      // very low fluctuation, so likely noise
+      inst->thresholdLogLrt = inst->maxLrt;
+    } else {
+      tmp32 = (int32_t)((tmpU32 << (9 + inst->stages)) / numHistLrt / 25);
+      // check if value is within min/max range
+      inst->thresholdLogLrt = WEBRTC_SPL_SAT(inst->maxLrt, tmp32, inst->minLrt);
+    }
+    if (fluctLrtFX < thresFluctLrtFX) {
+      // Do not use difference feature if fluctuation of LRT feature is very
+      // low: most likely just noise state
+      useFeatureSpecDiff = 0;
+    }
+
+    // for spectral flatness and spectral difference: compute the main peaks of
+    // histogram
+    maxPeak1 = 0;
+    maxPeak2 = 0;
+    posPeak1SpecFlatFX = 0;
+    posPeak2SpecFlatFX = 0;
+    weightPeak1SpecFlat = 0;
+    weightPeak2SpecFlat = 0;
+
+    // peaks for flatness
+    for (i = 0; i < HIST_PAR_EST; i++) {
+      if (inst->histSpecFlat[i] > maxPeak1) {
+        // Found new "first" peak
+        maxPeak2 = maxPeak1;
+        weightPeak2SpecFlat = weightPeak1SpecFlat;
+        posPeak2SpecFlatFX = posPeak1SpecFlatFX;
+
+        maxPeak1 = inst->histSpecFlat[i];
+        weightPeak1SpecFlat = inst->histSpecFlat[i];
+        posPeak1SpecFlatFX = (uint32_t)(2 * i + 1);
+      } else if (inst->histSpecFlat[i] > maxPeak2) {
+        // Found new "second" peak
+        maxPeak2 = inst->histSpecFlat[i];
+        weightPeak2SpecFlat = inst->histSpecFlat[i];
+        posPeak2SpecFlatFX = (uint32_t)(2 * i + 1);
+      }
+    }
+
+    // for spectral flatness feature
+    useFeatureSpecFlat = 1;
+    // merge the two peaks if they are close
+    if ((posPeak1SpecFlatFX - posPeak2SpecFlatFX < LIM_PEAK_SPACE_FLAT_DIFF) &&
+        (weightPeak2SpecFlat * LIM_PEAK_WEIGHT_FLAT_DIFF >
+         weightPeak1SpecFlat)) {
+      weightPeak1SpecFlat += weightPeak2SpecFlat;
+      posPeak1SpecFlatFX = (posPeak1SpecFlatFX + posPeak2SpecFlatFX) >> 1;
+    }
+    // reject if weight of peaks is not large enough, or peak value too small
+    if (weightPeak1SpecFlat < THRES_WEIGHT_FLAT_DIFF ||
+        posPeak1SpecFlatFX < THRES_PEAK_FLAT) {
+      useFeatureSpecFlat = 0;
+    } else {  // if selected, get the threshold
+      // compute the threshold and check if value is within min/max range
+      inst->thresholdSpecFlat =
+          WEBRTC_SPL_SAT(MAX_FLAT_Q10, FACTOR_2_FLAT_Q10 * posPeak1SpecFlatFX,
+                         MIN_FLAT_Q10);  // Q10
+    }
+    // done with flatness feature
+
+    if (useFeatureSpecDiff) {
+      // compute two peaks for spectral difference
+      maxPeak1 = 0;
+      maxPeak2 = 0;
+      posPeak1SpecDiffFX = 0;
+      posPeak2SpecDiffFX = 0;
+      weightPeak1SpecDiff = 0;
+      weightPeak2SpecDiff = 0;
+      // peaks for spectral difference
+      for (i = 0; i < HIST_PAR_EST; i++) {
+        if (inst->histSpecDiff[i] > maxPeak1) {
+          // Found new "first" peak
+          maxPeak2 = maxPeak1;
+          weightPeak2SpecDiff = weightPeak1SpecDiff;
+          posPeak2SpecDiffFX = posPeak1SpecDiffFX;
+
+          maxPeak1 = inst->histSpecDiff[i];
+          weightPeak1SpecDiff = inst->histSpecDiff[i];
+          posPeak1SpecDiffFX = (uint32_t)(2 * i + 1);
+        } else if (inst->histSpecDiff[i] > maxPeak2) {
+          // Found new "second" peak
+          maxPeak2 = inst->histSpecDiff[i];
+          weightPeak2SpecDiff = inst->histSpecDiff[i];
+          posPeak2SpecDiffFX = (uint32_t)(2 * i + 1);
+        }
+      }
+
+      // merge the two peaks if they are close
+      if ((posPeak1SpecDiffFX - posPeak2SpecDiffFX <
+           LIM_PEAK_SPACE_FLAT_DIFF) &&
+          (weightPeak2SpecDiff * LIM_PEAK_WEIGHT_FLAT_DIFF >
+           weightPeak1SpecDiff)) {
+        weightPeak1SpecDiff += weightPeak2SpecDiff;
+        posPeak1SpecDiffFX = (posPeak1SpecDiffFX + posPeak2SpecDiffFX) >> 1;
+      }
+      // get the threshold value and check if value is within min/max range
+      inst->thresholdSpecDiff =
+          WEBRTC_SPL_SAT(MAX_DIFF, FACTOR_1_LRT_DIFF * posPeak1SpecDiffFX,
+                         MIN_DIFF);  // 5x bigger
+      // reject if weight of peaks is not large enough
+      if (weightPeak1SpecDiff < THRES_WEIGHT_FLAT_DIFF) {
+        useFeatureSpecDiff = 0;
+      }
+      // done with spectral difference feature
+    }
+
+    // select the weights between the features
+    // inst->priorModelPars[4] is weight for LRT: always selected
+    featureSum = 6 / (1 + useFeatureSpecFlat + useFeatureSpecDiff);
+    inst->weightLogLrt = featureSum;
+    inst->weightSpecFlat = useFeatureSpecFlat * featureSum;
+    inst->weightSpecDiff = useFeatureSpecDiff * featureSum;
+
+    // set histograms to zero for next update
+    WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
+    WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
+    WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
+  }  // end of flag == 1
+}
+
+// Compute spectral flatness on input spectrum
+// magn is the magnitude spectrum
+// spectral flatness is returned in inst->featureSpecFlat
+void WebRtcNsx_ComputeSpectralFlatness(NoiseSuppressionFixedC* inst,
+                                       uint16_t* magn) {
+  uint32_t tmpU32;
+  uint32_t avgSpectralFlatnessNum, avgSpectralFlatnessDen;
+
+  int32_t tmp32;
+  int32_t currentSpectralFlatness, logCurSpectralFlatness;
+
+  int16_t zeros, frac, intPart;
+
+  size_t i;
+
+  // for flatness
+  avgSpectralFlatnessNum = 0;
+  avgSpectralFlatnessDen =
+      inst->sumMagn - (uint32_t)magn[0];  // Q(normData-stages)
+
+  // compute log of ratio of the geometric to arithmetic mean: check for log(0)
+  // case flatness = exp( sum(log(magn[i]))/N - log(sum(magn[i])/N) )
+  //          = exp( sum(log(magn[i]))/N ) * N / sum(magn[i])
+  //          = 2^( sum(log2(magn[i]))/N - (log2(sum(magn[i])) - log2(N)) )
+  //          [This is used]
+  for (i = 1; i < inst->magnLen; i++) {
+    // First bin is excluded from spectrum measures. Number of bins is now a
+    // power of 2
+    if (magn[i]) {
+      zeros = WebRtcSpl_NormU32((uint32_t)magn[i]);
+      frac = (int16_t)(
+          ((uint32_t)((uint32_t)(magn[i]) << zeros) & 0x7FFFFFFF) >> 23);
+      // log2(magn(i))
+      RTC_DCHECK_LT(frac, 256);
+      tmpU32 = (uint32_t)(((31 - zeros) << 8) +
+                          WebRtcNsx_kLogTableFrac[frac]);  // Q8
+      avgSpectralFlatnessNum += tmpU32;                    // Q8
+    } else {
+      // if at least one frequency component is zero, treat separately
+      tmpU32 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecFlat,
+                                     SPECT_FLAT_TAVG_Q14);  // Q24
+      inst->featureSpecFlat -= tmpU32 >> 14;                // Q10
+      return;
+    }
+  }
+  // ratio and inverse log: check for case of log(0)
+  zeros = WebRtcSpl_NormU32(avgSpectralFlatnessDen);
+  frac = (int16_t)(((avgSpectralFlatnessDen << zeros) & 0x7FFFFFFF) >> 23);
+  // log2(avgSpectralFlatnessDen)
+  RTC_DCHECK_LT(frac, 256);
+  tmp32 = (int32_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]);  // Q8
+  logCurSpectralFlatness = (int32_t)avgSpectralFlatnessNum;
+  logCurSpectralFlatness +=
+      ((int32_t)(inst->stages - 1) << (inst->stages + 7));  // Q(8+stages-1)
+  logCurSpectralFlatness -= (tmp32 << (inst->stages - 1));
+  logCurSpectralFlatness <<= (10 - inst->stages);  // Q17
+  tmp32 = (int32_t)(0x00020000 | (WEBRTC_SPL_ABS_W32(logCurSpectralFlatness) &
+                                  0x0001FFFF));  // Q17
+  intPart = 7 - (logCurSpectralFlatness >> 17);  // Add 7 for output in Q10.
+  if (intPart > 0) {
+    currentSpectralFlatness = tmp32 >> intPart;
+  } else {
+    currentSpectralFlatness = tmp32 << -intPart;
+  }
+
+  // time average update of spectral flatness feature
+  tmp32 = currentSpectralFlatness - (int32_t)inst->featureSpecFlat;  // Q10
+  tmp32 *= SPECT_FLAT_TAVG_Q14;                                      // Q24
+  inst->featureSpecFlat += tmp32 >> 14;                              // Q10
+  // done with flatness feature
+}
+
+// Compute the difference measure between input spectrum and a template/learned
+// noise spectrum magn_tmp is the input spectrum the reference/template spectrum
+// is  inst->magn_avg_pause[i] returns (normalized) spectral difference in
+// inst->featureSpecDiff
+void WebRtcNsx_ComputeSpectralDifference(NoiseSuppressionFixedC* inst,
+                                         uint16_t* magnIn) {
+  // This is to be calculated:
+  // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 /
+  // var(magnAvgPause)
+
+  uint32_t tmpU32no1, tmpU32no2;
+  uint32_t varMagnUFX, varPauseUFX, avgDiffNormMagnUFX;
+
+  int32_t tmp32no1, tmp32no2;
+  int32_t avgPauseFX, avgMagnFX, covMagnPauseFX;
+  int32_t maxPause, minPause;
+
+  int16_t tmp16no1;
+
+  size_t i;
+  int norm32, nShifts;
+
+  avgPauseFX = 0;
+  maxPause = 0;
+  minPause = inst->avgMagnPause[0];  // Q(prevQMagn)
+  // compute average quantities
+  for (i = 0; i < inst->magnLen; i++) {
+    // Compute mean of magn_pause
+    avgPauseFX += inst->avgMagnPause[i];  // in Q(prevQMagn)
+    maxPause = WEBRTC_SPL_MAX(maxPause, inst->avgMagnPause[i]);
+    minPause = WEBRTC_SPL_MIN(minPause, inst->avgMagnPause[i]);
+  }
+  // normalize by replacing div of "inst->magnLen" with "inst->stages-1" shifts
+  avgPauseFX >>= inst->stages - 1;
+  avgMagnFX = inst->sumMagn >> (inst->stages - 1);
+  // Largest possible deviation in magnPause for (co)var calculations
+  tmp32no1 = WEBRTC_SPL_MAX(maxPause - avgPauseFX, avgPauseFX - minPause);
+  // Get number of shifts to make sure we don't get wrap around in varPause
+  nShifts = WEBRTC_SPL_MAX(0, 10 + inst->stages - WebRtcSpl_NormW32(tmp32no1));
+
+  varMagnUFX = 0;
+  varPauseUFX = 0;
+  covMagnPauseFX = 0;
+  for (i = 0; i < inst->magnLen; i++) {
+    // Compute var and cov of magn and magn_pause
+    tmp16no1 = (int16_t)((int32_t)magnIn[i] - avgMagnFX);
+    tmp32no2 = inst->avgMagnPause[i] - avgPauseFX;
+    varMagnUFX += (uint32_t)(tmp16no1 * tmp16no1);  // Q(2*qMagn)
+    tmp32no1 = tmp32no2 * tmp16no1;                 // Q(prevQMagn+qMagn)
+    covMagnPauseFX += tmp32no1;                     // Q(prevQMagn+qMagn)
+    tmp32no1 = tmp32no2 >> nShifts;                 // Q(prevQMagn-minPause).
+    varPauseUFX += tmp32no1 * tmp32no1;             // Q(2*(prevQMagn-minPause))
+  }
+  // update of average magnitude spectrum: Q(-2*stages) and averaging replaced
+  // by shifts
+  inst->curAvgMagnEnergy +=
+      inst->magnEnergy >> (2 * inst->normData + inst->stages - 1);
+
+  avgDiffNormMagnUFX = varMagnUFX;  // Q(2*qMagn)
+  if ((varPauseUFX) && (covMagnPauseFX)) {
+    tmpU32no1 =
+        (uint32_t)WEBRTC_SPL_ABS_W32(covMagnPauseFX);  // Q(prevQMagn+qMagn)
+    norm32 = WebRtcSpl_NormU32(tmpU32no1) - 16;
+    if (norm32 > 0) {
+      tmpU32no1 <<= norm32;  // Q(prevQMagn+qMagn+norm32)
+    } else {
+      tmpU32no1 >>= -norm32;  // Q(prevQMagn+qMagn+norm32)
+    }
+    tmpU32no2 =
+        WEBRTC_SPL_UMUL(tmpU32no1, tmpU32no1);  // Q(2*(prevQMagn+qMagn-norm32))
+
+    nShifts += norm32;
+    nShifts <<= 1;
+    if (nShifts < 0) {
+      varPauseUFX >>= (-nShifts);  // Q(2*(qMagn+norm32+minPause))
+      nShifts = 0;
+    }
+    if (varPauseUFX > 0) {
+      // Q(2*(qMagn+norm32-16+minPause))
+      tmpU32no1 = tmpU32no2 / varPauseUFX;
+      tmpU32no1 >>= nShifts;
+
+      // Q(2*qMagn)
+      avgDiffNormMagnUFX -= WEBRTC_SPL_MIN(avgDiffNormMagnUFX, tmpU32no1);
+    } else {
+      avgDiffNormMagnUFX = 0;
+    }
+  }
+  // normalize and compute time average update of difference feature
+  tmpU32no1 = avgDiffNormMagnUFX >> (2 * inst->normData);
+  if (inst->featureSpecDiff > tmpU32no1) {
+    tmpU32no2 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecDiff - tmpU32no1,
+                                      SPECT_DIFF_TAVG_Q8);  // Q(8-2*stages)
+    inst->featureSpecDiff -= tmpU32no2 >> 8;                // Q(-2*stages)
+  } else {
+    tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no1 - inst->featureSpecDiff,
+                                      SPECT_DIFF_TAVG_Q8);  // Q(8-2*stages)
+    inst->featureSpecDiff += tmpU32no2 >> 8;                // Q(-2*stages)
+  }
+}
+
+// Transform input (speechFrame) to frequency domain magnitude (magnU16)
+void WebRtcNsx_DataAnalysis(NoiseSuppressionFixedC* inst,
+                            short* speechFrame,
+                            uint16_t* magnU16) {
+  uint32_t tmpU32no1;
+
+  int32_t tmp_1_w32 = 0;
+  int32_t tmp_2_w32 = 0;
+  int32_t sum_log_magn = 0;
+  int32_t sum_log_i_log_magn = 0;
+
+  uint16_t sum_log_magn_u16 = 0;
+  uint16_t tmp_u16 = 0;
+
+  int16_t sum_log_i = 0;
+  int16_t sum_log_i_square = 0;
+  int16_t frac = 0;
+  int16_t log2 = 0;
+  int16_t matrix_determinant = 0;
+  int16_t maxWinData;
+
+  size_t i, j;
+  int zeros;
+  int net_norm = 0;
+  int right_shifts_in_magnU16 = 0;
+  int right_shifts_in_initMagnEst = 0;
+
+  int16_t winData_buff[ANAL_BLOCKL_MAX * 2 + 16];
+  int16_t realImag_buff[ANAL_BLOCKL_MAX * 2 + 16];
+
+  // Align the structures to 32-byte boundary for the FFT function.
+  int16_t* winData = (int16_t*)(((uintptr_t)winData_buff + 31) & ~31);
+  int16_t* realImag = (int16_t*)(((uintptr_t)realImag_buff + 31) & ~31);
+
+  // Update analysis buffer for lower band, and window data before FFT.
+  WebRtcNsx_AnalysisUpdate(inst, winData, speechFrame);
+
+  // Get input energy
+  inst->energyIn =
+      WebRtcSpl_Energy(winData, inst->anaLen, &inst->scaleEnergyIn);
+
+  // Reset zero input flag
+  inst->zeroInputSignal = 0;
+  // Acquire norm for winData
+  maxWinData = WebRtcSpl_MaxAbsValueW16(winData, inst->anaLen);
+  inst->normData = WebRtcSpl_NormW16(maxWinData);
+  if (maxWinData == 0) {
+    // Treat zero input separately.
+    inst->zeroInputSignal = 1;
+    return;
+  }
+
+  // Determine the net normalization in the frequency domain
+  net_norm = inst->stages - inst->normData;
+  // Track lowest normalization factor and use it to prevent wrap around in
+  // shifting
+  right_shifts_in_magnU16 = inst->normData - inst->minNorm;
+  right_shifts_in_initMagnEst = WEBRTC_SPL_MAX(-right_shifts_in_magnU16, 0);
+  inst->minNorm -= right_shifts_in_initMagnEst;
+  right_shifts_in_magnU16 = WEBRTC_SPL_MAX(right_shifts_in_magnU16, 0);
+
+  // create realImag as winData interleaved with zeros (= imag. part), normalize
+  // it
+  WebRtcNsx_NormalizeRealBuffer(inst, winData, realImag);
+
+  // FFT output will be in winData[].
+  WebRtcSpl_RealForwardFFT(inst->real_fft, realImag, winData);
+
+  inst->imag[0] = 0;  // Q(normData-stages)
+  inst->imag[inst->anaLen2] = 0;
+  inst->real[0] = winData[0];  // Q(normData-stages)
+  inst->real[inst->anaLen2] = winData[inst->anaLen];
+  // Q(2*(normData-stages))
+  inst->magnEnergy = (uint32_t)(inst->real[0] * inst->real[0]);
+  inst->magnEnergy +=
+      (uint32_t)(inst->real[inst->anaLen2] * inst->real[inst->anaLen2]);
+  magnU16[0] =
+      (uint16_t)WEBRTC_SPL_ABS_W16(inst->real[0]);  // Q(normData-stages)
+  magnU16[inst->anaLen2] =
+      (uint16_t)WEBRTC_SPL_ABS_W16(inst->real[inst->anaLen2]);
+  inst->sumMagn = (uint32_t)magnU16[0];  // Q(normData-stages)
+  inst->sumMagn += (uint32_t)magnU16[inst->anaLen2];
+
+  if (inst->blockIndex >= END_STARTUP_SHORT) {
+    for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
+      inst->real[i] = winData[j];
+      inst->imag[i] = -winData[j + 1];
+      // magnitude spectrum
+      // energy in Q(2*(normData-stages))
+      tmpU32no1 = (uint32_t)(winData[j] * winData[j]);
+      tmpU32no1 += (uint32_t)(winData[j + 1] * winData[j + 1]);
+      inst->magnEnergy += tmpU32no1;  // Q(2*(normData-stages))
+
+      magnU16[i] =
+          (uint16_t)WebRtcSpl_SqrtFloor(tmpU32no1);  // Q(normData-stages)
+      inst->sumMagn += (uint32_t)magnU16[i];         // Q(normData-stages)
+    }
+  } else {
+    //
+    // Gather information during startup for noise parameter estimation
+    //
+
+    // Switch initMagnEst to Q(minNorm-stages)
+    inst->initMagnEst[0] >>= right_shifts_in_initMagnEst;
+    inst->initMagnEst[inst->anaLen2] >>= right_shifts_in_initMagnEst;
+
+    // Update initMagnEst with magnU16 in Q(minNorm-stages).
+    inst->initMagnEst[0] += magnU16[0] >> right_shifts_in_magnU16;
+    inst->initMagnEst[inst->anaLen2] +=
+        magnU16[inst->anaLen2] >> right_shifts_in_magnU16;
+
+    log2 = 0;
+    if (magnU16[inst->anaLen2]) {
+      // Calculate log2(magnU16[inst->anaLen2])
+      zeros = WebRtcSpl_NormU32((uint32_t)magnU16[inst->anaLen2]);
+      frac = (int16_t)(
+          (((uint32_t)magnU16[inst->anaLen2] << zeros) & 0x7FFFFFFF) >>
+          23);  // Q8
+      // log2(magnU16(i)) in Q8
+      RTC_DCHECK_LT(frac, 256);
+      log2 = (int16_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]);
+    }
+
+    sum_log_magn = (int32_t)log2;  // Q8
+    // sum_log_i_log_magn in Q17
+    sum_log_i_log_magn = (kLogIndex[inst->anaLen2] * log2) >> 3;
+
+    for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
+      inst->real[i] = winData[j];
+      inst->imag[i] = -winData[j + 1];
+      // magnitude spectrum
+      // energy in Q(2*(normData-stages))
+      tmpU32no1 = (uint32_t)(winData[j] * winData[j]);
+      tmpU32no1 += (uint32_t)(winData[j + 1] * winData[j + 1]);
+      inst->magnEnergy += tmpU32no1;  // Q(2*(normData-stages))
+
+      magnU16[i] =
+          (uint16_t)WebRtcSpl_SqrtFloor(tmpU32no1);  // Q(normData-stages)
+      inst->sumMagn += (uint32_t)magnU16[i];         // Q(normData-stages)
+
+      // Switch initMagnEst to Q(minNorm-stages)
+      inst->initMagnEst[i] >>= right_shifts_in_initMagnEst;
+
+      // Update initMagnEst with magnU16 in Q(minNorm-stages).
+      inst->initMagnEst[i] += magnU16[i] >> right_shifts_in_magnU16;
+
+      if (i >= kStartBand) {
+        // For pink noise estimation. Collect data neglecting lower frequency
+        // band
+        log2 = 0;
+        if (magnU16[i]) {
+          zeros = WebRtcSpl_NormU32((uint32_t)magnU16[i]);
+          frac =
+              (int16_t)((((uint32_t)magnU16[i] << zeros) & 0x7FFFFFFF) >> 23);
+          // log2(magnU16(i)) in Q8
+          RTC_DCHECK_LT(frac, 256);
+          log2 = (int16_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]);
+        }
+        sum_log_magn += (int32_t)log2;  // Q8
+        // sum_log_i_log_magn in Q17
+        sum_log_i_log_magn += (kLogIndex[i] * log2) >> 3;
+      }
+    }
+
+    //
+    // compute simplified noise model during startup
+    //
+
+    // Estimate White noise
+
+    // Switch whiteNoiseLevel to Q(minNorm-stages)
+    inst->whiteNoiseLevel >>= right_shifts_in_initMagnEst;
+
+    // Update the average magnitude spectrum, used as noise estimate.
+    tmpU32no1 = WEBRTC_SPL_UMUL_32_16(inst->sumMagn, inst->overdrive);
+    tmpU32no1 >>= inst->stages + 8;
+
+    // Replacing division above with 'stages' shifts
+    // Shift to same Q-domain as whiteNoiseLevel
+    tmpU32no1 >>= right_shifts_in_magnU16;
+    // This operation is safe from wrap around as long as END_STARTUP_SHORT <
+    // 128
+    RTC_DCHECK_LT(END_STARTUP_SHORT, 128);
+    inst->whiteNoiseLevel += tmpU32no1;  // Q(minNorm-stages)
+
+    // Estimate Pink noise parameters
+    // Denominator used in both parameter estimates.
+    // The value is only dependent on the size of the frequency band
+    // (kStartBand) and to reduce computational complexity stored in a table
+    // (kDeterminantEstMatrix[])
+    RTC_DCHECK_LT(kStartBand, 66);
+    matrix_determinant = kDeterminantEstMatrix[kStartBand];  // Q0
+    sum_log_i = kSumLogIndex[kStartBand];                    // Q5
+    sum_log_i_square = kSumSquareLogIndex[kStartBand];       // Q2
+    if (inst->fs == 8000) {
+      // Adjust values to shorter blocks in narrow band.
+      tmp_1_w32 = (int32_t)matrix_determinant;
+      tmp_1_w32 += (kSumLogIndex[65] * sum_log_i) >> 9;
+      tmp_1_w32 -= (kSumLogIndex[65] * kSumLogIndex[65]) >> 10;
+      tmp_1_w32 -= (int32_t)sum_log_i_square << 4;
+      tmp_1_w32 -= ((inst->magnLen - kStartBand) * kSumSquareLogIndex[65]) >> 2;
+      matrix_determinant = (int16_t)tmp_1_w32;
+      sum_log_i -= kSumLogIndex[65];               // Q5
+      sum_log_i_square -= kSumSquareLogIndex[65];  // Q2
+    }
+
+    // Necessary number of shifts to fit sum_log_magn in a word16
+    zeros = 16 - WebRtcSpl_NormW32(sum_log_magn);
+    if (zeros < 0) {
+      zeros = 0;
+    }
+    tmp_1_w32 = sum_log_magn << 1;                      // Q9
+    sum_log_magn_u16 = (uint16_t)(tmp_1_w32 >> zeros);  // Q(9-zeros).
+
+    // Calculate and update pinkNoiseNumerator. Result in Q11.
+    tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i_square,
+                                      sum_log_magn_u16);  // Q(11-zeros)
+    tmpU32no1 = sum_log_i_log_magn >> 12;                 // Q5
+
+    // Shift the largest value of sum_log_i and tmp32no3 before multiplication
+    tmp_u16 = ((uint16_t)sum_log_i << 1);  // Q6
+    if ((uint32_t)sum_log_i > tmpU32no1) {
+      tmp_u16 >>= zeros;
+    } else {
+      tmpU32no1 >>= zeros;
+    }
+    tmp_2_w32 -=
+        (int32_t)WEBRTC_SPL_UMUL_32_16(tmpU32no1, tmp_u16);  // Q(11-zeros)
+    matrix_determinant >>= zeros;                            // Q(-zeros)
+    tmp_2_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant);  // Q11
+    tmp_2_w32 += (int32_t)net_norm << 11;                            // Q11
+    if (tmp_2_w32 < 0) {
+      tmp_2_w32 = 0;
+    }
+    inst->pinkNoiseNumerator += tmp_2_w32;  // Q11
+
+    // Calculate and update pinkNoiseExp. Result in Q14.
+    tmp_2_w32 =
+        WEBRTC_SPL_MUL_16_U16(sum_log_i, sum_log_magn_u16);  // Q(14-zeros)
+    tmp_1_w32 = sum_log_i_log_magn >> (3 + zeros);
+    tmp_1_w32 *= inst->magnLen - kStartBand;
+    tmp_2_w32 -= tmp_1_w32;  // Q(14-zeros)
+    if (tmp_2_w32 > 0) {
+      // If the exponential parameter is negative force it to zero, which means
+      // a flat spectrum.
+      tmp_1_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant);  // Q14
+      inst->pinkNoiseExp += WEBRTC_SPL_SAT(16384, tmp_1_w32, 0);       // Q14
+    }
+  }
+}
+
+void WebRtcNsx_DataSynthesis(NoiseSuppressionFixedC* inst, short* outFrame) {
+  int32_t energyOut;
+
+  int16_t realImag_buff[ANAL_BLOCKL_MAX * 2 + 16];
+  int16_t rfft_out_buff[ANAL_BLOCKL_MAX * 2 + 16];
+
+  // Align the structures to 32-byte boundary for the FFT function.
+  int16_t* realImag = (int16_t*)(((uintptr_t)realImag_buff + 31) & ~31);
+  int16_t* rfft_out = (int16_t*)(((uintptr_t)rfft_out_buff + 31) & ~31);
+
+  int16_t tmp16no1, tmp16no2;
+  int16_t energyRatio;
+  int16_t gainFactor, gainFactor1, gainFactor2;
+
+  size_t i;
+  int outCIFFT;
+  int scaleEnergyOut = 0;
+
+  if (inst->zeroInputSignal) {
+    // synthesize the special case of zero input
+    // read out fully processed segment
+    for (i = 0; i < inst->blockLen10ms; i++) {
+      outFrame[i] = inst->synthesisBuffer[i];  // Q0
+    }
+    // update synthesis buffer
+    memcpy(
+        inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
+        (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->synthesisBuffer));
+    WebRtcSpl_ZerosArrayW16(
+        inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms,
+        inst->blockLen10ms);
+    return;
+  }
+
+  // Filter the data in the frequency domain, and create spectrum.
+  WebRtcNsx_PrepareSpectrum(inst, realImag);
+
+  // Inverse FFT output will be in rfft_out[].
+  outCIFFT = WebRtcSpl_RealInverseFFT(inst->real_fft, realImag, rfft_out);
+
+  WebRtcNsx_Denormalize(inst, rfft_out, outCIFFT);
+
+  // scale factor: only do it after END_STARTUP_LONG time
+  gainFactor = 8192;  // 8192 = Q13(1.0)
+  if (inst->gainMap == 1 && inst->blockIndex > END_STARTUP_LONG &&
+      inst->energyIn > 0) {
+    // Q(-scaleEnergyOut)
+    energyOut = WebRtcSpl_Energy(inst->real, inst->anaLen, &scaleEnergyOut);
+    if (scaleEnergyOut == 0 && !(energyOut & 0x7f800000)) {
+      energyOut = WEBRTC_SPL_SHIFT_W32(
+          energyOut, 8 + scaleEnergyOut - inst->scaleEnergyIn);
+    } else {
+      // |energyIn| is currently in Q(|scaleEnergyIn|), but to later on end up
+      // with an |energyRatio| in Q8 we need to change the Q-domain to
+      // Q(-8-scaleEnergyOut).
+      inst->energyIn >>= 8 + scaleEnergyOut - inst->scaleEnergyIn;
+    }
+
+    RTC_DCHECK_GT(inst->energyIn, 0);
+    energyRatio = (energyOut + inst->energyIn / 2) / inst->energyIn;  // Q8
+    // Limit the ratio to [0, 1] in Q8, i.e., [0, 256]
+    energyRatio = WEBRTC_SPL_SAT(256, energyRatio, 0);
+
+    // all done in lookup tables now
+    RTC_DCHECK_LT(energyRatio, 257);
+    gainFactor1 = kFactor1Table[energyRatio];       // Q8
+    gainFactor2 = inst->factor2Table[energyRatio];  // Q8
+
+    // combine both scales with speech/noise prob: note prior (priorSpeechProb)
+    // is not frequency dependent
+
+    // factor = inst->priorSpeechProb*factor1 +
+    // (1.0-inst->priorSpeechProb)*factor2; // original code
+    tmp16no1 = (int16_t)(((16384 - inst->priorNonSpeechProb) * gainFactor1) >>
+                         14);  // in Q13, where 16384 = Q14(1.0)
+    tmp16no2 = (int16_t)((inst->priorNonSpeechProb * gainFactor2) >> 14);
+    gainFactor = tmp16no1 + tmp16no2;  // Q13
+  }                                    // out of flag_gain_map==1
+
+  // Synthesis, read out fully processed segment, and update synthesis buffer.
+  WebRtcNsx_SynthesisUpdate(inst, outFrame, gainFactor);
+}
+
+void WebRtcNsx_ProcessCore(NoiseSuppressionFixedC* inst,
+                           const int16_t* const* speechFrame,
+                           int num_bands,
+                           int16_t* const* outFrame) {
+  // main routine for noise suppression
+
+  uint32_t tmpU32no1, tmpU32no2, tmpU32no3;
+  uint32_t satMax, maxNoiseU32;
+  uint32_t tmpMagnU32, tmpNoiseU32;
+  uint32_t nearMagnEst;
+  uint32_t noiseUpdateU32;
+  uint32_t noiseU32[HALF_ANAL_BLOCKL];
+  uint32_t postLocSnr[HALF_ANAL_BLOCKL];
+  uint32_t priorLocSnr[HALF_ANAL_BLOCKL];
+  uint32_t prevNearSnr[HALF_ANAL_BLOCKL];
+  uint32_t curNearSnr;
+  uint32_t priorSnr;
+  uint32_t noise_estimate = 0;
+  uint32_t noise_estimate_avg = 0;
+  uint32_t numerator = 0;
+
+  int32_t tmp32no1, tmp32no2;
+  int32_t pink_noise_num_avg = 0;
+
+  uint16_t tmpU16no1;
+  uint16_t magnU16[HALF_ANAL_BLOCKL];
+  uint16_t prevNoiseU16[HALF_ANAL_BLOCKL];
+  uint16_t nonSpeechProbFinal[HALF_ANAL_BLOCKL];
+  uint16_t gammaNoise, prevGammaNoise;
+  uint16_t noiseSupFilterTmp[HALF_ANAL_BLOCKL];
+
+  int16_t qMagn, qNoise;
+  int16_t avgProbSpeechHB, gainModHB, avgFilterGainHB, gainTimeDomainHB;
+  int16_t pink_noise_exp_avg = 0;
+
+  size_t i, j;
+  int nShifts, postShifts;
+  int norm32no1, norm32no2;
+  int flag, sign;
+  int q_domain_to_use = 0;
+
+  // Code for ARMv7-Neon platform assumes the following:
+  RTC_DCHECK_GT(inst->anaLen, 0);
+  RTC_DCHECK_GT(inst->anaLen2, 0);
+  RTC_DCHECK_EQ(0, inst->anaLen % 16);
+  RTC_DCHECK_EQ(0, inst->anaLen2 % 8);
+  RTC_DCHECK_GT(inst->blockLen10ms, 0);
+  RTC_DCHECK_EQ(0, inst->blockLen10ms % 16);
+  RTC_DCHECK_EQ(inst->magnLen, inst->anaLen2 + 1);
+
+#ifdef NS_FILEDEBUG
+  if (fwrite(spframe, sizeof(short), inst->blockLen10ms, inst->infile) !=
+      inst->blockLen10ms) {
+    RTC_NOTREACHED();
+  }
+#endif
+
+  // Check that initialization has been done
+  RTC_DCHECK_EQ(1, inst->initFlag);
+  RTC_DCHECK_LE(num_bands - 1, NUM_HIGH_BANDS_MAX);
+
+  const int16_t* const* speechFrameHB = NULL;
+  int16_t* const* outFrameHB = NULL;
+  size_t num_high_bands = 0;
+  if (num_bands > 1) {
+    speechFrameHB = &speechFrame[1];
+    outFrameHB = &outFrame[1];
+    num_high_bands = (size_t)(num_bands - 1);
+  }
+
+  // Store speechFrame and transform to frequency domain
+  WebRtcNsx_DataAnalysis(inst, (int16_t*)speechFrame[0], magnU16);
+
+  if (inst->zeroInputSignal) {
+    WebRtcNsx_DataSynthesis(inst, outFrame[0]);
+
+    if (num_bands > 1) {
+      // update analysis buffer for H band
+      // append new data to buffer FX
+      for (i = 0; i < num_high_bands; ++i) {
+        int block_shift = inst->anaLen - inst->blockLen10ms;
+        memcpy(inst->dataBufHBFX[i], inst->dataBufHBFX[i] + inst->blockLen10ms,
+               block_shift * sizeof(*inst->dataBufHBFX[i]));
+        memcpy(inst->dataBufHBFX[i] + block_shift, speechFrameHB[i],
+               inst->blockLen10ms * sizeof(*inst->dataBufHBFX[i]));
+        for (j = 0; j < inst->blockLen10ms; j++) {
+          outFrameHB[i][j] = inst->dataBufHBFX[i][j];  // Q0
+        }
+      }
+    }  // end of H band gain computation
+    return;
+  }
+
+  // Update block index when we have something to process
+  inst->blockIndex++;
+  //
+
+  // Norm of magn
+  qMagn = inst->normData - inst->stages;
+
+  // Compute spectral flatness on input spectrum
+  WebRtcNsx_ComputeSpectralFlatness(inst, magnU16);
+
+  // quantile noise estimate
+  WebRtcNsx_NoiseEstimation(inst, magnU16, noiseU32, &qNoise);
+
+  // noise estimate from previous frame
+  for (i = 0; i < inst->magnLen; i++) {
+    prevNoiseU16[i] = (uint16_t)(inst->prevNoiseU32[i] >> 11);  // Q(prevQNoise)
+  }
+
+  if (inst->blockIndex < END_STARTUP_SHORT) {
+    // Noise Q-domain to be used later; see description at end of section.
+    q_domain_to_use = WEBRTC_SPL_MIN((int)qNoise, inst->minNorm - inst->stages);
+
+    // Calculate frequency independent parts in parametric noise estimate and
+    // calculate the estimate for the lower frequency band (same values for all
+    // frequency bins)
+    if (inst->pinkNoiseExp) {
+      pink_noise_exp_avg =
+          (int16_t)WebRtcSpl_DivW32W16(inst->pinkNoiseExp,
+                                       (int16_t)(inst->blockIndex + 1));  // Q14
+      pink_noise_num_avg =
+          WebRtcSpl_DivW32W16(inst->pinkNoiseNumerator,
+                              (int16_t)(inst->blockIndex + 1));  // Q11
+      WebRtcNsx_CalcParametricNoiseEstimate(
+          inst, pink_noise_exp_avg, pink_noise_num_avg, kStartBand,
+          &noise_estimate, &noise_estimate_avg);
+    } else {
+      // Use white noise estimate if we have poor pink noise parameter estimates
+      noise_estimate = inst->whiteNoiseLevel;  // Q(minNorm-stages)
+      noise_estimate_avg =
+          noise_estimate / (inst->blockIndex + 1);  // Q(minNorm-stages)
+    }
+    for (i = 0; i < inst->magnLen; i++) {
+      // Estimate the background noise using the pink noise parameters if
+      // permitted
+      if ((inst->pinkNoiseExp) && (i >= kStartBand)) {
+        // Reset noise_estimate
+        noise_estimate = 0;
+        noise_estimate_avg = 0;
+        // Calculate the parametric noise estimate for current frequency bin
+        WebRtcNsx_CalcParametricNoiseEstimate(
+            inst, pink_noise_exp_avg, pink_noise_num_avg, i, &noise_estimate,
+            &noise_estimate_avg);
+      }
+      // Calculate parametric Wiener filter
+      noiseSupFilterTmp[i] = inst->denoiseBound;
+      if (inst->initMagnEst[i]) {
+        // numerator = (initMagnEst - noise_estimate * overdrive)
+        // Result in Q(8+minNorm-stages)
+        tmpU32no1 = WEBRTC_SPL_UMUL_32_16(noise_estimate, inst->overdrive);
+        numerator = inst->initMagnEst[i] << 8;
+        if (numerator > tmpU32no1) {
+          // Suppression filter coefficient larger than zero, so calculate.
+          numerator -= tmpU32no1;
+
+          // Determine number of left shifts in numerator for best accuracy
+          // after division
+          nShifts = WebRtcSpl_NormU32(numerator);
+          nShifts = WEBRTC_SPL_SAT(6, nShifts, 0);
+
+          // Shift numerator to Q(nShifts+8+minNorm-stages)
+          numerator <<= nShifts;
+
+          // Shift denominator to Q(nShifts-6+minNorm-stages)
+          tmpU32no1 = inst->initMagnEst[i] >> (6 - nShifts);
+          if (tmpU32no1 == 0) {
+            // This is only possible if numerator = 0, in which case
+            // we don't need any division.
+            tmpU32no1 = 1;
+          }
+          tmpU32no2 = numerator / tmpU32no1;  // Q14
+          noiseSupFilterTmp[i] =
+              (uint16_t)WEBRTC_SPL_SAT(16384, tmpU32no2,
+                                       (uint32_t)(inst->denoiseBound));  // Q14
+        }
+      }
+      // Weight quantile noise 'noiseU32' with modeled noise
+      // 'noise_estimate_avg' 'noiseU32 is in Q(qNoise) and 'noise_estimate' in
+      // Q(minNorm-stages) To guarantee that we do not get wrap around when
+      // shifting to the same domain we use the lowest one. Furthermore, we need
+      // to save 6 bits for the weighting. 'noise_estimate_avg' can handle this
+      // operation by construction, but 'noiseU32' may not.
+
+      // Shift 'noiseU32' to 'q_domain_to_use'
+      tmpU32no1 = noiseU32[i] >> (qNoise - q_domain_to_use);
+      // Shift 'noise_estimate_avg' to 'q_domain_to_use'
+      tmpU32no2 = noise_estimate_avg >>
+                  (inst->minNorm - inst->stages - q_domain_to_use);
+      // Make a simple check to see if we have enough room for weighting
+      // 'tmpU32no1' without wrap around
+      nShifts = 0;
+      if (tmpU32no1 & 0xfc000000) {
+        tmpU32no1 >>= 6;
+        tmpU32no2 >>= 6;
+        nShifts = 6;
+      }
+      tmpU32no1 *= inst->blockIndex;
+      tmpU32no2 *= (END_STARTUP_SHORT - inst->blockIndex);
+      // Add them together and divide by startup length
+      noiseU32[i] =
+          WebRtcSpl_DivU32U16(tmpU32no1 + tmpU32no2, END_STARTUP_SHORT);
+      // Shift back if necessary
+      noiseU32[i] <<= nShifts;
+    }
+    // Update new Q-domain for 'noiseU32'
+    qNoise = q_domain_to_use;
+  }
+  // compute average signal during END_STARTUP_LONG time:
+  // used to normalize spectral difference measure
+  if (inst->blockIndex < END_STARTUP_LONG) {
+    // substituting division with shift ending up in Q(-2*stages)
+    inst->timeAvgMagnEnergyTmp +=
+        inst->magnEnergy >> (2 * inst->normData + inst->stages - 1);
+    inst->timeAvgMagnEnergy =
+        WebRtcSpl_DivU32U16(inst->timeAvgMagnEnergyTmp, inst->blockIndex + 1);
+  }
+
+  // start processing at frames == converged+1
+  // STEP 1: compute prior and post SNR based on quantile noise estimates
+
+  // compute direct decision (DD) estimate of prior SNR: needed for new method
+  satMax = (uint32_t)1048575;  // Largest possible value without getting
+                               // overflow despite shifting 12 steps
+  postShifts = 6 + qMagn - qNoise;
+  nShifts = 5 - inst->prevQMagn + inst->prevQNoise;
+  for (i = 0; i < inst->magnLen; i++) {
+    // FLOAT:
+    // post SNR
+    // postLocSnr[i] = 0.0;
+    // if (magn[i] > noise[i])
+    // {
+    //   postLocSnr[i] = magn[i] / (noise[i] + 0.0001);
+    // }
+    // // previous post SNR
+    // // previous estimate: based on previous frame with gain filter (smooth is
+    // previous filter)
+    //
+    // prevNearSnr[i] = inst->prevMagnU16[i] / (inst->noisePrev[i] + 0.0001) *
+    // (inst->smooth[i]);
+    //
+    // // DD estimate is sum of two terms: current estimate and previous
+    // estimate
+    // // directed decision update of priorSnr (or we actually store
+    // [2*priorSnr+1])
+    //
+    // priorLocSnr[i] = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) *
+    // (postLocSnr[i] - 1.0);
+
+    // calculate post SNR: output in Q11
+    postLocSnr[i] = 2048;                   // 1.0 in Q11
+    tmpU32no1 = (uint32_t)magnU16[i] << 6;  // Q(6+qMagn)
+    if (postShifts < 0) {
+      tmpU32no2 = noiseU32[i] >> -postShifts;  // Q(6+qMagn)
+    } else {
+      tmpU32no2 = noiseU32[i] << postShifts;  // Q(6+qMagn)
+    }
+    if (tmpU32no1 > tmpU32no2) {
+      // Current magnitude larger than noise
+      tmpU32no1 <<= 11;  // Q(17+qMagn)
+      if (tmpU32no2 > 0) {
+        tmpU32no1 /= tmpU32no2;                             // Q11
+        postLocSnr[i] = WEBRTC_SPL_MIN(satMax, tmpU32no1);  // Q11
+      } else {
+        postLocSnr[i] = satMax;
+      }
+    }
+
+    // calculate prevNearSnr[i] and save for later instead of recalculating it
+    // later |nearMagnEst| in Q(prevQMagn + 14)
+    nearMagnEst = inst->prevMagnU16[i] * inst->noiseSupFilter[i];
+    tmpU32no1 = nearMagnEst << 3;                  // Q(prevQMagn+17)
+    tmpU32no2 = inst->prevNoiseU32[i] >> nShifts;  // Q(prevQMagn+6)
+
+    if (tmpU32no2 > 0) {
+      tmpU32no1 /= tmpU32no2;                         // Q11
+      tmpU32no1 = WEBRTC_SPL_MIN(satMax, tmpU32no1);  // Q11
+    } else {
+      tmpU32no1 = satMax;  // Q11
+    }
+    prevNearSnr[i] = tmpU32no1;  // Q11
+
+    // directed decision update of priorSnr
+    tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11);  // Q22
+    tmpU32no2 = WEBRTC_SPL_UMUL_32_16(postLocSnr[i] - 2048,
+                                      ONE_MINUS_DD_PR_SNR_Q11);  // Q22
+    priorSnr = tmpU32no1 + tmpU32no2 + 512;  // Q22 (added 512 for rounding)
+    // priorLocSnr = 1 + 2*priorSnr
+    priorLocSnr[i] = 2048 + (priorSnr >> 10);  // Q11
+  }                                            // end of loop over frequencies
+  // done with step 1: DD computation of prior and post SNR
+
+  // STEP 2: compute speech/noise likelihood
+
+  // compute difference of input spectrum with learned/estimated noise spectrum
+  WebRtcNsx_ComputeSpectralDifference(inst, magnU16);
+  // compute histograms for determination of parameters (thresholds and weights
+  // for features) parameters are extracted once every window time
+  // (=inst->modelUpdate) counter update
+  inst->cntThresUpdate++;
+  flag = (int)(inst->cntThresUpdate == inst->modelUpdate);
+  // update histogram
+  WebRtcNsx_FeatureParameterExtraction(inst, flag);
+  // compute model parameters
+  if (flag) {
+    inst->cntThresUpdate = 0;  // Reset counter
+    // update every window:
+    // get normalization for spectral difference for next window estimate
+
+    // Shift to Q(-2*stages)
+    inst->curAvgMagnEnergy >>= STAT_UPDATES;
+
+    tmpU32no1 = (inst->curAvgMagnEnergy + inst->timeAvgMagnEnergy + 1) >>
+                1;  // Q(-2*stages)
+    // Update featureSpecDiff
+    if ((tmpU32no1 != inst->timeAvgMagnEnergy) && (inst->featureSpecDiff) &&
+        (inst->timeAvgMagnEnergy > 0)) {
+      norm32no1 = 0;
+      tmpU32no3 = tmpU32no1;
+      while (0xFFFF0000 & tmpU32no3) {
+        tmpU32no3 >>= 1;
+        norm32no1++;
+      }
+      tmpU32no2 = inst->featureSpecDiff;
+      while (0xFFFF0000 & tmpU32no2) {
+        tmpU32no2 >>= 1;
+        norm32no1++;
+      }
+      tmpU32no3 = WEBRTC_SPL_UMUL(tmpU32no3, tmpU32no2);
+      tmpU32no3 /= inst->timeAvgMagnEnergy;
+      if (WebRtcSpl_NormU32(tmpU32no3) < norm32no1) {
+        inst->featureSpecDiff = 0x007FFFFF;
+      } else {
+        inst->featureSpecDiff =
+            WEBRTC_SPL_MIN(0x007FFFFF, tmpU32no3 << norm32no1);
+      }
+    }
+
+    inst->timeAvgMagnEnergy = tmpU32no1;  // Q(-2*stages)
+    inst->curAvgMagnEnergy = 0;
+  }
+
+  // compute speech/noise probability
+  WebRtcNsx_SpeechNoiseProb(inst, nonSpeechProbFinal, priorLocSnr, postLocSnr);
+
+  // time-avg parameter for noise update
+  gammaNoise = NOISE_UPDATE_Q8;  // Q8
+
+  maxNoiseU32 = 0;
+  postShifts = inst->prevQNoise - qMagn;
+  nShifts = inst->prevQMagn - qMagn;
+  for (i = 0; i < inst->magnLen; i++) {
+    // temporary noise update: use it for speech frames if update value is less
+    // than previous the formula has been rewritten into: noiseUpdate =
+    // noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] -
+    // noisePrev[i])
+
+    if (postShifts < 0) {
+      tmpU32no2 = magnU16[i] >> -postShifts;  // Q(prevQNoise)
+    } else {
+      tmpU32no2 = (uint32_t)magnU16[i] << postShifts;  // Q(prevQNoise)
+    }
+    if (prevNoiseU16[i] > tmpU32no2) {
+      sign = -1;
+      tmpU32no1 = prevNoiseU16[i] - tmpU32no2;
+    } else {
+      sign = 1;
+      tmpU32no1 = tmpU32no2 - prevNoiseU16[i];
+    }
+    noiseUpdateU32 = inst->prevNoiseU32[i];  // Q(prevQNoise+11)
+    tmpU32no3 = 0;
+    if ((tmpU32no1) && (nonSpeechProbFinal[i])) {
+      // This value will be used later, if gammaNoise changes
+      tmpU32no3 = WEBRTC_SPL_UMUL_32_16(
+          tmpU32no1, nonSpeechProbFinal[i]);  // Q(prevQNoise+8)
+      if (0x7c000000 & tmpU32no3) {
+        // Shifting required before multiplication
+        tmpU32no2 = (tmpU32no3 >> 5) * gammaNoise;  // Q(prevQNoise+11)
+      } else {
+        // We can do shifting after multiplication
+        tmpU32no2 = (tmpU32no3 * gammaNoise) >> 5;  // Q(prevQNoise+11)
+      }
+      if (sign > 0) {
+        noiseUpdateU32 += tmpU32no2;  // Q(prevQNoise+11)
+      } else {
+        // This operation is safe. We can never get wrap around, since worst
+        // case scenario means magnU16 = 0
+        noiseUpdateU32 -= tmpU32no2;  // Q(prevQNoise+11)
+      }
+    }
+
+    // increase gamma (i.e., less noise update) for frame likely to be speech
+    prevGammaNoise = gammaNoise;
+    gammaNoise = NOISE_UPDATE_Q8;
+    // time-constant based on speech/noise state
+    // increase gamma (i.e., less noise update) for frames likely to be speech
+    if (nonSpeechProbFinal[i] < ONE_MINUS_PROB_RANGE_Q8) {
+      gammaNoise = GAMMA_NOISE_TRANS_AND_SPEECH_Q8;
+    }
+
+    if (prevGammaNoise != gammaNoise) {
+      // new noise update
+      // this line is the same as above, only that the result is stored in a
+      // different variable and the gammaNoise has changed
+      //
+      // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb *
+      // (magn[i] - noisePrev[i])
+
+      if (0x7c000000 & tmpU32no3) {
+        // Shifting required before multiplication
+        tmpU32no2 = (tmpU32no3 >> 5) * gammaNoise;  // Q(prevQNoise+11)
+      } else {
+        // We can do shifting after multiplication
+        tmpU32no2 = (tmpU32no3 * gammaNoise) >> 5;  // Q(prevQNoise+11)
+      }
+      if (sign > 0) {
+        tmpU32no1 = inst->prevNoiseU32[i] + tmpU32no2;  // Q(prevQNoise+11)
+      } else {
+        tmpU32no1 = inst->prevNoiseU32[i] - tmpU32no2;  // Q(prevQNoise+11)
+      }
+      if (noiseUpdateU32 > tmpU32no1) {
+        noiseUpdateU32 = tmpU32no1;  // Q(prevQNoise+11)
+      }
+    }
+    noiseU32[i] = noiseUpdateU32;  // Q(prevQNoise+11)
+    if (noiseUpdateU32 > maxNoiseU32) {
+      maxNoiseU32 = noiseUpdateU32;
+    }
+
+    // conservative noise update
+    // // original FLOAT code
+    // if (prob_speech < PROB_RANGE) {
+    // inst->avgMagnPause[i] = inst->avgMagnPause[i] + (1.0 -
+    // gamma_pause)*(magn[i] - inst->avgMagnPause[i]);
+    // }
+
+    tmp32no2 = WEBRTC_SPL_SHIFT_W32(inst->avgMagnPause[i], -nShifts);
+    if (nonSpeechProbFinal[i] > ONE_MINUS_PROB_RANGE_Q8) {
+      if (nShifts < 0) {
+        tmp32no1 = (int32_t)magnU16[i] - tmp32no2;  // Q(qMagn)
+        tmp32no1 *= ONE_MINUS_GAMMA_PAUSE_Q8;       // Q(8+prevQMagn+nShifts)
+        tmp32no1 = (tmp32no1 + 128) >> 8;           // Q(qMagn).
+      } else {
+        // In Q(qMagn+nShifts)
+        tmp32no1 = ((int32_t)magnU16[i] << nShifts) - inst->avgMagnPause[i];
+        tmp32no1 *= ONE_MINUS_GAMMA_PAUSE_Q8;  // Q(8+prevQMagn+nShifts)
+        tmp32no1 = (tmp32no1 + (128 << nShifts)) >> (8 + nShifts);  // Q(qMagn).
+      }
+      tmp32no2 += tmp32no1;  // Q(qMagn)
+    }
+    inst->avgMagnPause[i] = tmp32no2;
+  }  // end of frequency loop
+
+  norm32no1 = WebRtcSpl_NormU32(maxNoiseU32);
+  qNoise = inst->prevQNoise + norm32no1 - 5;
+  // done with step 2: noise update
+
+  // STEP 3: compute dd update of prior snr and post snr based on new noise
+  // estimate
+  nShifts = inst->prevQNoise + 11 - qMagn;
+  for (i = 0; i < inst->magnLen; i++) {
+    // FLOAT code
+    // // post and prior SNR
+    // curNearSnr = 0.0;
+    // if (magn[i] > noise[i])
+    // {
+    // curNearSnr = magn[i] / (noise[i] + 0.0001) - 1.0;
+    // }
+    // // DD estimate is sum of two terms: current estimate and previous
+    // estimate
+    // // directed decision update of snrPrior
+    // snrPrior = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * curNearSnr;
+    // // gain filter
+    // tmpFloat1 = inst->overdrive + snrPrior;
+    // tmpFloat2 = snrPrior / tmpFloat1;
+    // theFilter[i] = tmpFloat2;
+
+    // calculate curNearSnr again, this is necessary because a new noise
+    // estimate has been made since then. for the original
+    curNearSnr = 0;  // Q11
+    if (nShifts < 0) {
+      // This case is equivalent with magn < noise which implies curNearSnr = 0;
+      tmpMagnU32 = (uint32_t)magnU16[i];      // Q(qMagn)
+      tmpNoiseU32 = noiseU32[i] << -nShifts;  // Q(qMagn)
+    } else if (nShifts > 17) {
+      tmpMagnU32 = (uint32_t)magnU16[i] << 17;      // Q(qMagn+17)
+      tmpNoiseU32 = noiseU32[i] >> (nShifts - 17);  // Q(qMagn+17)
+    } else {
+      tmpMagnU32 = (uint32_t)magnU16[i] << nShifts;  // Q(qNoise_prev+11)
+      tmpNoiseU32 = noiseU32[i];                     // Q(qNoise_prev+11)
+    }
+    if (tmpMagnU32 > tmpNoiseU32) {
+      tmpU32no1 = tmpMagnU32 - tmpNoiseU32;  // Q(qCur)
+      norm32no2 = WEBRTC_SPL_MIN(11, WebRtcSpl_NormU32(tmpU32no1));
+      tmpU32no1 <<= norm32no2;                      // Q(qCur+norm32no2)
+      tmpU32no2 = tmpNoiseU32 >> (11 - norm32no2);  // Q(qCur+norm32no2-11)
+      if (tmpU32no2 > 0) {
+        tmpU32no1 /= tmpU32no2;  // Q11
+      }
+      curNearSnr = WEBRTC_SPL_MIN(satMax, tmpU32no1);  // Q11
+    }
+
+    // directed decision update of priorSnr
+    // FLOAT
+    // priorSnr = DD_PR_SNR * prevNearSnr + (1.0-DD_PR_SNR) * curNearSnr;
+
+    tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11);  // Q22
+    tmpU32no2 =
+        WEBRTC_SPL_UMUL_32_16(curNearSnr, ONE_MINUS_DD_PR_SNR_Q11);  // Q22
+    priorSnr = tmpU32no1 + tmpU32no2;                                // Q22
+
+    // gain filter
+    tmpU32no1 = inst->overdrive + ((priorSnr + 8192) >> 14);  // Q8
+    RTC_DCHECK_GT(inst->overdrive, 0);
+    tmpU16no1 = (priorSnr + tmpU32no1 / 2) / tmpU32no1;  // Q14
+    inst->noiseSupFilter[i] = WEBRTC_SPL_SAT(
+        16384, tmpU16no1, inst->denoiseBound);  // 16384 = Q14(1.0) // Q14
+
+    // Weight in the parametric Wiener filter during startup
+    if (inst->blockIndex < END_STARTUP_SHORT) {
+      // Weight the two suppression filters
+      tmpU32no1 = inst->noiseSupFilter[i] * inst->blockIndex;
+      tmpU32no2 = noiseSupFilterTmp[i] * (END_STARTUP_SHORT - inst->blockIndex);
+      tmpU32no1 += tmpU32no2;
+      inst->noiseSupFilter[i] =
+          (uint16_t)WebRtcSpl_DivU32U16(tmpU32no1, END_STARTUP_SHORT);
+    }
+  }  // end of loop over frequencies
+  // done with step3
+
+  // save noise and magnitude spectrum for next frame
+  inst->prevQNoise = qNoise;
+  inst->prevQMagn = qMagn;
+  if (norm32no1 > 5) {
+    for (i = 0; i < inst->magnLen; i++) {
+      inst->prevNoiseU32[i] = noiseU32[i] << (norm32no1 - 5);  // Q(qNoise+11)
+      inst->prevMagnU16[i] = magnU16[i];                       // Q(qMagn)
+    }
+  } else {
+    for (i = 0; i < inst->magnLen; i++) {
+      inst->prevNoiseU32[i] = noiseU32[i] >> (5 - norm32no1);  // Q(qNoise+11)
+      inst->prevMagnU16[i] = magnU16[i];                       // Q(qMagn)
+    }
+  }
+
+  WebRtcNsx_DataSynthesis(inst, outFrame[0]);
+#ifdef NS_FILEDEBUG
+  if (fwrite(outframe, sizeof(short), inst->blockLen10ms, inst->outfile) !=
+      inst->blockLen10ms) {
+    RTC_NOTREACHED();
+  }
+#endif
+
+  // for H band:
+  // only update data buffer, then apply time-domain gain is applied derived
+  // from L band
+  if (num_bands > 1) {
+    // update analysis buffer for H band
+    // append new data to buffer FX
+    for (i = 0; i < num_high_bands; ++i) {
+      memcpy(
+          inst->dataBufHBFX[i], inst->dataBufHBFX[i] + inst->blockLen10ms,
+          (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->dataBufHBFX[i]));
+      memcpy(inst->dataBufHBFX[i] + inst->anaLen - inst->blockLen10ms,
+             speechFrameHB[i],
+             inst->blockLen10ms * sizeof(*inst->dataBufHBFX[i]));
+    }
+    // range for averaging low band quantities for H band gain
+
+    gainTimeDomainHB = 16384;  // 16384 = Q14(1.0)
+    // average speech prob from low band
+    // average filter gain from low band
+    // avg over second half (i.e., 4->8kHz) of freq. spectrum
+    tmpU32no1 = 0;  // Q12
+    tmpU16no1 = 0;  // Q8
+    for (i = inst->anaLen2 - (inst->anaLen2 >> 2); i < inst->anaLen2; i++) {
+      tmpU16no1 += nonSpeechProbFinal[i];                // Q8
+      tmpU32no1 += (uint32_t)(inst->noiseSupFilter[i]);  // Q14
+    }
+    RTC_DCHECK_GE(inst->stages, 7);
+    avgProbSpeechHB = (4096 - (tmpU16no1 >> (inst->stages - 7)));  // Q12
+    avgFilterGainHB = (int16_t)(tmpU32no1 >> (inst->stages - 3));  // Q14
+
+    // // original FLOAT code
+    // // gain based on speech probability:
+    // avg_prob_speech_tt=(float)2.0*avg_prob_speech-(float)1.0;
+    // gain_mod=(float)0.5*((float)1.0+(float)tanh(avg_prob_speech_tt)); //
+    // between 0 and 1
+
+    // gain based on speech probability:
+    // original expression: "0.5 * (1 + tanh(2x-1))"
+    // avgProbSpeechHB has been anyway saturated to a value between 0 and 1 so
+    // the other cases don't have to be dealt with avgProbSpeechHB and gainModHB
+    // are in Q12, 3607 = Q12(0.880615234375) which is a zero point of |0.5 * (1
+    // + tanh(2x-1)) - x| - |0.5 * (1 + tanh(2x-1)) - 0.880615234375| meaning
+    // that from that point the error of approximating the expression with f(x)
+    // = x would be greater than the error of approximating the expression with
+    // f(x) = 0.880615234375 error: "|0.5 * (1 + tanh(2x-1)) - x| from x=0 to
+    // 0.880615234375" ->
+    // http://www.wolframalpha.com/input/?i=|0.5+*+(1+%2B+tanh(2x-1))+-+x|+from+x%3D0+to+0.880615234375
+    // and:  "|0.5 * (1 + tanh(2x-1)) - 0.880615234375| from x=0.880615234375 to
+    // 1" ->
+    // http://www.wolframalpha.com/input/?i=+|0.5+*+(1+%2B+tanh(2x-1))+-+0.880615234375|+from+x%3D0.880615234375+to+1
+    gainModHB = WEBRTC_SPL_MIN(avgProbSpeechHB, 3607);
+
+    // // original FLOAT code
+    // //combine gain with low band gain
+    // if (avg_prob_speech < (float)0.5) {
+    // gain_time_domain_HB=(float)0.5*gain_mod+(float)0.5*avg_filter_gain;
+    // }
+    // else {
+    // gain_time_domain_HB=(float)0.25*gain_mod+(float)0.75*avg_filter_gain;
+    // }
+
+    // combine gain with low band gain
+    if (avgProbSpeechHB < 2048) {
+      // 2048 = Q12(0.5)
+      // the next two lines in float are  "gain_time_domain = 0.5 * gain_mod +
+      // 0.5 * avg_filter_gain"; Q2(0.5) = 2 equals one left shift
+      gainTimeDomainHB = (gainModHB << 1) + (avgFilterGainHB >> 1);  // Q14
+    } else {
+      // "gain_time_domain = 0.25 * gain_mod + 0.75 * agv_filter_gain;"
+      gainTimeDomainHB = (int16_t)((3 * avgFilterGainHB) >> 2);  // 3 = Q2(0.75)
+      gainTimeDomainHB += gainModHB;                             // Q14
+    }
+    // make sure gain is within flooring range
+    gainTimeDomainHB =
+        WEBRTC_SPL_SAT(16384, gainTimeDomainHB,
+                       (int16_t)(inst->denoiseBound));  // 16384 = Q14(1.0)
+
+    // apply gain
+    for (i = 0; i < num_high_bands; ++i) {
+      for (j = 0; j < inst->blockLen10ms; j++) {
+        outFrameHB[i][j] = (int16_t)(
+            (gainTimeDomainHB * inst->dataBufHBFX[i][j]) >> 14);  // Q0
+      }
+    }
+  }  // end of H band gain computation
+}
diff --git a/modules/audio_processing/ns/nsx_core.h b/modules/audio_processing/legacy_ns/nsx_core.h
similarity index 95%
rename from modules/audio_processing/ns/nsx_core.h
rename to modules/audio_processing/legacy_ns/nsx_core.h
index 9e9d142..a3f224a 100644
--- a/modules/audio_processing/ns/nsx_core.h
+++ b/modules/audio_processing/legacy_ns/nsx_core.h
@@ -8,15 +8,15 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_
-#define MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NS_NSX_CORE_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NSX_CORE_H_
 
 #ifdef NS_FILEDEBUG
 #include <stdio.h>
 #endif
 
 #include "common_audio/signal_processing/include/signal_processing_library.h"
-#include "modules/audio_processing/ns/nsx_defines.h"
+#include "modules/audio_processing/legacy_ns/nsx_defines.h"
 
 typedef struct NoiseSuppressionFixedC_ {
   uint32_t fs;
@@ -161,9 +161,9 @@
  *      - outFrame      : Output speech frame for each band
  */
 void WebRtcNsx_ProcessCore(NoiseSuppressionFixedC* inst,
-                           const short* const* inFrame,
+                           const int16_t* const* inFrame,
                            int num_bands,
-                           short* const* outFrame);
+                           int16_t* const* outFrame);
 
 /****************************************************************************
  * Some function pointers, for internal functions shared by ARM NEON and
@@ -258,4 +258,4 @@
 }
 #endif
 
-#endif  // MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_CORE_H_
+#endif  // MODULES_AUDIO_PROCESSING_LEGACY_NS_NSX_CORE_H_
diff --git a/modules/audio_processing/ns/nsx_core_c.c b/modules/audio_processing/legacy_ns/nsx_core_c.c
similarity index 97%
rename from modules/audio_processing/ns/nsx_core_c.c
rename to modules/audio_processing/legacy_ns/nsx_core_c.c
index 162fb19..2b0bb2f 100644
--- a/modules/audio_processing/ns/nsx_core_c.c
+++ b/modules/audio_processing/legacy_ns/nsx_core_c.c
@@ -9,9 +9,9 @@
  */
 
 #include "rtc_base/checks.h"
-#include "modules/audio_processing/ns/noise_suppression_x.h"
-#include "modules/audio_processing/ns/nsx_core.h"
-#include "modules/audio_processing/ns/nsx_defines.h"
+#include "modules/audio_processing/legacy_ns/noise_suppression_x.h"
+#include "modules/audio_processing/legacy_ns/nsx_core.h"
+#include "modules/audio_processing/legacy_ns/nsx_defines.h"
 
 static const int16_t kIndicatorTable[17] = {
   0, 2017, 3809, 5227, 6258, 6963, 7424, 7718,
@@ -257,4 +257,3 @@
     }
   }
 }
-
diff --git a/modules/audio_processing/ns/nsx_core_mips.c b/modules/audio_processing/legacy_ns/nsx_core_mips.c
similarity index 99%
rename from modules/audio_processing/ns/nsx_core_mips.c
rename to modules/audio_processing/legacy_ns/nsx_core_mips.c
index d58a9b2..af4c287 100644
--- a/modules/audio_processing/ns/nsx_core_mips.c
+++ b/modules/audio_processing/legacy_ns/nsx_core_mips.c
@@ -11,8 +11,8 @@
 #include <string.h>
 
 #include "rtc_base/checks.h"
-#include "modules/audio_processing/ns/noise_suppression_x.h"
-#include "modules/audio_processing/ns/nsx_core.h"
+#include "modules/audio_processing/legacy_ns/noise_suppression_x.h"
+#include "modules/audio_processing/legacy_ns/nsx_core.h"
 
 static const int16_t kIndicatorTable[17] = {
   0, 2017, 3809, 5227, 6258, 6963, 7424, 7718,
@@ -999,4 +999,3 @@
     : "memory"
   );
 }
-
diff --git a/modules/audio_processing/ns/nsx_core_neon.c b/modules/audio_processing/legacy_ns/nsx_core_neon.c
similarity index 99%
rename from modules/audio_processing/ns/nsx_core_neon.c
rename to modules/audio_processing/legacy_ns/nsx_core_neon.c
index 64ce99c..244111c 100644
--- a/modules/audio_processing/ns/nsx_core_neon.c
+++ b/modules/audio_processing/legacy_ns/nsx_core_neon.c
@@ -8,7 +8,7 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#include "modules/audio_processing/ns/nsx_core.h"
+#include "modules/audio_processing/legacy_ns/nsx_core.h"
 
 #include <arm_neon.h>
 
diff --git a/modules/audio_processing/ns/nsx_defines.h b/modules/audio_processing/legacy_ns/nsx_defines.h
similarity index 94%
rename from modules/audio_processing/ns/nsx_defines.h
rename to modules/audio_processing/legacy_ns/nsx_defines.h
index dc14dbc..18db311 100644
--- a/modules/audio_processing/ns/nsx_defines.h
+++ b/modules/audio_processing/legacy_ns/nsx_defines.h
@@ -8,8 +8,8 @@
  *  be found in the AUTHORS file in the root of the source tree.
  */
 
-#ifndef MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_
-#define MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NS_NSX_DEFINES_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NSX_DEFINES_H_
 
 #define ANAL_BLOCKL_MAX 256  /* Max analysis block length */
 #define HALF_ANAL_BLOCKL 129 /* Half max analysis block length + 1 */
@@ -71,4 +71,4 @@
 #define GAMMA_NOISE_TRANS_AND_SPEECH_Q8 \
   3 /* ~= Q8(0.01) Update for transition and noise region */
 
-#endif /* MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_NSX_DEFINES_H_ */
+#endif /* MODULES_AUDIO_PROCESSING_LEGACY_NS_NSX_DEFINES_H_ */
diff --git a/modules/audio_processing/legacy_ns/windows_private.h b/modules/audio_processing/legacy_ns/windows_private.h
new file mode 100644
index 0000000..21bb7d4
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/windows_private.h
@@ -0,0 +1,553 @@
+/*
+ *  Copyright (c) 2011 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_LEGACY_NS_WINDOWS_PRIVATE_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_WINDOWS_PRIVATE_H_
+
+// Hanning window for 4ms 16kHz
+static const float kHanning64w128[128] = {
+    0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
+    0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
+    0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
+    0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
+    0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
+    0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
+    0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
+    0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
+    0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
+    0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
+    0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
+    0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
+    0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
+    0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
+    0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
+    0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
+    1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
+    0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f,
+    0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f,
+    0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
+    0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f,
+    0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f,
+    0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
+    0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f,
+    0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f,
+    0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
+    0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f,
+    0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f,
+    0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
+    0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f,
+    0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f,
+    0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f};
+
+// hybrib Hanning & flat window
+static const float kBlocks80w128[128] = {
+    0.00000000f, 0.03271908f, 0.06540313f, 0.09801714f, 0.13052619f,
+    0.16289547f, 0.19509032f, 0.22707626f, 0.25881905f, 0.29028468f,
+    0.32143947f, 0.35225005f, 0.38268343f, 0.41270703f, 0.44228869f,
+    0.47139674f, 0.50000000f, 0.52806785f, 0.55557023f, 0.58247770f,
+    0.60876143f, 0.63439328f, 0.65934582f, 0.68359230f, 0.70710678f,
+    0.72986407f, 0.75183981f, 0.77301045f, 0.79335334f, 0.81284668f,
+    0.83146961f, 0.84920218f, 0.86602540f, 0.88192126f, 0.89687274f,
+    0.91086382f, 0.92387953f, 0.93590593f, 0.94693013f, 0.95694034f,
+    0.96592583f, 0.97387698f, 0.98078528f, 0.98664333f, 0.99144486f,
+    0.99518473f, 0.99785892f, 0.99946459f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 0.99946459f, 0.99785892f, 0.99518473f, 0.99144486f,
+    0.98664333f, 0.98078528f, 0.97387698f, 0.96592583f, 0.95694034f,
+    0.94693013f, 0.93590593f, 0.92387953f, 0.91086382f, 0.89687274f,
+    0.88192126f, 0.86602540f, 0.84920218f, 0.83146961f, 0.81284668f,
+    0.79335334f, 0.77301045f, 0.75183981f, 0.72986407f, 0.70710678f,
+    0.68359230f, 0.65934582f, 0.63439328f, 0.60876143f, 0.58247770f,
+    0.55557023f, 0.52806785f, 0.50000000f, 0.47139674f, 0.44228869f,
+    0.41270703f, 0.38268343f, 0.35225005f, 0.32143947f, 0.29028468f,
+    0.25881905f, 0.22707626f, 0.19509032f, 0.16289547f, 0.13052619f,
+    0.09801714f, 0.06540313f, 0.03271908f};
+
+// hybrib Hanning & flat window
+static const float kBlocks160w256[256] = {
+    0.00000000f, 0.01636173f, 0.03271908f, 0.04906767f, 0.06540313f,
+    0.08172107f, 0.09801714f, 0.11428696f, 0.13052619f, 0.14673047f,
+    0.16289547f, 0.17901686f, 0.19509032f, 0.21111155f, 0.22707626f,
+    0.24298018f, 0.25881905f, 0.27458862f, 0.29028468f, 0.30590302f,
+    0.32143947f, 0.33688985f, 0.35225005f, 0.36751594f, 0.38268343f,
+    0.39774847f, 0.41270703f, 0.42755509f, 0.44228869f, 0.45690388f,
+    0.47139674f, 0.48576339f, 0.50000000f, 0.51410274f, 0.52806785f,
+    0.54189158f, 0.55557023f, 0.56910015f, 0.58247770f, 0.59569930f,
+    0.60876143f, 0.62166057f, 0.63439328f, 0.64695615f, 0.65934582f,
+    0.67155895f, 0.68359230f, 0.69544264f, 0.70710678f, 0.71858162f,
+    0.72986407f, 0.74095113f, 0.75183981f, 0.76252720f, 0.77301045f,
+    0.78328675f, 0.79335334f, 0.80320753f, 0.81284668f, 0.82226822f,
+    0.83146961f, 0.84044840f, 0.84920218f, 0.85772861f, 0.86602540f,
+    0.87409034f, 0.88192126f, 0.88951608f, 0.89687274f, 0.90398929f,
+    0.91086382f, 0.91749450f, 0.92387953f, 0.93001722f, 0.93590593f,
+    0.94154407f, 0.94693013f, 0.95206268f, 0.95694034f, 0.96156180f,
+    0.96592583f, 0.97003125f, 0.97387698f, 0.97746197f, 0.98078528f,
+    0.98384601f, 0.98664333f, 0.98917651f, 0.99144486f, 0.99344778f,
+    0.99518473f, 0.99665524f, 0.99785892f, 0.99879546f, 0.99946459f,
+    0.99986614f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 0.99986614f, 0.99946459f, 0.99879546f, 0.99785892f,
+    0.99665524f, 0.99518473f, 0.99344778f, 0.99144486f, 0.98917651f,
+    0.98664333f, 0.98384601f, 0.98078528f, 0.97746197f, 0.97387698f,
+    0.97003125f, 0.96592583f, 0.96156180f, 0.95694034f, 0.95206268f,
+    0.94693013f, 0.94154407f, 0.93590593f, 0.93001722f, 0.92387953f,
+    0.91749450f, 0.91086382f, 0.90398929f, 0.89687274f, 0.88951608f,
+    0.88192126f, 0.87409034f, 0.86602540f, 0.85772861f, 0.84920218f,
+    0.84044840f, 0.83146961f, 0.82226822f, 0.81284668f, 0.80320753f,
+    0.79335334f, 0.78328675f, 0.77301045f, 0.76252720f, 0.75183981f,
+    0.74095113f, 0.72986407f, 0.71858162f, 0.70710678f, 0.69544264f,
+    0.68359230f, 0.67155895f, 0.65934582f, 0.64695615f, 0.63439328f,
+    0.62166057f, 0.60876143f, 0.59569930f, 0.58247770f, 0.56910015f,
+    0.55557023f, 0.54189158f, 0.52806785f, 0.51410274f, 0.50000000f,
+    0.48576339f, 0.47139674f, 0.45690388f, 0.44228869f, 0.42755509f,
+    0.41270703f, 0.39774847f, 0.38268343f, 0.36751594f, 0.35225005f,
+    0.33688985f, 0.32143947f, 0.30590302f, 0.29028468f, 0.27458862f,
+    0.25881905f, 0.24298018f, 0.22707626f, 0.21111155f, 0.19509032f,
+    0.17901686f, 0.16289547f, 0.14673047f, 0.13052619f, 0.11428696f,
+    0.09801714f, 0.08172107f, 0.06540313f, 0.04906767f, 0.03271908f,
+    0.01636173f};
+
+// hybrib Hanning & flat window: for 20ms
+static const float kBlocks320w512[512] = {
+    0.00000000f, 0.00818114f, 0.01636173f, 0.02454123f, 0.03271908f,
+    0.04089475f, 0.04906767f, 0.05723732f, 0.06540313f, 0.07356456f,
+    0.08172107f, 0.08987211f, 0.09801714f, 0.10615561f, 0.11428696f,
+    0.12241068f, 0.13052619f, 0.13863297f, 0.14673047f, 0.15481816f,
+    0.16289547f, 0.17096189f, 0.17901686f, 0.18705985f, 0.19509032f,
+    0.20310773f, 0.21111155f, 0.21910124f, 0.22707626f, 0.23503609f,
+    0.24298018f, 0.25090801f, 0.25881905f, 0.26671276f, 0.27458862f,
+    0.28244610f, 0.29028468f, 0.29810383f, 0.30590302f, 0.31368174f,
+    0.32143947f, 0.32917568f, 0.33688985f, 0.34458148f, 0.35225005f,
+    0.35989504f, 0.36751594f, 0.37511224f, 0.38268343f, 0.39022901f,
+    0.39774847f, 0.40524131f, 0.41270703f, 0.42014512f, 0.42755509f,
+    0.43493645f, 0.44228869f, 0.44961133f, 0.45690388f, 0.46416584f,
+    0.47139674f, 0.47859608f, 0.48576339f, 0.49289819f, 0.50000000f,
+    0.50706834f, 0.51410274f, 0.52110274f, 0.52806785f, 0.53499762f,
+    0.54189158f, 0.54874927f, 0.55557023f, 0.56235401f, 0.56910015f,
+    0.57580819f, 0.58247770f, 0.58910822f, 0.59569930f, 0.60225052f,
+    0.60876143f, 0.61523159f, 0.62166057f, 0.62804795f, 0.63439328f,
+    0.64069616f, 0.64695615f, 0.65317284f, 0.65934582f, 0.66547466f,
+    0.67155895f, 0.67759830f, 0.68359230f, 0.68954054f, 0.69544264f,
+    0.70129818f, 0.70710678f, 0.71286806f, 0.71858162f, 0.72424708f,
+    0.72986407f, 0.73543221f, 0.74095113f, 0.74642045f, 0.75183981f,
+    0.75720885f, 0.76252720f, 0.76779452f, 0.77301045f, 0.77817464f,
+    0.78328675f, 0.78834643f, 0.79335334f, 0.79830715f, 0.80320753f,
+    0.80805415f, 0.81284668f, 0.81758481f, 0.82226822f, 0.82689659f,
+    0.83146961f, 0.83598698f, 0.84044840f, 0.84485357f, 0.84920218f,
+    0.85349396f, 0.85772861f, 0.86190585f, 0.86602540f, 0.87008699f,
+    0.87409034f, 0.87803519f, 0.88192126f, 0.88574831f, 0.88951608f,
+    0.89322430f, 0.89687274f, 0.90046115f, 0.90398929f, 0.90745693f,
+    0.91086382f, 0.91420976f, 0.91749450f, 0.92071783f, 0.92387953f,
+    0.92697940f, 0.93001722f, 0.93299280f, 0.93590593f, 0.93875641f,
+    0.94154407f, 0.94426870f, 0.94693013f, 0.94952818f, 0.95206268f,
+    0.95453345f, 0.95694034f, 0.95928317f, 0.96156180f, 0.96377607f,
+    0.96592583f, 0.96801094f, 0.97003125f, 0.97198664f, 0.97387698f,
+    0.97570213f, 0.97746197f, 0.97915640f, 0.98078528f, 0.98234852f,
+    0.98384601f, 0.98527764f, 0.98664333f, 0.98794298f, 0.98917651f,
+    0.99034383f, 0.99144486f, 0.99247953f, 0.99344778f, 0.99434953f,
+    0.99518473f, 0.99595331f, 0.99665524f, 0.99729046f, 0.99785892f,
+    0.99836060f, 0.99879546f, 0.99916346f, 0.99946459f, 0.99969882f,
+    0.99986614f, 0.99996653f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f, 1.00000000f,
+    1.00000000f, 0.99996653f, 0.99986614f, 0.99969882f, 0.99946459f,
+    0.99916346f, 0.99879546f, 0.99836060f, 0.99785892f, 0.99729046f,
+    0.99665524f, 0.99595331f, 0.99518473f, 0.99434953f, 0.99344778f,
+    0.99247953f, 0.99144486f, 0.99034383f, 0.98917651f, 0.98794298f,
+    0.98664333f, 0.98527764f, 0.98384601f, 0.98234852f, 0.98078528f,
+    0.97915640f, 0.97746197f, 0.97570213f, 0.97387698f, 0.97198664f,
+    0.97003125f, 0.96801094f, 0.96592583f, 0.96377607f, 0.96156180f,
+    0.95928317f, 0.95694034f, 0.95453345f, 0.95206268f, 0.94952818f,
+    0.94693013f, 0.94426870f, 0.94154407f, 0.93875641f, 0.93590593f,
+    0.93299280f, 0.93001722f, 0.92697940f, 0.92387953f, 0.92071783f,
+    0.91749450f, 0.91420976f, 0.91086382f, 0.90745693f, 0.90398929f,
+    0.90046115f, 0.89687274f, 0.89322430f, 0.88951608f, 0.88574831f,
+    0.88192126f, 0.87803519f, 0.87409034f, 0.87008699f, 0.86602540f,
+    0.86190585f, 0.85772861f, 0.85349396f, 0.84920218f, 0.84485357f,
+    0.84044840f, 0.83598698f, 0.83146961f, 0.82689659f, 0.82226822f,
+    0.81758481f, 0.81284668f, 0.80805415f, 0.80320753f, 0.79830715f,
+    0.79335334f, 0.78834643f, 0.78328675f, 0.77817464f, 0.77301045f,
+    0.76779452f, 0.76252720f, 0.75720885f, 0.75183981f, 0.74642045f,
+    0.74095113f, 0.73543221f, 0.72986407f, 0.72424708f, 0.71858162f,
+    0.71286806f, 0.70710678f, 0.70129818f, 0.69544264f, 0.68954054f,
+    0.68359230f, 0.67759830f, 0.67155895f, 0.66547466f, 0.65934582f,
+    0.65317284f, 0.64695615f, 0.64069616f, 0.63439328f, 0.62804795f,
+    0.62166057f, 0.61523159f, 0.60876143f, 0.60225052f, 0.59569930f,
+    0.58910822f, 0.58247770f, 0.57580819f, 0.56910015f, 0.56235401f,
+    0.55557023f, 0.54874927f, 0.54189158f, 0.53499762f, 0.52806785f,
+    0.52110274f, 0.51410274f, 0.50706834f, 0.50000000f, 0.49289819f,
+    0.48576339f, 0.47859608f, 0.47139674f, 0.46416584f, 0.45690388f,
+    0.44961133f, 0.44228869f, 0.43493645f, 0.42755509f, 0.42014512f,
+    0.41270703f, 0.40524131f, 0.39774847f, 0.39022901f, 0.38268343f,
+    0.37511224f, 0.36751594f, 0.35989504f, 0.35225005f, 0.34458148f,
+    0.33688985f, 0.32917568f, 0.32143947f, 0.31368174f, 0.30590302f,
+    0.29810383f, 0.29028468f, 0.28244610f, 0.27458862f, 0.26671276f,
+    0.25881905f, 0.25090801f, 0.24298018f, 0.23503609f, 0.22707626f,
+    0.21910124f, 0.21111155f, 0.20310773f, 0.19509032f, 0.18705985f,
+    0.17901686f, 0.17096189f, 0.16289547f, 0.15481816f, 0.14673047f,
+    0.13863297f, 0.13052619f, 0.12241068f, 0.11428696f, 0.10615561f,
+    0.09801714f, 0.08987211f, 0.08172107f, 0.07356456f, 0.06540313f,
+    0.05723732f, 0.04906767f, 0.04089475f, 0.03271908f, 0.02454123f,
+    0.01636173f, 0.00818114f};
+
+// Hanning window: for 15ms at 16kHz with symmetric zeros
+static const float kBlocks240w512[512] = {
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00654494f, 0.01308960f, 0.01963369f,
+    0.02617695f, 0.03271908f, 0.03925982f, 0.04579887f, 0.05233596f,
+    0.05887080f, 0.06540313f, 0.07193266f, 0.07845910f, 0.08498218f,
+    0.09150162f, 0.09801714f, 0.10452846f, 0.11103531f, 0.11753740f,
+    0.12403446f, 0.13052620f, 0.13701233f, 0.14349262f, 0.14996676f,
+    0.15643448f, 0.16289547f, 0.16934951f, 0.17579629f, 0.18223552f,
+    0.18866697f, 0.19509032f, 0.20150533f, 0.20791170f, 0.21430916f,
+    0.22069745f, 0.22707628f, 0.23344538f, 0.23980446f, 0.24615330f,
+    0.25249159f, 0.25881904f, 0.26513544f, 0.27144045f, 0.27773386f,
+    0.28401536f, 0.29028466f, 0.29654160f, 0.30278578f, 0.30901700f,
+    0.31523499f, 0.32143945f, 0.32763019f, 0.33380687f, 0.33996925f,
+    0.34611708f, 0.35225007f, 0.35836795f, 0.36447051f, 0.37055743f,
+    0.37662852f, 0.38268346f, 0.38872197f, 0.39474389f, 0.40074885f,
+    0.40673664f, 0.41270703f, 0.41865975f, 0.42459452f, 0.43051112f,
+    0.43640924f, 0.44228873f, 0.44814920f, 0.45399052f, 0.45981237f,
+    0.46561453f, 0.47139674f, 0.47715878f, 0.48290035f, 0.48862126f,
+    0.49432120f, 0.50000000f, 0.50565743f, 0.51129311f, 0.51690692f,
+    0.52249855f, 0.52806789f, 0.53361452f, 0.53913832f, 0.54463905f,
+    0.55011642f, 0.55557024f, 0.56100029f, 0.56640625f, 0.57178795f,
+    0.57714522f, 0.58247769f, 0.58778524f, 0.59306765f, 0.59832460f,
+    0.60355598f, 0.60876143f, 0.61394083f, 0.61909395f, 0.62422055f,
+    0.62932038f, 0.63439333f, 0.63943899f, 0.64445734f, 0.64944810f,
+    0.65441096f, 0.65934587f, 0.66425246f, 0.66913062f, 0.67398012f,
+    0.67880076f, 0.68359232f, 0.68835455f, 0.69308740f, 0.69779050f,
+    0.70246369f, 0.70710677f, 0.71171963f, 0.71630198f, 0.72085363f,
+    0.72537440f, 0.72986406f, 0.73432255f, 0.73874950f, 0.74314487f,
+    0.74750835f, 0.75183982f, 0.75613910f, 0.76040596f, 0.76464027f,
+    0.76884186f, 0.77301043f, 0.77714598f, 0.78124821f, 0.78531694f,
+    0.78935206f, 0.79335338f, 0.79732066f, 0.80125386f, 0.80515265f,
+    0.80901700f, 0.81284672f, 0.81664157f, 0.82040149f, 0.82412618f,
+    0.82781565f, 0.83146966f, 0.83508795f, 0.83867061f, 0.84221727f,
+    0.84572780f, 0.84920216f, 0.85264021f, 0.85604161f, 0.85940641f,
+    0.86273444f, 0.86602545f, 0.86927933f, 0.87249607f, 0.87567532f,
+    0.87881714f, 0.88192129f, 0.88498765f, 0.88801610f, 0.89100653f,
+    0.89395881f, 0.89687276f, 0.89974827f, 0.90258533f, 0.90538365f,
+    0.90814316f, 0.91086388f, 0.91354549f, 0.91618794f, 0.91879123f,
+    0.92135513f, 0.92387950f, 0.92636442f, 0.92880958f, 0.93121493f,
+    0.93358046f, 0.93590593f, 0.93819135f, 0.94043654f, 0.94264150f,
+    0.94480604f, 0.94693011f, 0.94901365f, 0.95105654f, 0.95305866f,
+    0.95501995f, 0.95694035f, 0.95881975f, 0.96065807f, 0.96245527f,
+    0.96421117f, 0.96592581f, 0.96759909f, 0.96923089f, 0.97082120f,
+    0.97236991f, 0.97387701f, 0.97534233f, 0.97676587f, 0.97814763f,
+    0.97948742f, 0.98078531f, 0.98204112f, 0.98325491f, 0.98442656f,
+    0.98555607f, 0.98664331f, 0.98768836f, 0.98869103f, 0.98965138f,
+    0.99056935f, 0.99144489f, 0.99227792f, 0.99306846f, 0.99381649f,
+    0.99452192f, 0.99518472f, 0.99580491f, 0.99638247f, 0.99691731f,
+    0.99740952f, 0.99785894f, 0.99826562f, 0.99862951f, 0.99895066f,
+    0.99922901f, 0.99946457f, 0.99965733f, 0.99980724f, 0.99991435f,
+    0.99997860f, 1.00000000f, 0.99997860f, 0.99991435f, 0.99980724f,
+    0.99965733f, 0.99946457f, 0.99922901f, 0.99895066f, 0.99862951f,
+    0.99826562f, 0.99785894f, 0.99740946f, 0.99691731f, 0.99638247f,
+    0.99580491f, 0.99518472f, 0.99452192f, 0.99381644f, 0.99306846f,
+    0.99227792f, 0.99144489f, 0.99056935f, 0.98965138f, 0.98869103f,
+    0.98768836f, 0.98664331f, 0.98555607f, 0.98442656f, 0.98325491f,
+    0.98204112f, 0.98078525f, 0.97948742f, 0.97814757f, 0.97676587f,
+    0.97534227f, 0.97387695f, 0.97236991f, 0.97082120f, 0.96923089f,
+    0.96759909f, 0.96592581f, 0.96421117f, 0.96245521f, 0.96065807f,
+    0.95881969f, 0.95694029f, 0.95501995f, 0.95305860f, 0.95105648f,
+    0.94901365f, 0.94693011f, 0.94480604f, 0.94264150f, 0.94043654f,
+    0.93819129f, 0.93590593f, 0.93358046f, 0.93121493f, 0.92880952f,
+    0.92636436f, 0.92387950f, 0.92135507f, 0.91879123f, 0.91618794f,
+    0.91354543f, 0.91086382f, 0.90814310f, 0.90538365f, 0.90258527f,
+    0.89974827f, 0.89687276f, 0.89395875f, 0.89100647f, 0.88801610f,
+    0.88498759f, 0.88192123f, 0.87881714f, 0.87567532f, 0.87249595f,
+    0.86927933f, 0.86602539f, 0.86273432f, 0.85940641f, 0.85604161f,
+    0.85264009f, 0.84920216f, 0.84572780f, 0.84221715f, 0.83867055f,
+    0.83508795f, 0.83146954f, 0.82781565f, 0.82412612f, 0.82040137f,
+    0.81664157f, 0.81284660f, 0.80901700f, 0.80515265f, 0.80125374f,
+    0.79732066f, 0.79335332f, 0.78935200f, 0.78531694f, 0.78124815f,
+    0.77714586f, 0.77301049f, 0.76884180f, 0.76464021f, 0.76040596f,
+    0.75613904f, 0.75183970f, 0.74750835f, 0.74314481f, 0.73874938f,
+    0.73432249f, 0.72986400f, 0.72537428f, 0.72085363f, 0.71630186f,
+    0.71171951f, 0.70710677f, 0.70246363f, 0.69779032f, 0.69308734f,
+    0.68835449f, 0.68359220f, 0.67880070f, 0.67398006f, 0.66913044f,
+    0.66425240f, 0.65934575f, 0.65441096f, 0.64944804f, 0.64445722f,
+    0.63943905f, 0.63439327f, 0.62932026f, 0.62422055f, 0.61909389f,
+    0.61394072f, 0.60876143f, 0.60355592f, 0.59832448f, 0.59306765f,
+    0.58778518f, 0.58247757f, 0.57714522f, 0.57178789f, 0.56640613f,
+    0.56100023f, 0.55557019f, 0.55011630f, 0.54463905f, 0.53913826f,
+    0.53361434f, 0.52806783f, 0.52249849f, 0.51690674f, 0.51129305f,
+    0.50565726f, 0.50000006f, 0.49432117f, 0.48862115f, 0.48290038f,
+    0.47715873f, 0.47139663f, 0.46561456f, 0.45981231f, 0.45399037f,
+    0.44814920f, 0.44228864f, 0.43640912f, 0.43051112f, 0.42459446f,
+    0.41865960f, 0.41270703f, 0.40673658f, 0.40074870f, 0.39474386f,
+    0.38872188f, 0.38268328f, 0.37662849f, 0.37055734f, 0.36447033f,
+    0.35836792f, 0.35224995f, 0.34611690f, 0.33996922f, 0.33380675f,
+    0.32763001f, 0.32143945f, 0.31523487f, 0.30901679f, 0.30278572f,
+    0.29654145f, 0.29028472f, 0.28401530f, 0.27773371f, 0.27144048f,
+    0.26513538f, 0.25881892f, 0.25249159f, 0.24615324f, 0.23980433f,
+    0.23344538f, 0.22707619f, 0.22069728f, 0.21430916f, 0.20791161f,
+    0.20150517f, 0.19509031f, 0.18866688f, 0.18223536f, 0.17579627f,
+    0.16934940f, 0.16289529f, 0.15643445f, 0.14996666f, 0.14349243f,
+    0.13701232f, 0.13052608f, 0.12403426f, 0.11753736f, 0.11103519f,
+    0.10452849f, 0.09801710f, 0.09150149f, 0.08498220f, 0.07845904f,
+    0.07193252f, 0.06540315f, 0.05887074f, 0.05233581f, 0.04579888f,
+    0.03925974f, 0.03271893f, 0.02617695f, 0.01963361f, 0.01308943f,
+    0.00654493f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f};
+
+// Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz
+static const float kBlocks480w1024[1024] = {
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00327249f, 0.00654494f,
+    0.00981732f, 0.01308960f, 0.01636173f, 0.01963369f, 0.02290544f,
+    0.02617695f, 0.02944817f, 0.03271908f, 0.03598964f, 0.03925982f,
+    0.04252957f, 0.04579887f, 0.04906768f, 0.05233596f, 0.05560368f,
+    0.05887080f, 0.06213730f, 0.06540313f, 0.06866825f, 0.07193266f,
+    0.07519628f, 0.07845910f, 0.08172107f, 0.08498218f, 0.08824237f,
+    0.09150162f, 0.09475989f, 0.09801714f, 0.10127335f, 0.10452846f,
+    0.10778246f, 0.11103531f, 0.11428697f, 0.11753740f, 0.12078657f,
+    0.12403446f, 0.12728101f, 0.13052620f, 0.13376999f, 0.13701233f,
+    0.14025325f, 0.14349262f, 0.14673047f, 0.14996676f, 0.15320145f,
+    0.15643448f, 0.15966582f, 0.16289547f, 0.16612339f, 0.16934951f,
+    0.17257382f, 0.17579629f, 0.17901687f, 0.18223552f, 0.18545224f,
+    0.18866697f, 0.19187967f, 0.19509032f, 0.19829889f, 0.20150533f,
+    0.20470962f, 0.20791170f, 0.21111156f, 0.21430916f, 0.21750447f,
+    0.22069745f, 0.22388805f, 0.22707628f, 0.23026206f, 0.23344538f,
+    0.23662618f, 0.23980446f, 0.24298020f, 0.24615330f, 0.24932377f,
+    0.25249159f, 0.25565669f, 0.25881904f, 0.26197866f, 0.26513544f,
+    0.26828939f, 0.27144045f, 0.27458861f, 0.27773386f, 0.28087610f,
+    0.28401536f, 0.28715158f, 0.29028466f, 0.29341471f, 0.29654160f,
+    0.29966527f, 0.30278578f, 0.30590302f, 0.30901700f, 0.31212768f,
+    0.31523499f, 0.31833893f, 0.32143945f, 0.32453656f, 0.32763019f,
+    0.33072028f, 0.33380687f, 0.33688986f, 0.33996925f, 0.34304500f,
+    0.34611708f, 0.34918544f, 0.35225007f, 0.35531089f, 0.35836795f,
+    0.36142117f, 0.36447051f, 0.36751595f, 0.37055743f, 0.37359497f,
+    0.37662852f, 0.37965801f, 0.38268346f, 0.38570479f, 0.38872197f,
+    0.39173502f, 0.39474389f, 0.39774847f, 0.40074885f, 0.40374491f,
+    0.40673664f, 0.40972406f, 0.41270703f, 0.41568562f, 0.41865975f,
+    0.42162940f, 0.42459452f, 0.42755508f, 0.43051112f, 0.43346250f,
+    0.43640924f, 0.43935132f, 0.44228873f, 0.44522133f, 0.44814920f,
+    0.45107228f, 0.45399052f, 0.45690390f, 0.45981237f, 0.46271592f,
+    0.46561453f, 0.46850815f, 0.47139674f, 0.47428030f, 0.47715878f,
+    0.48003215f, 0.48290035f, 0.48576337f, 0.48862126f, 0.49147385f,
+    0.49432120f, 0.49716330f, 0.50000000f, 0.50283140f, 0.50565743f,
+    0.50847799f, 0.51129311f, 0.51410276f, 0.51690692f, 0.51970553f,
+    0.52249855f, 0.52528602f, 0.52806789f, 0.53084403f, 0.53361452f,
+    0.53637928f, 0.53913832f, 0.54189163f, 0.54463905f, 0.54738063f,
+    0.55011642f, 0.55284631f, 0.55557024f, 0.55828828f, 0.56100029f,
+    0.56370628f, 0.56640625f, 0.56910014f, 0.57178795f, 0.57446963f,
+    0.57714522f, 0.57981455f, 0.58247769f, 0.58513463f, 0.58778524f,
+    0.59042960f, 0.59306765f, 0.59569931f, 0.59832460f, 0.60094351f,
+    0.60355598f, 0.60616195f, 0.60876143f, 0.61135441f, 0.61394083f,
+    0.61652070f, 0.61909395f, 0.62166059f, 0.62422055f, 0.62677383f,
+    0.62932038f, 0.63186020f, 0.63439333f, 0.63691956f, 0.63943899f,
+    0.64195162f, 0.64445734f, 0.64695615f, 0.64944810f, 0.65193301f,
+    0.65441096f, 0.65688187f, 0.65934587f, 0.66180271f, 0.66425246f,
+    0.66669512f, 0.66913062f, 0.67155898f, 0.67398012f, 0.67639405f,
+    0.67880076f, 0.68120021f, 0.68359232f, 0.68597710f, 0.68835455f,
+    0.69072467f, 0.69308740f, 0.69544262f, 0.69779050f, 0.70013082f,
+    0.70246369f, 0.70478904f, 0.70710677f, 0.70941699f, 0.71171963f,
+    0.71401459f, 0.71630198f, 0.71858168f, 0.72085363f, 0.72311789f,
+    0.72537440f, 0.72762316f, 0.72986406f, 0.73209721f, 0.73432255f,
+    0.73653996f, 0.73874950f, 0.74095118f, 0.74314487f, 0.74533057f,
+    0.74750835f, 0.74967808f, 0.75183982f, 0.75399351f, 0.75613910f,
+    0.75827658f, 0.76040596f, 0.76252723f, 0.76464027f, 0.76674515f,
+    0.76884186f, 0.77093029f, 0.77301043f, 0.77508241f, 0.77714598f,
+    0.77920127f, 0.78124821f, 0.78328675f, 0.78531694f, 0.78733873f,
+    0.78935206f, 0.79135692f, 0.79335338f, 0.79534125f, 0.79732066f,
+    0.79929149f, 0.80125386f, 0.80320752f, 0.80515265f, 0.80708915f,
+    0.80901700f, 0.81093621f, 0.81284672f, 0.81474853f, 0.81664157f,
+    0.81852591f, 0.82040149f, 0.82226825f, 0.82412618f, 0.82597536f,
+    0.82781565f, 0.82964706f, 0.83146966f, 0.83328325f, 0.83508795f,
+    0.83688378f, 0.83867061f, 0.84044838f, 0.84221727f, 0.84397703f,
+    0.84572780f, 0.84746957f, 0.84920216f, 0.85092574f, 0.85264021f,
+    0.85434544f, 0.85604161f, 0.85772866f, 0.85940641f, 0.86107504f,
+    0.86273444f, 0.86438453f, 0.86602545f, 0.86765707f, 0.86927933f,
+    0.87089235f, 0.87249607f, 0.87409031f, 0.87567532f, 0.87725097f,
+    0.87881714f, 0.88037390f, 0.88192129f, 0.88345921f, 0.88498765f,
+    0.88650668f, 0.88801610f, 0.88951612f, 0.89100653f, 0.89248741f,
+    0.89395881f, 0.89542055f, 0.89687276f, 0.89831537f, 0.89974827f,
+    0.90117162f, 0.90258533f, 0.90398932f, 0.90538365f, 0.90676826f,
+    0.90814316f, 0.90950841f, 0.91086388f, 0.91220951f, 0.91354549f,
+    0.91487163f, 0.91618794f, 0.91749454f, 0.91879123f, 0.92007810f,
+    0.92135513f, 0.92262226f, 0.92387950f, 0.92512691f, 0.92636442f,
+    0.92759192f, 0.92880958f, 0.93001723f, 0.93121493f, 0.93240267f,
+    0.93358046f, 0.93474817f, 0.93590593f, 0.93705362f, 0.93819135f,
+    0.93931901f, 0.94043654f, 0.94154406f, 0.94264150f, 0.94372880f,
+    0.94480604f, 0.94587320f, 0.94693011f, 0.94797695f, 0.94901365f,
+    0.95004016f, 0.95105654f, 0.95206273f, 0.95305866f, 0.95404440f,
+    0.95501995f, 0.95598525f, 0.95694035f, 0.95788521f, 0.95881975f,
+    0.95974404f, 0.96065807f, 0.96156180f, 0.96245527f, 0.96333838f,
+    0.96421117f, 0.96507370f, 0.96592581f, 0.96676767f, 0.96759909f,
+    0.96842021f, 0.96923089f, 0.97003126f, 0.97082120f, 0.97160077f,
+    0.97236991f, 0.97312868f, 0.97387701f, 0.97461486f, 0.97534233f,
+    0.97605932f, 0.97676587f, 0.97746199f, 0.97814763f, 0.97882277f,
+    0.97948742f, 0.98014158f, 0.98078531f, 0.98141843f, 0.98204112f,
+    0.98265332f, 0.98325491f, 0.98384601f, 0.98442656f, 0.98499662f,
+    0.98555607f, 0.98610497f, 0.98664331f, 0.98717111f, 0.98768836f,
+    0.98819500f, 0.98869103f, 0.98917651f, 0.98965138f, 0.99011570f,
+    0.99056935f, 0.99101239f, 0.99144489f, 0.99186671f, 0.99227792f,
+    0.99267852f, 0.99306846f, 0.99344778f, 0.99381649f, 0.99417448f,
+    0.99452192f, 0.99485862f, 0.99518472f, 0.99550015f, 0.99580491f,
+    0.99609905f, 0.99638247f, 0.99665523f, 0.99691731f, 0.99716878f,
+    0.99740952f, 0.99763954f, 0.99785894f, 0.99806762f, 0.99826562f,
+    0.99845290f, 0.99862951f, 0.99879545f, 0.99895066f, 0.99909520f,
+    0.99922901f, 0.99935216f, 0.99946457f, 0.99956632f, 0.99965733f,
+    0.99973762f, 0.99980724f, 0.99986613f, 0.99991435f, 0.99995178f,
+    0.99997860f, 0.99999464f, 1.00000000f, 0.99999464f, 0.99997860f,
+    0.99995178f, 0.99991435f, 0.99986613f, 0.99980724f, 0.99973762f,
+    0.99965733f, 0.99956632f, 0.99946457f, 0.99935216f, 0.99922901f,
+    0.99909520f, 0.99895066f, 0.99879545f, 0.99862951f, 0.99845290f,
+    0.99826562f, 0.99806762f, 0.99785894f, 0.99763954f, 0.99740946f,
+    0.99716872f, 0.99691731f, 0.99665523f, 0.99638247f, 0.99609905f,
+    0.99580491f, 0.99550015f, 0.99518472f, 0.99485862f, 0.99452192f,
+    0.99417448f, 0.99381644f, 0.99344778f, 0.99306846f, 0.99267852f,
+    0.99227792f, 0.99186671f, 0.99144489f, 0.99101239f, 0.99056935f,
+    0.99011564f, 0.98965138f, 0.98917651f, 0.98869103f, 0.98819494f,
+    0.98768836f, 0.98717111f, 0.98664331f, 0.98610497f, 0.98555607f,
+    0.98499656f, 0.98442656f, 0.98384601f, 0.98325491f, 0.98265326f,
+    0.98204112f, 0.98141843f, 0.98078525f, 0.98014158f, 0.97948742f,
+    0.97882277f, 0.97814757f, 0.97746193f, 0.97676587f, 0.97605932f,
+    0.97534227f, 0.97461486f, 0.97387695f, 0.97312862f, 0.97236991f,
+    0.97160077f, 0.97082120f, 0.97003126f, 0.96923089f, 0.96842015f,
+    0.96759909f, 0.96676761f, 0.96592581f, 0.96507365f, 0.96421117f,
+    0.96333838f, 0.96245521f, 0.96156180f, 0.96065807f, 0.95974404f,
+    0.95881969f, 0.95788515f, 0.95694029f, 0.95598525f, 0.95501995f,
+    0.95404440f, 0.95305860f, 0.95206267f, 0.95105648f, 0.95004016f,
+    0.94901365f, 0.94797695f, 0.94693011f, 0.94587314f, 0.94480604f,
+    0.94372880f, 0.94264150f, 0.94154406f, 0.94043654f, 0.93931895f,
+    0.93819129f, 0.93705362f, 0.93590593f, 0.93474817f, 0.93358046f,
+    0.93240267f, 0.93121493f, 0.93001723f, 0.92880952f, 0.92759192f,
+    0.92636436f, 0.92512691f, 0.92387950f, 0.92262226f, 0.92135507f,
+    0.92007804f, 0.91879123f, 0.91749448f, 0.91618794f, 0.91487157f,
+    0.91354543f, 0.91220951f, 0.91086382f, 0.90950835f, 0.90814310f,
+    0.90676820f, 0.90538365f, 0.90398932f, 0.90258527f, 0.90117157f,
+    0.89974827f, 0.89831525f, 0.89687276f, 0.89542055f, 0.89395875f,
+    0.89248741f, 0.89100647f, 0.88951600f, 0.88801610f, 0.88650662f,
+    0.88498759f, 0.88345915f, 0.88192123f, 0.88037384f, 0.87881714f,
+    0.87725091f, 0.87567532f, 0.87409031f, 0.87249595f, 0.87089223f,
+    0.86927933f, 0.86765701f, 0.86602539f, 0.86438447f, 0.86273432f,
+    0.86107504f, 0.85940641f, 0.85772860f, 0.85604161f, 0.85434544f,
+    0.85264009f, 0.85092574f, 0.84920216f, 0.84746951f, 0.84572780f,
+    0.84397697f, 0.84221715f, 0.84044844f, 0.83867055f, 0.83688372f,
+    0.83508795f, 0.83328319f, 0.83146954f, 0.82964706f, 0.82781565f,
+    0.82597530f, 0.82412612f, 0.82226813f, 0.82040137f, 0.81852591f,
+    0.81664157f, 0.81474847f, 0.81284660f, 0.81093609f, 0.80901700f,
+    0.80708915f, 0.80515265f, 0.80320752f, 0.80125374f, 0.79929143f,
+    0.79732066f, 0.79534125f, 0.79335332f, 0.79135686f, 0.78935200f,
+    0.78733861f, 0.78531694f, 0.78328675f, 0.78124815f, 0.77920121f,
+    0.77714586f, 0.77508223f, 0.77301049f, 0.77093029f, 0.76884180f,
+    0.76674509f, 0.76464021f, 0.76252711f, 0.76040596f, 0.75827658f,
+    0.75613904f, 0.75399339f, 0.75183970f, 0.74967796f, 0.74750835f,
+    0.74533057f, 0.74314481f, 0.74095106f, 0.73874938f, 0.73653996f,
+    0.73432249f, 0.73209721f, 0.72986400f, 0.72762305f, 0.72537428f,
+    0.72311789f, 0.72085363f, 0.71858162f, 0.71630186f, 0.71401453f,
+    0.71171951f, 0.70941705f, 0.70710677f, 0.70478898f, 0.70246363f,
+    0.70013070f, 0.69779032f, 0.69544268f, 0.69308734f, 0.69072461f,
+    0.68835449f, 0.68597704f, 0.68359220f, 0.68120021f, 0.67880070f,
+    0.67639399f, 0.67398006f, 0.67155886f, 0.66913044f, 0.66669512f,
+    0.66425240f, 0.66180259f, 0.65934575f, 0.65688181f, 0.65441096f,
+    0.65193301f, 0.64944804f, 0.64695609f, 0.64445722f, 0.64195150f,
+    0.63943905f, 0.63691956f, 0.63439327f, 0.63186014f, 0.62932026f,
+    0.62677372f, 0.62422055f, 0.62166059f, 0.61909389f, 0.61652064f,
+    0.61394072f, 0.61135429f, 0.60876143f, 0.60616189f, 0.60355592f,
+    0.60094339f, 0.59832448f, 0.59569913f, 0.59306765f, 0.59042960f,
+    0.58778518f, 0.58513451f, 0.58247757f, 0.57981461f, 0.57714522f,
+    0.57446963f, 0.57178789f, 0.56910002f, 0.56640613f, 0.56370628f,
+    0.56100023f, 0.55828822f, 0.55557019f, 0.55284619f, 0.55011630f,
+    0.54738069f, 0.54463905f, 0.54189152f, 0.53913826f, 0.53637916f,
+    0.53361434f, 0.53084403f, 0.52806783f, 0.52528596f, 0.52249849f,
+    0.51970541f, 0.51690674f, 0.51410276f, 0.51129305f, 0.50847787f,
+    0.50565726f, 0.50283122f, 0.50000006f, 0.49716327f, 0.49432117f,
+    0.49147379f, 0.48862115f, 0.48576325f, 0.48290038f, 0.48003212f,
+    0.47715873f, 0.47428021f, 0.47139663f, 0.46850798f, 0.46561456f,
+    0.46271589f, 0.45981231f, 0.45690379f, 0.45399037f, 0.45107210f,
+    0.44814920f, 0.44522130f, 0.44228864f, 0.43935123f, 0.43640912f,
+    0.43346232f, 0.43051112f, 0.42755505f, 0.42459446f, 0.42162928f,
+    0.41865960f, 0.41568545f, 0.41270703f, 0.40972400f, 0.40673658f,
+    0.40374479f, 0.40074870f, 0.39774850f, 0.39474386f, 0.39173496f,
+    0.38872188f, 0.38570464f, 0.38268328f, 0.37965804f, 0.37662849f,
+    0.37359491f, 0.37055734f, 0.36751580f, 0.36447033f, 0.36142117f,
+    0.35836792f, 0.35531086f, 0.35224995f, 0.34918529f, 0.34611690f,
+    0.34304500f, 0.33996922f, 0.33688980f, 0.33380675f, 0.33072016f,
+    0.32763001f, 0.32453656f, 0.32143945f, 0.31833887f, 0.31523487f,
+    0.31212750f, 0.30901679f, 0.30590302f, 0.30278572f, 0.29966521f,
+    0.29654145f, 0.29341453f, 0.29028472f, 0.28715155f, 0.28401530f,
+    0.28087601f, 0.27773371f, 0.27458847f, 0.27144048f, 0.26828936f,
+    0.26513538f, 0.26197854f, 0.25881892f, 0.25565651f, 0.25249159f,
+    0.24932374f, 0.24615324f, 0.24298008f, 0.23980433f, 0.23662600f,
+    0.23344538f, 0.23026201f, 0.22707619f, 0.22388794f, 0.22069728f,
+    0.21750426f, 0.21430916f, 0.21111152f, 0.20791161f, 0.20470949f,
+    0.20150517f, 0.19829892f, 0.19509031f, 0.19187963f, 0.18866688f,
+    0.18545210f, 0.18223536f, 0.17901689f, 0.17579627f, 0.17257376f,
+    0.16934940f, 0.16612324f, 0.16289529f, 0.15966584f, 0.15643445f,
+    0.15320137f, 0.14996666f, 0.14673033f, 0.14349243f, 0.14025325f,
+    0.13701232f, 0.13376991f, 0.13052608f, 0.12728085f, 0.12403426f,
+    0.12078657f, 0.11753736f, 0.11428688f, 0.11103519f, 0.10778230f,
+    0.10452849f, 0.10127334f, 0.09801710f, 0.09475980f, 0.09150149f,
+    0.08824220f, 0.08498220f, 0.08172106f, 0.07845904f, 0.07519618f,
+    0.07193252f, 0.06866808f, 0.06540315f, 0.06213728f, 0.05887074f,
+    0.05560357f, 0.05233581f, 0.04906749f, 0.04579888f, 0.04252954f,
+    0.03925974f, 0.03598953f, 0.03271893f, 0.02944798f, 0.02617695f,
+    0.02290541f, 0.01963361f, 0.01636161f, 0.01308943f, 0.00981712f,
+    0.00654493f, 0.00327244f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f,
+    0.00000000f, 0.00000000f, 0.00000000f, 0.00000000f};
+
+#endif  // MODULES_AUDIO_PROCESSING_LEGACY_NS_WINDOWS_PRIVATE_H_
diff --git a/modules/audio_processing/ns/BUILD.gn b/modules/audio_processing/ns/BUILD.gn
new file mode 100644
index 0000000..077cb00
--- /dev/null
+++ b/modules/audio_processing/ns/BUILD.gn
@@ -0,0 +1,104 @@
+# 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.
+
+import("../../../webrtc.gni")
+
+rtc_static_library("ns") {
+  visibility = [ "*" ]
+  configs += [ "..:apm_debug_dump" ]
+  sources = [
+    "fast_math.cc",
+    "fast_math.h",
+    "histograms.cc",
+    "histograms.h",
+    "noise_estimator.cc",
+    "noise_estimator.h",
+    "noise_suppressor.cc",
+    "noise_suppressor.h",
+    "ns_common.h",
+    "ns_config.h",
+    "ns_fft.cc",
+    "ns_fft.h",
+    "prior_signal_model.cc",
+    "prior_signal_model.h",
+    "prior_signal_model_estimator.cc",
+    "prior_signal_model_estimator.h",
+    "quantile_noise_estimator.cc",
+    "quantile_noise_estimator.h",
+    "signal_model.cc",
+    "signal_model.h",
+    "signal_model_estimator.cc",
+    "signal_model_estimator.h",
+    "speech_probability_estimator.cc",
+    "speech_probability_estimator.h",
+    "suppression_params.cc",
+    "suppression_params.h",
+    "wiener_filter.cc",
+    "wiener_filter.h",
+  ]
+
+  defines = []
+  if (rtc_build_with_neon && current_cpu != "arm64") {
+    suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ]
+    cflags = [ "-mfpu=neon" ]
+  }
+
+  deps = [
+    "..:apm_logging",
+    "..:audio_buffer",
+    "..:high_pass_filter",
+    "../../../api:array_view",
+    "../../../common_audio:common_audio_c",
+    "../../../common_audio/third_party/fft4g",
+    "../../../rtc_base:checks",
+    "../../../rtc_base:rtc_base_approved",
+    "../../../rtc_base:safe_minmax",
+    "../../../rtc_base/system:arch",
+    "../../../system_wrappers:cpu_features_api",
+    "../../../system_wrappers:field_trial",
+    "../../../system_wrappers:metrics",
+    "../utility:cascaded_biquad_filter",
+    "../utility:ooura_fft",
+    "//third_party/abseil-cpp/absl/types:optional",
+  ]
+}
+
+if (rtc_include_tests) {
+  rtc_source_set("ns_unittests") {
+    testonly = true
+
+    configs += [ "..:apm_debug_dump" ]
+    sources = [
+      "noise_suppressor_unittest.cc",
+    ]
+
+    deps = [
+      ":ns",
+      "..:apm_logging",
+      "..:audio_buffer",
+      "..:audio_processing",
+      "..:audio_processing_unittests",
+      "..:high_pass_filter",
+      "../../../api:array_view",
+      "../../../rtc_base:checks",
+      "../../../rtc_base:rtc_base_approved",
+      "../../../rtc_base:safe_minmax",
+      "../../../rtc_base/system:arch",
+      "../../../system_wrappers:cpu_features_api",
+      "../../../test:test_support",
+      "../utility:cascaded_biquad_filter",
+      "//third_party/abseil-cpp/absl/types:optional",
+    ]
+
+    defines = []
+
+    if (rtc_enable_protobuf) {
+      sources += []
+    }
+  }
+}
diff --git a/modules/audio_processing/ns/defines.h b/modules/audio_processing/ns/defines.h
deleted file mode 100644
index 2935f25..0000000
--- a/modules/audio_processing/ns/defines.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- *  Copyright (c) 2011 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.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
-#define MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
-
-#define BLOCKL_MAX 160        // max processing block length: 160
-#define ANAL_BLOCKL_MAX 256   // max analysis block length: 256
-#define HALF_ANAL_BLOCKL 129  // half max analysis block length + 1
-#define NUM_HIGH_BANDS_MAX 2  // max number of high bands: 2
-
-#define QUANTILE (float)0.25
-
-#define SIMULT 3
-#define END_STARTUP_LONG 200
-#define END_STARTUP_SHORT 50
-#define FACTOR (float)40.0
-#define WIDTH (float)0.01
-
-// Length of fft work arrays.
-#define IP_LENGTH \
-  (ANAL_BLOCKL_MAX >> 1)  // must be at least ceil(2 + sqrt(ANAL_BLOCKL_MAX/2))
-#define W_LENGTH (ANAL_BLOCKL_MAX >> 1)
-
-// PARAMETERS FOR NEW METHOD
-#define DD_PR_SNR (float)0.98  // DD update of prior SNR
-#define LRT_TAVG (float)0.50   // tavg parameter for LRT (previously 0.90)
-#define SPECT_FL_TAVG \
-  (float)0.30  // tavg parameter for spectral flatness measure
-#define SPECT_DIFF_TAVG \
-  (float)0.30  // tavg parameter for spectral difference measure
-#define PRIOR_UPDATE (float)0.10   // update parameter of prior model
-#define NOISE_UPDATE (float)0.90   // update parameter for noise
-#define SPEECH_UPDATE (float)0.99  // update parameter when likely speech
-#define WIDTH_PR_MAP \
-  (float)4.0  // width parameter in sigmoid map for prior model
-#define LRT_FEATURE_THR (float)0.5  // default threshold for LRT feature
-#define SF_FEATURE_THR \
-  (float)0.5  // default threshold for Spectral Flatness feature
-#define SD_FEATURE_THR \
-  (float)0.5  // default threshold for Spectral Difference feature
-#define PROB_RANGE \
-  (float)0.20                    // probability threshold for noise state in
-                                 // speech/noise likelihood
-#define HIST_PAR_EST 1000        // histogram size for estimation of parameters
-#define GAMMA_PAUSE (float)0.05  // update for conservative noise estimate
-//
-#define B_LIM (float)0.5  // threshold in final energy gain factor calculation
-#endif                    // MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_DEFINES_H_
diff --git a/modules/audio_processing/ns/fast_math.cc b/modules/audio_processing/ns/fast_math.cc
new file mode 100644
index 0000000..d13110c
--- /dev/null
+++ b/modules/audio_processing/ns/fast_math.cc
@@ -0,0 +1,84 @@
+/*
+ *  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/ns/fast_math.h"
+
+#include <math.h>
+#include <stdint.h>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+float FastLog2f(float in) {
+  RTC_DCHECK_GT(in, .0f);
+  // Read and interpret float as uint32_t and then cast to float.
+  // This is done to extract the exponent (bits 30 - 23).
+  // "Right shift" of the exponent is then performed by multiplying
+  // with the constant (1/2^23). Finally, we subtract a constant to
+  // remove the bias (https://en.wikipedia.org/wiki/Exponent_bias).
+  union {
+    float dummy;
+    uint32_t a;
+  } x = {in};
+  float out = x.a;
+  out *= 1.1920929e-7f;  // 1/2^23
+  out -= 126.942695f;    // Remove bias.
+  return out;
+}
+
+}  // namespace
+
+float SqrtFastApproximation(float f) {
+  // TODO(peah): Add fast approximate implementation.
+  return sqrtf(f);
+}
+
+float Pow2Approximation(float p) {
+  // TODO(peah): Add fast approximate implementation.
+  return powf(2.f, p);
+}
+
+float PowApproximation(float x, float p) {
+  return Pow2Approximation(p * FastLog2f(x));
+}
+
+float LogApproximation(float x) {
+  constexpr float kLogOf2 = 0.69314718056f;
+  return FastLog2f(x) * kLogOf2;
+}
+
+void LogApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y) {
+  for (size_t k = 0; k < x.size(); ++k) {
+    y[k] = LogApproximation(x[k]);
+  }
+}
+
+float ExpApproximation(float x) {
+  constexpr float kLog10Ofe = 0.4342944819f;
+  return PowApproximation(10.f, x * kLog10Ofe);
+}
+
+void ExpApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y) {
+  for (size_t k = 0; k < x.size(); ++k) {
+    y[k] = ExpApproximation(x[k]);
+  }
+}
+
+void ExpApproximationSignFlip(rtc::ArrayView<const float> x,
+                              rtc::ArrayView<float> y) {
+  for (size_t k = 0; k < x.size(); ++k) {
+    y[k] = ExpApproximation(-x[k]);
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/fast_math.h b/modules/audio_processing/ns/fast_math.h
new file mode 100644
index 0000000..0aefee9
--- /dev/null
+++ b/modules/audio_processing/ns/fast_math.h
@@ -0,0 +1,38 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_
+#define MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_
+
+#include "api/array_view.h"
+
+namespace webrtc {
+
+// Sqrt approximation.
+float SqrtFastApproximation(float f);
+
+// Log base conversion log(x) = log2(x)/log2(e).
+float LogApproximation(float x);
+void LogApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
+
+// 2^x approximation.
+float Pow2Approximation(float p);
+
+// x^p approximation.
+float PowApproximation(float x, float p);
+
+// e^x approximation.
+float ExpApproximation(float x);
+void ExpApproximation(rtc::ArrayView<const float> x, rtc::ArrayView<float> y);
+void ExpApproximationSignFlip(rtc::ArrayView<const float> x,
+                              rtc::ArrayView<float> y);
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_FAST_MATH_H_
diff --git a/modules/audio_processing/ns/histograms.cc b/modules/audio_processing/ns/histograms.cc
new file mode 100644
index 0000000..1d4f459
--- /dev/null
+++ b/modules/audio_processing/ns/histograms.cc
@@ -0,0 +1,47 @@
+/*
+ *  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/ns/histograms.h"
+
+namespace webrtc {
+
+Histograms::Histograms() {
+  Clear();
+}
+
+void Histograms::Clear() {
+  lrt_.fill(0);
+  spectral_flatness_.fill(0);
+  spectral_diff_.fill(0);
+}
+
+void Histograms::Update(const SignalModel& features_) {
+  // Update the histogram for the LRT.
+  constexpr float kOneByBinSizeLrt = 1.f / kBinSizeLrt;
+  if (features_.lrt < kHistogramSize * kBinSizeLrt && features_.lrt >= 0.f) {
+    ++lrt_[kOneByBinSizeLrt * features_.lrt];
+  }
+
+  // Update histogram for the spectral flatness.
+  constexpr float kOneByBinSizeSpecFlat = 1.f / kBinSizeSpecFlat;
+  if (features_.spectral_flatness < kHistogramSize * kBinSizeSpecFlat &&
+      features_.spectral_flatness >= 0.f) {
+    ++spectral_flatness_[features_.spectral_flatness * kOneByBinSizeSpecFlat];
+  }
+
+  // Update histogram for the spectral difference.
+  constexpr float kOneByBinSizeSpecDiff = 1.f / kBinSizeSpecDiff;
+  if (features_.spectral_diff < kHistogramSize * kBinSizeSpecDiff &&
+      features_.spectral_diff >= 0.f) {
+    ++spectral_diff_[features_.spectral_diff * kOneByBinSizeSpecDiff];
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/histograms.h b/modules/audio_processing/ns/histograms.h
new file mode 100644
index 0000000..9640e74
--- /dev/null
+++ b/modules/audio_processing/ns/histograms.h
@@ -0,0 +1,55 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_
+#define MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/signal_model.h"
+
+namespace webrtc {
+
+constexpr int kHistogramSize = 1000;
+
+// Class for handling the updating of histograms.
+class Histograms {
+ public:
+  Histograms();
+  Histograms(const Histograms&) = delete;
+  Histograms& operator=(const Histograms&) = delete;
+
+  // Clears the histograms.
+  void Clear();
+
+  // Extracts thresholds for feature parameters and updates the corresponding
+  // histogram.
+  void Update(const SignalModel& features_);
+
+  // Methods for accessing the histograms.
+  rtc::ArrayView<const int, kHistogramSize> get_lrt() const { return lrt_; }
+  rtc::ArrayView<const int, kHistogramSize> get_spectral_flatness() const {
+    return spectral_flatness_;
+  }
+  rtc::ArrayView<const int, kHistogramSize> get_spectral_diff() const {
+    return spectral_diff_;
+  }
+
+ private:
+  std::array<int, kHistogramSize> lrt_;
+  std::array<int, kHistogramSize> spectral_flatness_;
+  std::array<int, kHistogramSize> spectral_diff_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_HISTOGRAMS_H_
diff --git a/modules/audio_processing/ns/noise_estimator.cc b/modules/audio_processing/ns/noise_estimator.cc
new file mode 100644
index 0000000..5367545
--- /dev/null
+++ b/modules/audio_processing/ns/noise_estimator.cc
@@ -0,0 +1,195 @@
+/*
+ *  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/ns/noise_estimator.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Log(i).
+constexpr std::array<float, 129> log_table = {
+    0.f,       0.f,       0.f,       0.f,       0.f,       1.609438f, 1.791759f,
+    1.945910f, 2.079442f, 2.197225f, 2.302585f, 2.397895f, 2.484907f, 2.564949f,
+    2.639057f, 2.708050f, 2.772589f, 2.833213f, 2.890372f, 2.944439f, 2.995732f,
+    3.044522f, 3.091043f, 3.135494f, 3.178054f, 3.218876f, 3.258097f, 3.295837f,
+    3.332205f, 3.367296f, 3.401197f, 3.433987f, 3.465736f, 3.496507f, 3.526361f,
+    3.555348f, 3.583519f, 3.610918f, 3.637586f, 3.663562f, 3.688879f, 3.713572f,
+    3.737669f, 3.761200f, 3.784190f, 3.806663f, 3.828641f, 3.850147f, 3.871201f,
+    3.891820f, 3.912023f, 3.931826f, 3.951244f, 3.970292f, 3.988984f, 4.007333f,
+    4.025352f, 4.043051f, 4.060443f, 4.077538f, 4.094345f, 4.110874f, 4.127134f,
+    4.143135f, 4.158883f, 4.174387f, 4.189655f, 4.204693f, 4.219508f, 4.234107f,
+    4.248495f, 4.262680f, 4.276666f, 4.290460f, 4.304065f, 4.317488f, 4.330733f,
+    4.343805f, 4.356709f, 4.369448f, 4.382027f, 4.394449f, 4.406719f, 4.418841f,
+    4.430817f, 4.442651f, 4.454347f, 4.465908f, 4.477337f, 4.488636f, 4.499810f,
+    4.510859f, 4.521789f, 4.532599f, 4.543295f, 4.553877f, 4.564348f, 4.574711f,
+    4.584968f, 4.595119f, 4.605170f, 4.615121f, 4.624973f, 4.634729f, 4.644391f,
+    4.653960f, 4.663439f, 4.672829f, 4.682131f, 4.691348f, 4.700480f, 4.709530f,
+    4.718499f, 4.727388f, 4.736198f, 4.744932f, 4.753591f, 4.762174f, 4.770685f,
+    4.779124f, 4.787492f, 4.795791f, 4.804021f, 4.812184f, 4.820282f, 4.828314f,
+    4.836282f, 4.844187f, 4.852030f};
+
+}  // namespace
+
+NoiseEstimator::NoiseEstimator(const SuppressionParams& suppression_params)
+    : suppression_params_(suppression_params) {
+  noise_spectrum_.fill(0.f);
+  prev_noise_spectrum_.fill(0.f);
+  conservative_noise_spectrum_.fill(0.f);
+  parametric_noise_spectrum_.fill(0.f);
+}
+
+void NoiseEstimator::PrepareAnalysis() {
+  std::copy(noise_spectrum_.begin(), noise_spectrum_.end(),
+            prev_noise_spectrum_.begin());
+}
+
+void NoiseEstimator::PreUpdate(
+    int32_t num_analyzed_frames,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+    float signal_spectral_sum) {
+  quantile_noise_estimator_.Estimate(signal_spectrum, noise_spectrum_);
+
+  if (num_analyzed_frames < kShortStartupPhaseBlocks) {
+    // Compute simplified noise model during startup.
+    const size_t kStartBand = 5;
+    float sum_log_i_log_magn = 0.f;
+    float sum_log_i = 0.f;
+    float sum_log_i_square = 0.f;
+    float sum_log_magn = 0.f;
+    for (size_t i = kStartBand; i < kFftSizeBy2Plus1; ++i) {
+      float log_i = log_table[i];
+      sum_log_i += log_i;
+      sum_log_i_square += log_i * log_i;
+      float log_signal = LogApproximation(signal_spectrum[i]);
+      sum_log_magn += log_signal;
+      sum_log_i_log_magn += log_i * log_signal;
+    }
+
+    // Estimate the parameter for the level of the white noise.
+    constexpr float kOneByFftSizeBy2Plus1 = 1.f / kFftSizeBy2Plus1;
+    white_noise_level_ += signal_spectral_sum * kOneByFftSizeBy2Plus1 *
+                          suppression_params_.over_subtraction_factor;
+
+    // Estimate pink noise parameters.
+    float denom = sum_log_i_square * (kFftSizeBy2Plus1 - kStartBand) -
+                  sum_log_i * sum_log_i;
+    float num =
+        sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn;
+    RTC_DCHECK_NE(denom, 0.f);
+    float pink_noise_adjustment = num / denom;
+
+    // Constrain the estimated spectrum to be positive.
+    pink_noise_adjustment = std::max(pink_noise_adjustment, 0.f);
+    pink_noise_numerator_ += pink_noise_adjustment;
+    num = sum_log_i * sum_log_magn -
+          (kFftSizeBy2Plus1 - kStartBand) * sum_log_i_log_magn;
+    RTC_DCHECK_NE(denom, 0.f);
+    pink_noise_adjustment = num / denom;
+
+    // Constrain the pink noise power to be in the interval [0, 1].
+    pink_noise_adjustment = std::max(std::min(pink_noise_adjustment, 1.f), 0.f);
+
+    pink_noise_exp_ += pink_noise_adjustment;
+
+    const float one_by_num_analyzed_frames_plus_1 =
+        1.f / (num_analyzed_frames + 1.f);
+
+    // Calculate the frequency-independent parts of parametric noise estimate.
+    float parametric_exp = 0.f;
+    float parametric_num = 0.f;
+    if (pink_noise_exp_ > 0.f) {
+      // Use pink noise estimate.
+      parametric_num = ExpApproximation(pink_noise_numerator_ *
+                                        one_by_num_analyzed_frames_plus_1);
+      parametric_num *= num_analyzed_frames + 1.f;
+      parametric_exp = pink_noise_exp_ * one_by_num_analyzed_frames_plus_1;
+    }
+
+    constexpr float kOneByShortStartupPhaseBlocks =
+        1.f / kShortStartupPhaseBlocks;
+    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+      // Estimate the background noise using the white and pink noise
+      // parameters.
+      if (pink_noise_exp_ == 0.f) {
+        // Use white noise estimate.
+        parametric_noise_spectrum_[i] = white_noise_level_;
+      } else {
+        // Use pink noise estimate.
+        float use_band = i < kStartBand ? kStartBand : i;
+        float denom = PowApproximation(use_band, parametric_exp);
+        RTC_DCHECK_NE(denom, 0.f);
+        parametric_noise_spectrum_[i] = parametric_num / denom;
+      }
+    }
+
+    // Weight quantile noise with modeled noise.
+    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+      noise_spectrum_[i] *= num_analyzed_frames;
+      float tmp = parametric_noise_spectrum_[i] *
+                  (kShortStartupPhaseBlocks - num_analyzed_frames);
+      noise_spectrum_[i] += tmp * one_by_num_analyzed_frames_plus_1;
+      noise_spectrum_[i] *= kOneByShortStartupPhaseBlocks;
+    }
+  }
+}
+
+void NoiseEstimator::PostUpdate(
+    rtc::ArrayView<const float> speech_probability,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum) {
+  // Time-avg parameter for noise_spectrum update.
+  constexpr float kNoiseUpdate = 0.9f;
+
+  float gamma = kNoiseUpdate;
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    const float prob_speech = speech_probability[i];
+    const float prob_non_speech = 1.f - prob_speech;
+
+    // Temporary noise update used for speech frames if update value is less
+    // than previous.
+    float noise_update_tmp =
+        gamma * prev_noise_spectrum_[i] +
+        (1.f - gamma) * (prob_non_speech * signal_spectrum[i] +
+                         prob_speech * prev_noise_spectrum_[i]);
+
+    // Time-constant based on speech/noise_spectrum state.
+    float gamma_old = gamma;
+
+    // Increase gamma for frame likely to be seech.
+    constexpr float kProbRange = .2f;
+    gamma = prob_speech > kProbRange ? .99f : kNoiseUpdate;
+
+    // Conservative noise_spectrum update.
+    if (prob_speech < kProbRange) {
+      conservative_noise_spectrum_[i] +=
+          0.05f * (signal_spectrum[i] - conservative_noise_spectrum_[i]);
+    }
+
+    // Noise_spectrum update.
+    if (gamma == gamma_old) {
+      noise_spectrum_[i] = noise_update_tmp;
+    } else {
+      noise_spectrum_[i] =
+          gamma * prev_noise_spectrum_[i] +
+          (1.f - gamma) * (prob_non_speech * signal_spectrum[i] +
+                           prob_speech * prev_noise_spectrum_[i]);
+      // Allow for noise_spectrum update downwards: If noise_spectrum update
+      // decreases the noise_spectrum, it is safe, so allow it to happen.
+      noise_spectrum_[i] = std::min(noise_spectrum_[i], noise_update_tmp);
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/noise_estimator.h b/modules/audio_processing/ns/noise_estimator.h
new file mode 100644
index 0000000..0c0466a
--- /dev/null
+++ b/modules/audio_processing/ns/noise_estimator.h
@@ -0,0 +1,77 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/quantile_noise_estimator.h"
+#include "modules/audio_processing/ns/suppression_params.h"
+
+namespace webrtc {
+
+// Class for estimating the spectral characteristics of the noise in an incoming
+// signal.
+class NoiseEstimator {
+ public:
+  explicit NoiseEstimator(const SuppressionParams& suppression_params);
+
+  // Prepare the estimator for analysis of a new frame.
+  void PrepareAnalysis();
+
+  // Performs the first step of the estimator update.
+  void PreUpdate(int32_t num_analyzed_frames,
+                 rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+                 float signal_spectral_sum);
+
+  // Performs the second step of the estimator update.
+  void PostUpdate(
+      rtc::ArrayView<const float> speech_probability,
+      rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum);
+
+  // Returns the noise spectral estimate.
+  rtc::ArrayView<const float, kFftSizeBy2Plus1> get_noise_spectrum() const {
+    return noise_spectrum_;
+  }
+
+  // Returns the noise from the previous frame.
+  rtc::ArrayView<const float, kFftSizeBy2Plus1> get_prev_noise_spectrum()
+      const {
+    return prev_noise_spectrum_;
+  }
+
+  // Returns a noise spectral estimate based on white and pink noise parameters.
+  rtc::ArrayView<const float, kFftSizeBy2Plus1> get_parametric_noise_spectrum()
+      const {
+    return parametric_noise_spectrum_;
+  }
+  rtc::ArrayView<const float, kFftSizeBy2Plus1>
+  get_conservative_noise_spectrum() const {
+    return conservative_noise_spectrum_;
+  }
+
+ private:
+  const SuppressionParams& suppression_params_;
+  float white_noise_level_ = 0.f;
+  float pink_noise_numerator_ = 0.f;
+  float pink_noise_exp_ = 0.f;
+  std::array<float, kFftSizeBy2Plus1> prev_noise_spectrum_;
+  std::array<float, kFftSizeBy2Plus1> conservative_noise_spectrum_;
+  std::array<float, kFftSizeBy2Plus1> parametric_noise_spectrum_;
+  std::array<float, kFftSizeBy2Plus1> noise_spectrum_;
+  QuantileNoiseEstimator quantile_noise_estimator_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_NOISE_ESTIMATOR_H_
diff --git a/modules/audio_processing/ns/noise_suppressor.cc b/modules/audio_processing/ns/noise_suppressor.cc
new file mode 100644
index 0000000..89e1fe0
--- /dev/null
+++ b/modules/audio_processing/ns/noise_suppressor.cc
@@ -0,0 +1,549 @@
+/*
+ *  Copyright (c) 2012 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/ns/noise_suppressor.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Maps sample rate to number of bands.
+size_t NumBandsForRate(size_t sample_rate_hz) {
+  RTC_DCHECK(sample_rate_hz == 16000 || sample_rate_hz == 32000 ||
+             sample_rate_hz == 48000);
+  return sample_rate_hz / 16000;
+}
+
+// Maximum number of channels for which the channel data is stored on
+// the stack. If the number of channels are larger than this, they are stored
+// using scratch memory that is pre-allocated on the heap. The reason for this
+// partitioning is not to waste heap space for handling the more common numbers
+// of channels, while at the same time not limiting the support for higher
+// numbers of channels by enforcing the channel data to be stored on the
+// stack using a fixed maximum value.
+constexpr size_t kMaxNumChannelsOnStack = 2;
+
+// Chooses the number of channels to store on the heap when that is required due
+// to the number of channels being larger than the pre-defined number
+// of channels to store on the stack.
+size_t NumChannelsOnHeap(size_t num_channels) {
+  return num_channels > kMaxNumChannelsOnStack ? num_channels : 0;
+}
+
+// Hybrib Hanning and flat window for the filterbank.
+constexpr std::array<float, 96> kBlocks160w256FirstHalf = {
+    0.00000000f, 0.01636173f, 0.03271908f, 0.04906767f, 0.06540313f,
+    0.08172107f, 0.09801714f, 0.11428696f, 0.13052619f, 0.14673047f,
+    0.16289547f, 0.17901686f, 0.19509032f, 0.21111155f, 0.22707626f,
+    0.24298018f, 0.25881905f, 0.27458862f, 0.29028468f, 0.30590302f,
+    0.32143947f, 0.33688985f, 0.35225005f, 0.36751594f, 0.38268343f,
+    0.39774847f, 0.41270703f, 0.42755509f, 0.44228869f, 0.45690388f,
+    0.47139674f, 0.48576339f, 0.50000000f, 0.51410274f, 0.52806785f,
+    0.54189158f, 0.55557023f, 0.56910015f, 0.58247770f, 0.59569930f,
+    0.60876143f, 0.62166057f, 0.63439328f, 0.64695615f, 0.65934582f,
+    0.67155895f, 0.68359230f, 0.69544264f, 0.70710678f, 0.71858162f,
+    0.72986407f, 0.74095113f, 0.75183981f, 0.76252720f, 0.77301045f,
+    0.78328675f, 0.79335334f, 0.80320753f, 0.81284668f, 0.82226822f,
+    0.83146961f, 0.84044840f, 0.84920218f, 0.85772861f, 0.86602540f,
+    0.87409034f, 0.88192126f, 0.88951608f, 0.89687274f, 0.90398929f,
+    0.91086382f, 0.91749450f, 0.92387953f, 0.93001722f, 0.93590593f,
+    0.94154407f, 0.94693013f, 0.95206268f, 0.95694034f, 0.96156180f,
+    0.96592583f, 0.97003125f, 0.97387698f, 0.97746197f, 0.98078528f,
+    0.98384601f, 0.98664333f, 0.98917651f, 0.99144486f, 0.99344778f,
+    0.99518473f, 0.99665524f, 0.99785892f, 0.99879546f, 0.99946459f,
+    0.99986614f};
+
+// Applies the filterbank window to a buffer.
+void ApplyFilterBankWindow(rtc::ArrayView<float, kFftSize> x) {
+  for (size_t i = 0; i < 96; ++i) {
+    x[i] = kBlocks160w256FirstHalf[i] * x[i];
+  }
+
+  for (size_t i = 161, k = 95; i < kFftSize; ++i, --k) {
+    RTC_DCHECK_NE(0, k);
+    x[i] = kBlocks160w256FirstHalf[k] * x[i];
+  }
+}
+
+// Extends a frame with previous data.
+void FormExtendedFrame(rtc::ArrayView<const float, kNsFrameSize> frame,
+                       rtc::ArrayView<float, kFftSize - kNsFrameSize> old_data,
+                       rtc::ArrayView<float, kFftSize> extended_frame) {
+  std::copy(old_data.begin(), old_data.end(), extended_frame.begin());
+  std::copy(frame.begin(), frame.end(),
+            extended_frame.begin() + old_data.size());
+  std::copy(extended_frame.end() - old_data.size(), extended_frame.end(),
+            old_data.begin());
+}
+
+// Uses overlap-and-add to produce an output frame.
+void OverlapAndAdd(rtc::ArrayView<const float, kFftSize> extended_frame,
+                   rtc::ArrayView<float, kOverlapSize> overlap_memory,
+                   rtc::ArrayView<float, kNsFrameSize> output_frame) {
+  for (size_t i = 0; i < kOverlapSize; ++i) {
+    output_frame[i] = overlap_memory[i] + extended_frame[i];
+  }
+  std::copy(extended_frame.begin() + kOverlapSize,
+            extended_frame.begin() + kNsFrameSize,
+            output_frame.begin() + kOverlapSize);
+  std::copy(extended_frame.begin() + kNsFrameSize, extended_frame.end(),
+            overlap_memory.begin());
+}
+
+// Produces a delayed frame.
+void DelaySignal(rtc::ArrayView<const float, kNsFrameSize> frame,
+                 rtc::ArrayView<float, kFftSize - kNsFrameSize> delay_buffer,
+                 rtc::ArrayView<float, kNsFrameSize> delayed_frame) {
+  constexpr size_t kSamplesFromFrame = kNsFrameSize - (kFftSize - kNsFrameSize);
+  std::copy(delay_buffer.begin(), delay_buffer.end(), delayed_frame.begin());
+  std::copy(frame.begin(), frame.begin() + kSamplesFromFrame,
+            delayed_frame.begin() + delay_buffer.size());
+
+  std::copy(frame.begin() + kSamplesFromFrame, frame.end(),
+            delay_buffer.begin());
+}
+
+// Computes the energy of an extended frame.
+float ComputeEnergyOfExtendedFrame(rtc::ArrayView<const float, kFftSize> x) {
+  float energy = 0.f;
+  for (float x_k : x) {
+    energy += x_k * x_k;
+  }
+
+  return energy;
+}
+
+// Computes the energy of an extended frame based on its subcomponents.
+float ComputeEnergyOfExtendedFrame(
+    rtc::ArrayView<const float, kNsFrameSize> frame,
+    rtc::ArrayView<float, kFftSize - kNsFrameSize> old_data) {
+  float energy = 0.f;
+  for (float v : old_data) {
+    energy += v * v;
+  }
+  for (float v : frame) {
+    energy += v * v;
+  }
+
+  return energy;
+}
+
+// Computes the magnitude spectrum based on an FFT output.
+void ComputeMagnitudeSpectrum(
+    rtc::ArrayView<const float, kFftSize> real,
+    rtc::ArrayView<const float, kFftSize> imag,
+    rtc::ArrayView<float, kFftSizeBy2Plus1> signal_spectrum) {
+  signal_spectrum[0] = fabsf(real[0]) + 1.f;
+  signal_spectrum[kFftSizeBy2Plus1 - 1] =
+      fabsf(real[kFftSizeBy2Plus1 - 1]) + 1.f;
+
+  for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) {
+    signal_spectrum[i] =
+        SqrtFastApproximation(real[i] * real[i] + imag[i] * imag[i]) + 1.f;
+  }
+}
+
+// Compute prior and post SNR.
+void ComputeSnr(rtc::ArrayView<const float, kFftSizeBy2Plus1> filter,
+                rtc::ArrayView<const float> prev_signal_spectrum,
+                rtc::ArrayView<const float> signal_spectrum,
+                rtc::ArrayView<const float> prev_noise_spectrum,
+                rtc::ArrayView<const float> noise_spectrum,
+                rtc::ArrayView<float> prior_snr,
+                rtc::ArrayView<float> post_snr) {
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    // Previous post SNR.
+    // Previous estimate: based on previous frame with gain filter.
+    float prev_estimate = prev_signal_spectrum[i] /
+                          (prev_noise_spectrum[i] + 0.0001f) * filter[i];
+    // Post SNR.
+    if (signal_spectrum[i] > noise_spectrum[i]) {
+      post_snr[i] = signal_spectrum[i] / (noise_spectrum[i] + 0.0001f) - 1.f;
+    } else {
+      post_snr[i] = 0.f;
+    }
+    // The directed decision estimate of the prior SNR is a sum the current and
+    // previous estimates.
+    prior_snr[i] = 0.98f * prev_estimate + (1.f - 0.98f) * post_snr[i];
+  }
+}
+
+// Computes the attenuating gain for the noise suppression of the upper bands.
+float ComputeUpperBandsGain(
+    float minimum_attenuating_gain,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> filter,
+    rtc::ArrayView<const float> speech_probability,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> prev_analysis_signal_spectrum,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum) {
+  // Average speech prob and filter gain for the end of the lowest band.
+  constexpr int kNumAvgBins = 32;
+  constexpr float kOneByNumAvgBins = 1.f / kNumAvgBins;
+
+  float avg_prob_speech = 0.f;
+  float avg_filter_gain = 0.f;
+  for (size_t i = kFftSizeBy2Plus1 - kNumAvgBins - 1; i < kFftSizeBy2Plus1 - 1;
+       i++) {
+    avg_prob_speech += speech_probability[i];
+    avg_filter_gain += filter[i];
+  }
+  avg_prob_speech = avg_prob_speech * kOneByNumAvgBins;
+  avg_filter_gain = avg_filter_gain * kOneByNumAvgBins;
+
+  // If the speech was suppressed by a component between Analyze and Process, an
+  // example being by an AEC, it should not be considered speech for the purpose
+  // of high band suppression. To that end, the speech probability is scaled
+  // accordingly.
+  float sum_analysis_spectrum = 0.f;
+  float sum_processing_spectrum = 0.f;
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    sum_analysis_spectrum += prev_analysis_signal_spectrum[i];
+    sum_processing_spectrum += signal_spectrum[i];
+  }
+
+  // The magnitude spectrum computation enforces the spectrum to be strictly
+  // positive.
+  RTC_DCHECK_GT(sum_analysis_spectrum, 0.f);
+  avg_prob_speech *= sum_processing_spectrum / sum_analysis_spectrum;
+
+  // Compute gain based on speech probability.
+  float gain =
+      0.5f * (1.f + static_cast<float>(tanh(2.f * avg_prob_speech - 1.f)));
+
+  // Combine gain with low band gain.
+  if (avg_prob_speech >= 0.5f) {
+    gain = 0.25f * gain + 0.75f * avg_filter_gain;
+  } else {
+    gain = 0.5f * gain + 0.5f * avg_filter_gain;
+  }
+
+  // Make sure gain is within flooring range.
+  return std::min(std::max(gain, minimum_attenuating_gain), 1.f);
+}
+
+}  // namespace
+
+NoiseSuppressor::ChannelState::ChannelState(
+    const SuppressionParams& suppression_params,
+    size_t num_bands)
+    : wiener_filter(suppression_params),
+      noise_estimator(suppression_params),
+      process_delay_memory(num_bands > 1 ? num_bands - 1 : 0) {
+  analyze_analysis_memory.fill(0.f);
+  prev_analysis_signal_spectrum.fill(1.f);
+  process_analysis_memory.fill(0.f);
+  process_synthesis_memory.fill(0.f);
+  for (auto& d : process_delay_memory) {
+    d.fill(0.f);
+  }
+}
+
+NoiseSuppressor::NoiseSuppressor(const NsConfig& config,
+                                 size_t sample_rate_hz,
+                                 size_t num_channels)
+    : num_bands_(NumBandsForRate(sample_rate_hz)),
+      num_channels_(num_channels),
+      suppression_params_(config.target_level),
+      filter_bank_states_heap_(NumChannelsOnHeap(num_channels_)),
+      upper_band_gains_heap_(NumChannelsOnHeap(num_channels_)),
+      energies_before_filtering_heap_(NumChannelsOnHeap(num_channels_)),
+      gain_adjustments_heap_(NumChannelsOnHeap(num_channels_)),
+      channels_(num_channels_) {
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    channels_[ch] =
+        std::make_unique<ChannelState>(suppression_params_, num_bands_);
+  }
+}
+
+void NoiseSuppressor::AggregateWienerFilters(
+    rtc::ArrayView<float, kFftSizeBy2Plus1> filter) const {
+  rtc::ArrayView<const float, kFftSizeBy2Plus1> filter0 =
+      channels_[0]->wiener_filter.get_filter();
+  std::copy(filter0.begin(), filter0.end(), filter.begin());
+
+  for (size_t ch = 1; ch < num_channels_; ++ch) {
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> filter_ch =
+        channels_[ch]->wiener_filter.get_filter();
+
+    for (size_t k = 0; k < kFftSizeBy2Plus1; ++k) {
+      filter[k] = std::min(filter[k], filter_ch[k]);
+    }
+  }
+}
+
+void NoiseSuppressor::Analyze(const AudioBuffer& audio) {
+  // Prepare the noise estimator for the analysis stage.
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    channels_[ch]->noise_estimator.PrepareAnalysis();
+  }
+
+  // Check for zero frames.
+  bool zero_frame = true;
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    rtc::ArrayView<const float, kNsFrameSize> y_band0(
+        &audio.split_bands_const(ch)[0][0], kNsFrameSize);
+    float energy = ComputeEnergyOfExtendedFrame(
+        y_band0, channels_[ch]->analyze_analysis_memory);
+    if (energy > 0.f) {
+      zero_frame = false;
+      break;
+    }
+  }
+
+  if (zero_frame) {
+    // We want to avoid updating statistics in this case:
+    // Updating feature statistics when we have zeros only will cause
+    // thresholds to move towards zero signal situations. This in turn has the
+    // effect that once the signal is "turned on" (non-zero values) everything
+    // will be treated as speech and there is no noise suppression effect.
+    // Depending on the duration of the inactive signal it takes a
+    // considerable amount of time for the system to learn what is noise and
+    // what is speech.
+    return;
+  }
+
+  // Only update analysis counter for frames that are properly analyzed.
+  if (++num_analyzed_frames_ < 0) {
+    num_analyzed_frames_ = 0;
+  }
+
+  // Analyze all channels.
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    std::unique_ptr<ChannelState>& ch_p = channels_[ch];
+    rtc::ArrayView<const float, kNsFrameSize> y_band0(
+        &audio.split_bands_const(ch)[0][0], kNsFrameSize);
+
+    // Form an extended frame and apply analysis filter bank windowing.
+    std::array<float, kFftSize> extended_frame;
+    FormExtendedFrame(y_band0, ch_p->analyze_analysis_memory, extended_frame);
+    ApplyFilterBankWindow(extended_frame);
+
+    // Compute the magnitude spectrum.
+    std::array<float, kFftSize> real;
+    std::array<float, kFftSize> imag;
+    fft_.Fft(extended_frame, real, imag);
+
+    std::array<float, kFftSizeBy2Plus1> signal_spectrum;
+    ComputeMagnitudeSpectrum(real, imag, signal_spectrum);
+
+    // Compute energies.
+    float signal_energy = 0.f;
+    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+      signal_energy += real[i] * real[i] + imag[i] * imag[i];
+    }
+    signal_energy /= kFftSizeBy2Plus1;
+
+    float signal_spectral_sum = 0.f;
+    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+      signal_spectral_sum += signal_spectrum[i];
+    }
+
+    // Estimate the noise spectra and the probability estimates of speech
+    // presence.
+    ch_p->noise_estimator.PreUpdate(num_analyzed_frames_, signal_spectrum,
+                                    signal_spectral_sum);
+
+    std::array<float, kFftSizeBy2Plus1> post_snr;
+    std::array<float, kFftSizeBy2Plus1> prior_snr;
+    ComputeSnr(ch_p->wiener_filter.get_filter(),
+               ch_p->prev_analysis_signal_spectrum, signal_spectrum,
+               ch_p->noise_estimator.get_prev_noise_spectrum(),
+               ch_p->noise_estimator.get_noise_spectrum(), prior_snr, post_snr);
+
+    ch_p->speech_probability_estimator.Update(
+        num_analyzed_frames_, prior_snr, post_snr,
+        ch_p->noise_estimator.get_conservative_noise_spectrum(),
+        signal_spectrum, signal_spectral_sum, signal_energy);
+
+    ch_p->noise_estimator.PostUpdate(
+        ch_p->speech_probability_estimator.get_probability(), signal_spectrum);
+
+    // Store the magnitude spectrum to make it avalilable for the process
+    // method.
+    std::copy(signal_spectrum.begin(), signal_spectrum.end(),
+              ch_p->prev_analysis_signal_spectrum.begin());
+  }
+}
+
+void NoiseSuppressor::Process(AudioBuffer* audio) {
+  // Select the space for storing data during the processing.
+  std::array<FilterBankState, kMaxNumChannelsOnStack> filter_bank_states_stack;
+  rtc::ArrayView<FilterBankState> filter_bank_states(
+      filter_bank_states_stack.data(), num_channels_);
+  std::array<float, kMaxNumChannelsOnStack> upper_band_gains_stack;
+  rtc::ArrayView<float> upper_band_gains(upper_band_gains_stack.data(),
+                                         num_channels_);
+  std::array<float, kMaxNumChannelsOnStack> energies_before_filtering_stack;
+  rtc::ArrayView<float> energies_before_filtering(
+      energies_before_filtering_stack.data(), num_channels_);
+  std::array<float, kMaxNumChannelsOnStack> gain_adjustments_stack;
+  rtc::ArrayView<float> gain_adjustments(gain_adjustments_stack.data(),
+                                         num_channels_);
+  if (NumChannelsOnHeap(num_channels_) > 0) {
+    // If the stack-allocated space is too small, use the heap for storing the
+    // data.
+    filter_bank_states = rtc::ArrayView<FilterBankState>(
+        filter_bank_states_heap_.data(), num_channels_);
+    upper_band_gains =
+        rtc::ArrayView<float>(upper_band_gains_heap_.data(), num_channels_);
+    energies_before_filtering = rtc::ArrayView<float>(
+        energies_before_filtering_heap_.data(), num_channels_);
+    gain_adjustments =
+        rtc::ArrayView<float>(gain_adjustments_heap_.data(), num_channels_);
+  }
+
+  // Compute the suppression filters for all channels.
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    // Form an extended frame and apply analysis filter bank windowing.
+    rtc::ArrayView<float, kNsFrameSize> y_band0(&audio->split_bands(ch)[0][0],
+                                                kNsFrameSize);
+
+    FormExtendedFrame(y_band0, channels_[ch]->process_analysis_memory,
+                      filter_bank_states[ch].extended_frame);
+
+    ApplyFilterBankWindow(filter_bank_states[ch].extended_frame);
+
+    energies_before_filtering[ch] =
+        ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame);
+
+    // Perform filter bank analysis and compute the magnitude spectrum.
+    fft_.Fft(filter_bank_states[ch].extended_frame, filter_bank_states[ch].real,
+             filter_bank_states[ch].imag);
+
+    std::array<float, kFftSizeBy2Plus1> signal_spectrum;
+    ComputeMagnitudeSpectrum(filter_bank_states[ch].real,
+                             filter_bank_states[ch].imag, signal_spectrum);
+
+    // Compute the frequency domain gain filter for noise attenuation.
+    channels_[ch]->wiener_filter.Update(
+        num_analyzed_frames_,
+        channels_[ch]->noise_estimator.get_noise_spectrum(),
+        channels_[ch]->noise_estimator.get_prev_noise_spectrum(),
+        channels_[ch]->noise_estimator.get_parametric_noise_spectrum(),
+        signal_spectrum);
+
+    if (num_bands_ > 1) {
+      // Compute the time-domain gain for attenuating the noise in the upper
+      // bands.
+
+      upper_band_gains[ch] = ComputeUpperBandsGain(
+          suppression_params_.minimum_attenuating_gain,
+          channels_[ch]->wiener_filter.get_filter(),
+          channels_[ch]->speech_probability_estimator.get_probability(),
+          channels_[ch]->prev_analysis_signal_spectrum, signal_spectrum);
+    }
+  }
+
+  // Aggregate the Wiener filters for all channels.
+  std::array<float, kFftSizeBy2Plus1> filter_data;
+  rtc::ArrayView<const float, kFftSizeBy2Plus1> filter = filter_data;
+  if (num_channels_ == 1) {
+    filter = channels_[0]->wiener_filter.get_filter();
+  } else {
+    AggregateWienerFilters(filter_data);
+  }
+
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    // Apply the filter to the lower band.
+    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+      filter_bank_states[ch].real[i] *= filter[i];
+      filter_bank_states[ch].imag[i] *= filter[i];
+    }
+  }
+
+  // Perform filter bank synthesis
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    fft_.Ifft(filter_bank_states[ch].real, filter_bank_states[ch].imag,
+              filter_bank_states[ch].extended_frame);
+  }
+
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    const float energy_after_filtering =
+        ComputeEnergyOfExtendedFrame(filter_bank_states[ch].extended_frame);
+
+    // Apply synthesis window.
+    ApplyFilterBankWindow(filter_bank_states[ch].extended_frame);
+
+    // Compute the adjustment of the noise attenuation filter based on the
+    // effect of the attenuation.
+    gain_adjustments[ch] =
+        channels_[ch]->wiener_filter.ComputeOverallScalingFactor(
+            num_analyzed_frames_,
+            channels_[ch]->speech_probability_estimator.get_prior_probability(),
+            energies_before_filtering[ch], energy_after_filtering);
+  }
+
+  // Select and apply adjustment of the noise attenuation filter based on the
+  // effect of the attenuation.
+  float gain_adjustment = gain_adjustments[0];
+  for (size_t ch = 1; ch < num_channels_; ++ch) {
+    gain_adjustment = std::min(gain_adjustment, gain_adjustments[ch]);
+  }
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    for (size_t i = 0; i < kFftSize; ++i) {
+      filter_bank_states[ch].extended_frame[i] =
+          gain_adjustment * filter_bank_states[ch].extended_frame[i];
+    }
+  }
+
+  // Use overlap-and-add to form the output frame of the lowest band.
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    rtc::ArrayView<float, kNsFrameSize> y_band0(&audio->split_bands(ch)[0][0],
+                                                kNsFrameSize);
+    OverlapAndAdd(filter_bank_states[ch].extended_frame,
+                  channels_[ch]->process_synthesis_memory, y_band0);
+  }
+
+  if (num_bands_ > 1) {
+    // Select the noise attenuating gain to apply to the upper band.
+    float upper_band_gain = upper_band_gains[0];
+    for (size_t ch = 1; ch < num_channels_; ++ch) {
+      upper_band_gain = std::min(upper_band_gain, upper_band_gains[ch]);
+    }
+
+    // Process the upper bands.
+    for (size_t ch = 0; ch < num_channels_; ++ch) {
+      for (size_t b = 1; b < num_bands_; ++b) {
+        // Delay the upper bands to match the delay of the filterbank applied to
+        // the lowest band.
+        rtc::ArrayView<float, kNsFrameSize> y_band(
+            &audio->split_bands(ch)[b][0], kNsFrameSize);
+        std::array<float, kNsFrameSize> delayed_frame;
+        DelaySignal(y_band, channels_[ch]->process_delay_memory[b - 1],
+                    delayed_frame);
+
+        // Apply the time-domain noise-attenuating gain.
+        for (size_t j = 0; j < kNsFrameSize; j++) {
+          y_band[j] = upper_band_gain * delayed_frame[j];
+        }
+      }
+    }
+  }
+
+  // Limit the output the allowed range.
+  for (size_t ch = 0; ch < num_channels_; ++ch) {
+    for (size_t b = 0; b < num_bands_; ++b) {
+      rtc::ArrayView<float, kNsFrameSize> y_band(&audio->split_bands(ch)[b][0],
+                                                 kNsFrameSize);
+      for (size_t j = 0; j < kNsFrameSize; j++) {
+        y_band[j] = std::min(std::max(y_band[j], -32768.f), 32767.f);
+      }
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/noise_suppressor.h b/modules/audio_processing/ns/noise_suppressor.h
new file mode 100644
index 0000000..d962886
--- /dev/null
+++ b/modules/audio_processing/ns/noise_suppressor.h
@@ -0,0 +1,83 @@
+/*
+ *  Copyright (c) 2012 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_
+
+#include <memory>
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/audio_buffer.h"
+#include "modules/audio_processing/ns/noise_estimator.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/ns_config.h"
+#include "modules/audio_processing/ns/ns_fft.h"
+#include "modules/audio_processing/ns/speech_probability_estimator.h"
+#include "modules/audio_processing/ns/wiener_filter.h"
+
+namespace webrtc {
+
+// Class for suppressing noise in a signal.
+class NoiseSuppressor {
+ public:
+  NoiseSuppressor(const NsConfig& config,
+                  size_t sample_rate_hz,
+                  size_t num_channels);
+  NoiseSuppressor(const NoiseSuppressor&) = delete;
+  NoiseSuppressor& operator=(const NoiseSuppressor&) = delete;
+
+  // Analyses the signal (typically applied before the AEC to avoid analyzing
+  // any comfort noise signal).
+  void Analyze(const AudioBuffer& audio);
+
+  // Applies noise suppression.
+  void Process(AudioBuffer* audio);
+
+ private:
+  const size_t num_bands_;
+  const size_t num_channels_;
+  const SuppressionParams suppression_params_;
+  int32_t num_analyzed_frames_ = -1;
+  NrFft fft_;
+
+  struct ChannelState {
+    ChannelState(const SuppressionParams& suppression_params, size_t num_bands);
+
+    SpeechProbabilityEstimator speech_probability_estimator;
+    WienerFilter wiener_filter;
+    NoiseEstimator noise_estimator;
+    std::array<float, kFftSizeBy2Plus1> prev_analysis_signal_spectrum;
+    std::array<float, kFftSize - kNsFrameSize> analyze_analysis_memory;
+    std::array<float, kOverlapSize> process_analysis_memory;
+    std::array<float, kOverlapSize> process_synthesis_memory;
+    std::vector<std::array<float, kOverlapSize>> process_delay_memory;
+  };
+
+  struct FilterBankState {
+    std::array<float, kFftSize> real;
+    std::array<float, kFftSize> imag;
+    std::array<float, kFftSize> extended_frame;
+  };
+
+  std::vector<FilterBankState> filter_bank_states_heap_;
+  std::vector<float> upper_band_gains_heap_;
+  std::vector<float> energies_before_filtering_heap_;
+  std::vector<float> gain_adjustments_heap_;
+  std::vector<std::unique_ptr<ChannelState>> channels_;
+
+  // Aggregates the Wiener filters into a single filter to use.
+  void AggregateWienerFilters(
+      rtc::ArrayView<float, kFftSizeBy2Plus1> filter) const;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_NOISE_SUPPRESSOR_H_
diff --git a/modules/audio_processing/ns/noise_suppressor_unittest.cc b/modules/audio_processing/ns/noise_suppressor_unittest.cc
new file mode 100644
index 0000000..28ea63a
--- /dev/null
+++ b/modules/audio_processing/ns/noise_suppressor_unittest.cc
@@ -0,0 +1,102 @@
+/*
+ *  Copyright (c) 2016 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/ns/noise_suppressor.h"
+
+#include <deque>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "rtc_base/strings/string_builder.h"
+#include "test/gmock.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+std::string ProduceDebugText(int sample_rate_hz,
+                             size_t num_channels,
+                             NsConfig::SuppressionLevel level) {
+  rtc::StringBuilder ss;
+  ss << "Sample rate: " << sample_rate_hz << ", num_channels: " << num_channels
+     << ", level: " << static_cast<int>(level);
+  return ss.Release();
+}
+
+void PopulateInputFrameWithIdenticalChannels(size_t num_channels,
+                                             size_t num_bands,
+                                             size_t frame_index,
+                                             AudioBuffer* audio) {
+  for (size_t ch = 0; ch < num_channels; ++ch) {
+    for (size_t b = 0; b < num_bands; ++b) {
+      for (size_t i = 0; i < 160; ++i) {
+        float value = static_cast<int>(frame_index * 160 + i);
+        audio->split_bands(ch)[b][i] = (value > 0 ? 5000 * b + value : 0);
+      }
+    }
+  }
+}
+
+void VerifyIdenticalChannels(size_t num_channels,
+                             size_t num_bands,
+                             size_t frame_index,
+                             const AudioBuffer& audio) {
+  EXPECT_GT(num_channels, 1u);
+  for (size_t ch = 1; ch < num_channels; ++ch) {
+    for (size_t b = 0; b < num_bands; ++b) {
+      for (size_t i = 0; i < 160; ++i) {
+        EXPECT_EQ(audio.split_bands_const(ch)[b][i],
+                  audio.split_bands_const(0)[b][i]);
+      }
+    }
+  }
+}
+
+}  // namespace
+
+// Verifies that the same noise reduction effect is applied to all channels.
+TEST(NoiseSuppressor, IdenticalChannelEffects) {
+  for (auto rate : {16000, 32000, 48000}) {
+    for (auto num_channels : {1, 4, 8}) {
+      for (auto level :
+           {NsConfig::SuppressionLevel::k6dB, NsConfig::SuppressionLevel::k12dB,
+            NsConfig::SuppressionLevel::k18dB,
+            NsConfig::SuppressionLevel::k21dB}) {
+        SCOPED_TRACE(ProduceDebugText(rate, num_channels, level));
+
+        const size_t num_bands = rate / 16000;
+        // const int frame_length = rtc::CheckedDivExact(rate, 100);
+        AudioBuffer audio(rate, num_channels, rate, num_channels, rate,
+                          num_channels);
+        NsConfig cfg;
+        NoiseSuppressor ns(cfg, rate, num_channels);
+        for (size_t frame_index = 0; frame_index < 1000; ++frame_index) {
+          if (rate > 16000) {
+            audio.SplitIntoFrequencyBands();
+          }
+
+          PopulateInputFrameWithIdenticalChannels(num_channels, num_bands,
+                                                  frame_index, &audio);
+
+          ns.Analyze(audio);
+          ns.Process(&audio);
+          if (num_channels > 1) {
+            VerifyIdenticalChannels(num_channels, num_bands, frame_index,
+                                    audio);
+          }
+        }
+      }
+    }
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/ns_common.h b/modules/audio_processing/ns/ns_common.h
new file mode 100644
index 0000000..d6149f7
--- /dev/null
+++ b/modules/audio_processing/ns/ns_common.h
@@ -0,0 +1,34 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_
+
+#include <cstddef>
+
+namespace webrtc {
+
+constexpr size_t kFftSize = 256;
+constexpr size_t kFftSizeBy2Plus1 = kFftSize / 2 + 1;
+constexpr size_t kNsFrameSize = 160;
+constexpr size_t kOverlapSize = kFftSize - kNsFrameSize;
+
+constexpr int kShortStartupPhaseBlocks = 50;
+constexpr int kLongStartupPhaseBlocks = 200;
+constexpr int kFeatureUpdateWindowSize = 500;
+
+constexpr float kLtrFeatureThr = 0.5f;
+constexpr float kBinSizeLrt = 0.1f;
+constexpr float kBinSizeSpecFlat = 0.05f;
+constexpr float kBinSizeSpecDiff = 0.1f;
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_NS_COMMON_H_
diff --git a/modules/audio_processing/ns/ns_config.h b/modules/audio_processing/ns/ns_config.h
new file mode 100644
index 0000000..0a285e9
--- /dev/null
+++ b/modules/audio_processing/ns/ns_config.h
@@ -0,0 +1,24 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_
+#define MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_
+
+namespace webrtc {
+
+// Config struct for the noise suppressor
+struct NsConfig {
+  enum class SuppressionLevel { k6dB, k12dB, k18dB, k21dB };
+  SuppressionLevel target_level = SuppressionLevel::k12dB;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_NS_CONFIG_H_
diff --git a/modules/audio_processing/ns/ns_fft.cc b/modules/audio_processing/ns/ns_fft.cc
new file mode 100644
index 0000000..8d1c43f
--- /dev/null
+++ b/modules/audio_processing/ns/ns_fft.cc
@@ -0,0 +1,64 @@
+/*
+ *  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/ns/ns_fft.h"
+
+#include "common_audio/third_party/fft4g/fft4g.h"
+
+namespace webrtc {
+
+NrFft::NrFft() : bit_reversal_state_(kFftSize / 2), tables_(kFftSize / 2) {
+  // Initialize WebRtc_rdt (setting (bit_reversal_state_[0] to 0 triggers
+  // initialization)
+  bit_reversal_state_[0] = 0.f;
+  std::array<float, kFftSize> tmp_buffer;
+  tmp_buffer.fill(0.f);
+  WebRtc_rdft(kFftSize, 1, tmp_buffer.data(), bit_reversal_state_.data(),
+              tables_.data());
+}
+
+void NrFft::Fft(rtc::ArrayView<float, kFftSize> time_data,
+                rtc::ArrayView<float, kFftSize> real,
+                rtc::ArrayView<float, kFftSize> imag) {
+  WebRtc_rdft(kFftSize, 1, time_data.data(), bit_reversal_state_.data(),
+              tables_.data());
+
+  imag[0] = 0;
+  real[0] = time_data[0];
+
+  imag[kFftSizeBy2Plus1 - 1] = 0;
+  real[kFftSizeBy2Plus1 - 1] = time_data[1];
+
+  for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) {
+    real[i] = time_data[2 * i];
+    imag[i] = time_data[2 * i + 1];
+  }
+}
+
+void NrFft::Ifft(rtc::ArrayView<const float> real,
+                 rtc::ArrayView<const float> imag,
+                 rtc::ArrayView<float> time_data) {
+  time_data[0] = real[0];
+  time_data[1] = real[kFftSizeBy2Plus1 - 1];
+  for (size_t i = 1; i < kFftSizeBy2Plus1 - 1; ++i) {
+    time_data[2 * i] = real[i];
+    time_data[2 * i + 1] = imag[i];
+  }
+  WebRtc_rdft(kFftSize, -1, time_data.data(), bit_reversal_state_.data(),
+              tables_.data());
+
+  // Scale the output
+  constexpr float kScaling = 2.f / kFftSize;
+  for (float& d : time_data) {
+    d *= kScaling;
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/ns_fft.h b/modules/audio_processing/ns/ns_fft.h
new file mode 100644
index 0000000..539251e
--- /dev/null
+++ b/modules/audio_processing/ns/ns_fft.h
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_
+#define MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_
+
+#include <vector>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+
+namespace webrtc {
+
+// Wrapper class providing 256 point FFT functionality.
+class NrFft {
+ public:
+  NrFft();
+  NrFft(const NrFft&) = delete;
+  NrFft& operator=(const NrFft&) = delete;
+
+  // Transforms the signal from time to frequency domain.
+  void Fft(rtc::ArrayView<float, kFftSize> time_data,
+           rtc::ArrayView<float, kFftSize> real,
+           rtc::ArrayView<float, kFftSize> imag);
+
+  // Transforms the signal from frequency to time domain.
+  void Ifft(rtc::ArrayView<const float> real,
+            rtc::ArrayView<const float> imag,
+            rtc::ArrayView<float> time_data);
+
+ private:
+  std::vector<size_t> bit_reversal_state_;
+  std::vector<float> tables_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_NS_FFT_H_
diff --git a/modules/audio_processing/ns/nsx_core.c b/modules/audio_processing/ns/nsx_core.c
deleted file mode 100644
index 8043656..0000000
--- a/modules/audio_processing/ns/nsx_core.c
+++ /dev/null
@@ -1,2107 +0,0 @@
-/*
- *  Copyright (c) 2012 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/ns/noise_suppression_x.h"
-
-#include <math.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "rtc_base/checks.h"
-#include "common_audio/signal_processing/include/real_fft.h"
-#include "modules/audio_processing/ns/nsx_core.h"
-#include "system_wrappers/include/cpu_features_wrapper.h"
-
-#if defined(WEBRTC_HAS_NEON)
-/* Tables are defined in ARM assembly files. */
-extern const int16_t WebRtcNsx_kLogTable[9];
-extern const int16_t WebRtcNsx_kCounterDiv[201];
-extern const int16_t WebRtcNsx_kLogTableFrac[256];
-#else
-static const int16_t WebRtcNsx_kLogTable[9] = {
-  0, 177, 355, 532, 710, 887, 1065, 1242, 1420
-};
-
-static const int16_t WebRtcNsx_kCounterDiv[201] = {
-  32767, 16384, 10923, 8192, 6554, 5461, 4681, 4096, 3641, 3277, 2979, 2731,
-  2521, 2341, 2185, 2048, 1928, 1820, 1725, 1638, 1560, 1489, 1425, 1365, 1311,
-  1260, 1214, 1170, 1130, 1092, 1057, 1024, 993, 964, 936, 910, 886, 862, 840,
-  819, 799, 780, 762, 745, 728, 712, 697, 683, 669, 655, 643, 630, 618, 607,
-  596, 585, 575, 565, 555, 546, 537, 529, 520, 512, 504, 496, 489, 482, 475,
-  468, 462, 455, 449, 443, 437, 431, 426, 420, 415, 410, 405, 400, 395, 390,
-  386, 381, 377, 372, 368, 364, 360, 356, 352, 349, 345, 341, 338, 334, 331,
-  328, 324, 321, 318, 315, 312, 309, 306, 303, 301, 298, 295, 293, 290, 287,
-  285, 282, 280, 278, 275, 273, 271, 269, 266, 264, 262, 260, 258, 256, 254,
-  252, 250, 248, 246, 245, 243, 241, 239, 237, 236, 234, 232, 231, 229, 228,
-  226, 224, 223, 221, 220, 218, 217, 216, 214, 213, 211, 210, 209, 207, 206,
-  205, 204, 202, 201, 200, 199, 197, 196, 195, 194, 193, 192, 191, 189, 188,
-  187, 186, 185, 184, 183, 182, 181, 180, 179, 178, 177, 176, 175, 174, 173,
-  172, 172, 171, 170, 169, 168, 167, 166, 165, 165, 164, 163
-};
-
-static const int16_t WebRtcNsx_kLogTableFrac[256] = {
-  0,   1,   3,   4,   6,   7,   9,  10,  11,  13,  14,  16,  17,  18,  20,  21,
-  22,  24,  25,  26,  28,  29,  30,  32,  33,  34,  36,  37,  38,  40,  41,  42,
-  44,  45,  46,  47,  49,  50,  51,  52,  54,  55,  56,  57,  59,  60,  61,  62,
-  63,  65,  66,  67,  68,  69,  71,  72,  73,  74,  75,  77,  78,  79,  80,  81,
-  82,  84,  85,  86,  87,  88,  89,  90,  92,  93,  94,  95,  96,  97,  98,  99,
-  100, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 116,
-  117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131,
-  132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
-  147, 148, 149, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160,
-  161, 162, 163, 164, 165, 166, 167, 168, 169, 169, 170, 171, 172, 173, 174,
-  175, 176, 177, 178, 178, 179, 180, 181, 182, 183, 184, 185, 185, 186, 187,
-  188, 189, 190, 191, 192, 192, 193, 194, 195, 196, 197, 198, 198, 199, 200,
-  201, 202, 203, 203, 204, 205, 206, 207, 208, 208, 209, 210, 211, 212, 212,
-  213, 214, 215, 216, 216, 217, 218, 219, 220, 220, 221, 222, 223, 224, 224,
-  225, 226, 227, 228, 228, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236,
-  237, 238, 238, 239, 240, 241, 241, 242, 243, 244, 244, 245, 246, 247, 247,
-  248, 249, 249, 250, 251, 252, 252, 253, 254, 255, 255
-};
-#endif  // WEBRTC_HAS_NEON
-
-// Skip first frequency bins during estimation. (0 <= value < 64)
-static const size_t kStartBand = 5;
-
-// hybrib Hanning & flat window
-static const int16_t kBlocks80w128x[128] = {
-  0,    536,   1072,   1606,   2139,   2669,   3196,   3720,   4240,   4756,   5266,
-  5771,   6270,   6762,   7246,   7723,   8192,   8652,   9102,   9543,   9974,  10394,
-  10803,  11200,  11585,  11958,  12318,  12665,  12998,  13318,  13623,  13913,  14189,
-  14449,  14694,  14924,  15137,  15334,  15515,  15679,  15826,  15956,  16069,  16165,
-  16244,  16305,  16349,  16375,  16384,  16384,  16384,  16384,  16384,  16384,  16384,
-  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,
-  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,  16384,
-  16384,  16384,  16384,  16384,  16375,  16349,  16305,  16244,  16165,  16069,  15956,
-  15826,  15679,  15515,  15334,  15137,  14924,  14694,  14449,  14189,  13913,  13623,
-  13318,  12998,  12665,  12318,  11958,  11585,  11200,  10803,  10394,   9974,   9543,
-  9102,   8652,   8192,   7723,   7246,   6762,   6270,   5771,   5266,   4756,   4240,
-  3720,   3196,   2669,   2139,   1606,   1072,    536
-};
-
-// hybrib Hanning & flat window
-static const int16_t kBlocks160w256x[256] = {
-  0,   268,   536,   804,  1072,  1339,  1606,  1872,
-  2139,  2404,  2669,  2933,  3196,  3459,  3720,  3981,
-  4240,  4499,  4756,  5012,  5266,  5520,  5771,  6021,
-  6270,  6517,  6762,  7005,  7246,  7486,  7723,  7959,
-  8192,  8423,  8652,  8878,  9102,  9324,  9543,  9760,
-  9974, 10185, 10394, 10600, 10803, 11003, 11200, 11394,
-  11585, 11773, 11958, 12140, 12318, 12493, 12665, 12833,
-  12998, 13160, 13318, 13472, 13623, 13770, 13913, 14053,
-  14189, 14321, 14449, 14574, 14694, 14811, 14924, 15032,
-  15137, 15237, 15334, 15426, 15515, 15599, 15679, 15754,
-  15826, 15893, 15956, 16015, 16069, 16119, 16165, 16207,
-  16244, 16277, 16305, 16329, 16349, 16364, 16375, 16382,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16384, 16384, 16384, 16384, 16384, 16384, 16384,
-  16384, 16382, 16375, 16364, 16349, 16329, 16305, 16277,
-  16244, 16207, 16165, 16119, 16069, 16015, 15956, 15893,
-  15826, 15754, 15679, 15599, 15515, 15426, 15334, 15237,
-  15137, 15032, 14924, 14811, 14694, 14574, 14449, 14321,
-  14189, 14053, 13913, 13770, 13623, 13472, 13318, 13160,
-  12998, 12833, 12665, 12493, 12318, 12140, 11958, 11773,
-  11585, 11394, 11200, 11003, 10803, 10600, 10394, 10185,
-  9974,  9760,  9543,  9324,  9102,  8878,  8652,  8423,
-  8192,  7959,  7723,  7486,  7246,  7005,  6762,  6517,
-  6270,  6021,  5771,  5520,  5266,  5012,  4756,  4499,
-  4240,  3981,  3720,  3459,  3196,  2933,  2669,  2404,
-  2139,  1872,  1606,  1339,  1072,   804,   536,   268
-};
-
-// Gain factor1 table: Input value in Q8 and output value in Q13
-// original floating point code
-//  if (gain > blim) {
-//    factor1 = 1.0 + 1.3 * (gain - blim);
-//    if (gain * factor1 > 1.0) {
-//      factor1 = 1.0 / gain;
-//    }
-//  } else {
-//    factor1 = 1.0;
-//  }
-static const int16_t kFactor1Table[257] = {
-  8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8233, 8274, 8315, 8355, 8396, 8436, 8475, 8515, 8554, 8592, 8631, 8669,
-  8707, 8745, 8783, 8820, 8857, 8894, 8931, 8967, 9003, 9039, 9075, 9111, 9146, 9181,
-  9216, 9251, 9286, 9320, 9354, 9388, 9422, 9456, 9489, 9523, 9556, 9589, 9622, 9655,
-  9687, 9719, 9752, 9784, 9816, 9848, 9879, 9911, 9942, 9973, 10004, 10035, 10066,
-  10097, 10128, 10158, 10188, 10218, 10249, 10279, 10308, 10338, 10368, 10397, 10426,
-  10456, 10485, 10514, 10543, 10572, 10600, 10629, 10657, 10686, 10714, 10742, 10770,
-  10798, 10826, 10854, 10882, 10847, 10810, 10774, 10737, 10701, 10666, 10631, 10596,
-  10562, 10527, 10494, 10460, 10427, 10394, 10362, 10329, 10297, 10266, 10235, 10203,
-  10173, 10142, 10112, 10082, 10052, 10023, 9994, 9965, 9936, 9908, 9879, 9851, 9824,
-  9796, 9769, 9742, 9715, 9689, 9662, 9636, 9610, 9584, 9559, 9534, 9508, 9484, 9459,
-  9434, 9410, 9386, 9362, 9338, 9314, 9291, 9268, 9245, 9222, 9199, 9176, 9154, 9132,
-  9110, 9088, 9066, 9044, 9023, 9002, 8980, 8959, 8939, 8918, 8897, 8877, 8857, 8836,
-  8816, 8796, 8777, 8757, 8738, 8718, 8699, 8680, 8661, 8642, 8623, 8605, 8586, 8568,
-  8550, 8532, 8514, 8496, 8478, 8460, 8443, 8425, 8408, 8391, 8373, 8356, 8339, 8323,
-  8306, 8289, 8273, 8256, 8240, 8224, 8208, 8192
-};
-
-// For Factor2 tables
-// original floating point code
-// if (gain > blim) {
-//   factor2 = 1.0;
-// } else {
-//   factor2 = 1.0 - 0.3 * (blim - gain);
-//   if (gain <= inst->denoiseBound) {
-//     factor2 = 1.0 - 0.3 * (blim - inst->denoiseBound);
-//   }
-// }
-//
-// Gain factor table: Input value in Q8 and output value in Q13
-static const int16_t kFactor2Aggressiveness1[257] = {
-  7577, 7577, 7577, 7577, 7577, 7577,
-  7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7577, 7596, 7614, 7632,
-  7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
-  7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
-  8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
-  8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
-};
-
-// Gain factor table: Input value in Q8 and output value in Q13
-static const int16_t kFactor2Aggressiveness2[257] = {
-  7270, 7270, 7270, 7270, 7270, 7306,
-  7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632,
-  7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
-  7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
-  8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
-  8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
-};
-
-// Gain factor table: Input value in Q8 and output value in Q13
-static const int16_t kFactor2Aggressiveness3[257] = {
-  7184, 7184, 7184, 7229, 7270, 7306,
-  7339, 7369, 7397, 7424, 7448, 7472, 7495, 7517, 7537, 7558, 7577, 7596, 7614, 7632,
-  7650, 7667, 7683, 7699, 7715, 7731, 7746, 7761, 7775, 7790, 7804, 7818, 7832, 7845,
-  7858, 7871, 7884, 7897, 7910, 7922, 7934, 7946, 7958, 7970, 7982, 7993, 8004, 8016,
-  8027, 8038, 8049, 8060, 8070, 8081, 8091, 8102, 8112, 8122, 8132, 8143, 8152, 8162,
-  8172, 8182, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192,
-  8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192, 8192
-};
-
-// sum of log2(i) from table index to inst->anaLen2 in Q5
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kSumLogIndex[66] = {
-  0,  22917,  22917,  22885,  22834,  22770,  22696,  22613,
-  22524,  22428,  22326,  22220,  22109,  21994,  21876,  21754,
-  21629,  21501,  21370,  21237,  21101,  20963,  20822,  20679,
-  20535,  20388,  20239,  20089,  19937,  19783,  19628,  19470,
-  19312,  19152,  18991,  18828,  18664,  18498,  18331,  18164,
-  17994,  17824,  17653,  17480,  17306,  17132,  16956,  16779,
-  16602,  16423,  16243,  16063,  15881,  15699,  15515,  15331,
-  15146,  14960,  14774,  14586,  14398,  14209,  14019,  13829,
-  13637,  13445
-};
-
-// sum of log2(i)^2 from table index to inst->anaLen2 in Q2
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kSumSquareLogIndex[66] = {
-  0,  16959,  16959,  16955,  16945,  16929,  16908,  16881,
-  16850,  16814,  16773,  16729,  16681,  16630,  16575,  16517,
-  16456,  16392,  16325,  16256,  16184,  16109,  16032,  15952,
-  15870,  15786,  15700,  15612,  15521,  15429,  15334,  15238,
-  15140,  15040,  14938,  14834,  14729,  14622,  14514,  14404,
-  14292,  14179,  14064,  13947,  13830,  13710,  13590,  13468,
-  13344,  13220,  13094,  12966,  12837,  12707,  12576,  12444,
-  12310,  12175,  12039,  11902,  11763,  11624,  11483,  11341,
-  11198,  11054
-};
-
-// log2(table index) in Q12
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kLogIndex[129] = {
-  0,      0,   4096,   6492,   8192,   9511,  10588,  11499,
-  12288,  12984,  13607,  14170,  14684,  15157,  15595,  16003,
-  16384,  16742,  17080,  17400,  17703,  17991,  18266,  18529,
-  18780,  19021,  19253,  19476,  19691,  19898,  20099,  20292,
-  20480,  20662,  20838,  21010,  21176,  21338,  21496,  21649,
-  21799,  21945,  22087,  22226,  22362,  22495,  22625,  22752,
-  22876,  22998,  23117,  23234,  23349,  23462,  23572,  23680,
-  23787,  23892,  23994,  24095,  24195,  24292,  24388,  24483,
-  24576,  24668,  24758,  24847,  24934,  25021,  25106,  25189,
-  25272,  25354,  25434,  25513,  25592,  25669,  25745,  25820,
-  25895,  25968,  26041,  26112,  26183,  26253,  26322,  26390,
-  26458,  26525,  26591,  26656,  26721,  26784,  26848,  26910,
-  26972,  27033,  27094,  27154,  27213,  27272,  27330,  27388,
-  27445,  27502,  27558,  27613,  27668,  27722,  27776,  27830,
-  27883,  27935,  27988,  28039,  28090,  28141,  28191,  28241,
-  28291,  28340,  28388,  28437,  28484,  28532,  28579,  28626,
-  28672
-};
-
-// determinant of estimation matrix in Q0 corresponding to the log2 tables above
-// Note that the first table value is invalid, since log2(0) = -infinity
-static const int16_t kDeterminantEstMatrix[66] = {
-  0,  29814,  25574,  22640,  20351,  18469,  16873,  15491,
-  14277,  13199,  12233,  11362,  10571,   9851,   9192,   8587,
-  8030,   7515,   7038,   6596,   6186,   5804,   5448,   5115,
-  4805,   4514,   4242,   3988,   3749,   3524,   3314,   3116,
-  2930,   2755,   2590,   2435,   2289,   2152,   2022,   1900,
-  1785,   1677,   1575,   1478,   1388,   1302,   1221,   1145,
-  1073,   1005,    942,    881,    825,    771,    721,    674,
-  629,    587,    547,    510,    475,    442,    411,    382,
-  355,    330
-};
-
-// Update the noise estimation information.
-static void UpdateNoiseEstimate(NoiseSuppressionFixedC* inst, int offset) {
-  int32_t tmp32no1 = 0;
-  int32_t tmp32no2 = 0;
-  int16_t tmp16 = 0;
-  const int16_t kExp2Const = 11819; // Q13
-
-  size_t i = 0;
-
-  tmp16 = WebRtcSpl_MaxValueW16(inst->noiseEstLogQuantile + offset,
-                                   inst->magnLen);
-  // Guarantee a Q-domain as high as possible and still fit in int16
-  inst->qNoise = 14 - (int) WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-                   kExp2Const, tmp16, 21);
-  for (i = 0; i < inst->magnLen; i++) {
-    // inst->quantile[i]=exp(inst->lquantile[offset+i]);
-    // in Q21
-    tmp32no2 = kExp2Const * inst->noiseEstLogQuantile[offset + i];
-    tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac
-    tmp16 = (int16_t)(tmp32no2 >> 21);
-    tmp16 -= 21;// shift 21 to get result in Q0
-    tmp16 += (int16_t) inst->qNoise; //shift to get result in Q(qNoise)
-    if (tmp16 < 0) {
-      tmp32no1 >>= -tmp16;
-    } else {
-      tmp32no1 <<= tmp16;
-    }
-    inst->noiseEstQuantile[i] = WebRtcSpl_SatW32ToW16(tmp32no1);
-  }
-}
-
-// Noise Estimation
-static void NoiseEstimationC(NoiseSuppressionFixedC* inst,
-                             uint16_t* magn,
-                             uint32_t* noise,
-                             int16_t* q_noise) {
-  int16_t lmagn[HALF_ANAL_BLOCKL], counter, countDiv;
-  int16_t countProd, delta, zeros, frac;
-  int16_t log2, tabind, logval, tmp16, tmp16no1, tmp16no2;
-  const int16_t log2_const = 22713; // Q15
-  const int16_t width_factor = 21845;
-
-  size_t i, s, offset;
-
-  tabind = inst->stages - inst->normData;
-  RTC_DCHECK_LT(tabind, 9);
-  RTC_DCHECK_GT(tabind, -9);
-  if (tabind < 0) {
-    logval = -WebRtcNsx_kLogTable[-tabind];
-  } else {
-    logval = WebRtcNsx_kLogTable[tabind];
-  }
-
-  // lmagn(i)=log(magn(i))=log(2)*log2(magn(i))
-  // magn is in Q(-stages), and the real lmagn values are:
-  // real_lmagn(i)=log(magn(i)*2^stages)=log(magn(i))+log(2^stages)
-  // lmagn in Q8
-  for (i = 0; i < inst->magnLen; i++) {
-    if (magn[i]) {
-      zeros = WebRtcSpl_NormU32((uint32_t)magn[i]);
-      frac = (int16_t)((((uint32_t)magn[i] << zeros)
-                              & 0x7FFFFFFF) >> 23);
-      // log2(magn(i))
-      RTC_DCHECK_LT(frac, 256);
-      log2 = (int16_t)(((31 - zeros) << 8)
-                             + WebRtcNsx_kLogTableFrac[frac]);
-      // log2(magn(i))*log(2)
-      lmagn[i] = (int16_t)((log2 * log2_const) >> 15);
-      // + log(2^stages)
-      lmagn[i] += logval;
-    } else {
-      lmagn[i] = logval;//0;
-    }
-  }
-
-  // loop over simultaneous estimates
-  for (s = 0; s < SIMULT; s++) {
-    offset = s * inst->magnLen;
-
-    // Get counter values from state
-    counter = inst->noiseEstCounter[s];
-    RTC_DCHECK_LT(counter, 201);
-    countDiv = WebRtcNsx_kCounterDiv[counter];
-    countProd = (int16_t)(counter * countDiv);
-
-    // quant_est(...)
-    for (i = 0; i < inst->magnLen; i++) {
-      // compute delta
-      if (inst->noiseEstDensity[offset + i] > 512) {
-        // Get the value for delta by shifting intead of dividing.
-        int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i]);
-        delta = (int16_t)(FACTOR_Q16 >> (14 - factor));
-      } else {
-        delta = FACTOR_Q7;
-        if (inst->blockIndex < END_STARTUP_LONG) {
-          // Smaller step size during startup. This prevents from using
-          // unrealistic values causing overflow.
-          delta = FACTOR_Q7_STARTUP;
-        }
-      }
-
-      // update log quantile estimate
-      tmp16 = (int16_t)((delta * countDiv) >> 14);
-      if (lmagn[i] > inst->noiseEstLogQuantile[offset + i]) {
-        // +=QUANTILE*delta/(inst->counter[s]+1) QUANTILE=0.25, =1 in Q2
-        // CounterDiv=1/(inst->counter[s]+1) in Q15
-        tmp16 += 2;
-        inst->noiseEstLogQuantile[offset + i] += tmp16 / 4;
-      } else {
-        tmp16 += 1;
-        // *(1-QUANTILE), in Q2 QUANTILE=0.25, 1-0.25=0.75=3 in Q2
-        // TODO(bjornv): investigate why we need to truncate twice.
-        tmp16no2 = (int16_t)((tmp16 / 2) * 3 / 2);
-        inst->noiseEstLogQuantile[offset + i] -= tmp16no2;
-        if (inst->noiseEstLogQuantile[offset + i] < logval) {
-          // This is the smallest fixed point representation we can
-          // have, hence we limit the output.
-          inst->noiseEstLogQuantile[offset + i] = logval;
-        }
-      }
-
-      // update density estimate
-      if (WEBRTC_SPL_ABS_W16(lmagn[i] - inst->noiseEstLogQuantile[offset + i])
-          < WIDTH_Q8) {
-        tmp16no1 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-                     inst->noiseEstDensity[offset + i], countProd, 15);
-        tmp16no2 = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-                     width_factor, countDiv, 15);
-        inst->noiseEstDensity[offset + i] = tmp16no1 + tmp16no2;
-      }
-    }  // end loop over magnitude spectrum
-
-    if (counter >= END_STARTUP_LONG) {
-      inst->noiseEstCounter[s] = 0;
-      if (inst->blockIndex >= END_STARTUP_LONG) {
-        UpdateNoiseEstimate(inst, offset);
-      }
-    }
-    inst->noiseEstCounter[s]++;
-
-  }  // end loop over simultaneous estimates
-
-  // Sequentially update the noise during startup
-  if (inst->blockIndex < END_STARTUP_LONG) {
-    UpdateNoiseEstimate(inst, offset);
-  }
-
-  for (i = 0; i < inst->magnLen; i++) {
-    noise[i] = (uint32_t)(inst->noiseEstQuantile[i]); // Q(qNoise)
-  }
-  (*q_noise) = (int16_t)inst->qNoise;
-}
-
-// Filter the data in the frequency domain, and create spectrum.
-static void PrepareSpectrumC(NoiseSuppressionFixedC* inst, int16_t* freq_buf) {
-  size_t i = 0, j = 0;
-
-  for (i = 0; i < inst->magnLen; i++) {
-    inst->real[i] = (int16_t)((inst->real[i] *
-        (int16_t)(inst->noiseSupFilter[i])) >> 14);  // Q(normData-stages)
-    inst->imag[i] = (int16_t)((inst->imag[i] *
-        (int16_t)(inst->noiseSupFilter[i])) >> 14);  // Q(normData-stages)
-  }
-
-  freq_buf[0] = inst->real[0];
-  freq_buf[1] = -inst->imag[0];
-  for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
-    freq_buf[j] = inst->real[i];
-    freq_buf[j + 1] = -inst->imag[i];
-  }
-  freq_buf[inst->anaLen] = inst->real[inst->anaLen2];
-  freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2];
-}
-
-// Denormalize the real-valued signal |in|, the output from inverse FFT.
-static void DenormalizeC(NoiseSuppressionFixedC* inst,
-                         int16_t* in,
-                         int factor) {
-  size_t i = 0;
-  int32_t tmp32 = 0;
-  for (i = 0; i < inst->anaLen; i += 1) {
-    tmp32 = WEBRTC_SPL_SHIFT_W32((int32_t)in[i],
-                                 factor - inst->normData);
-    inst->real[i] = WebRtcSpl_SatW32ToW16(tmp32); // Q0
-  }
-}
-
-// For the noise supression process, synthesis, read out fully processed
-// segment, and update synthesis buffer.
-static void SynthesisUpdateC(NoiseSuppressionFixedC* inst,
-                             int16_t* out_frame,
-                             int16_t gain_factor) {
-  size_t i = 0;
-  int16_t tmp16a = 0;
-  int16_t tmp16b = 0;
-  int32_t tmp32 = 0;
-
-  // synthesis
-  for (i = 0; i < inst->anaLen; i++) {
-    tmp16a = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-                 inst->window[i], inst->real[i], 14); // Q0, window in Q14
-    tmp32 = WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(tmp16a, gain_factor, 13); // Q0
-    // Down shift with rounding
-    tmp16b = WebRtcSpl_SatW32ToW16(tmp32); // Q0
-    inst->synthesisBuffer[i] = WebRtcSpl_AddSatW16(inst->synthesisBuffer[i],
-                                                   tmp16b); // Q0
-  }
-
-  // read out fully processed segment
-  for (i = 0; i < inst->blockLen10ms; i++) {
-    out_frame[i] = inst->synthesisBuffer[i]; // Q0
-  }
-
-  // update synthesis buffer
-  memcpy(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
-      (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->synthesisBuffer));
-  WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer
-      + inst->anaLen - inst->blockLen10ms, inst->blockLen10ms);
-}
-
-// Update analysis buffer for lower band, and window data before FFT.
-static void AnalysisUpdateC(NoiseSuppressionFixedC* inst,
-                            int16_t* out,
-                            int16_t* new_speech) {
-  size_t i = 0;
-
-  // For lower band update analysis buffer.
-  memcpy(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms,
-      (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->analysisBuffer));
-  memcpy(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms, new_speech,
-      inst->blockLen10ms * sizeof(*inst->analysisBuffer));
-
-  // Window data before FFT.
-  for (i = 0; i < inst->anaLen; i++) {
-    out[i] = (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
-               inst->window[i], inst->analysisBuffer[i], 14); // Q0
-  }
-}
-
-// Normalize the real-valued signal |in|, the input to forward FFT.
-static void NormalizeRealBufferC(NoiseSuppressionFixedC* inst,
-                                 const int16_t* in,
-                                 int16_t* out) {
-  size_t i = 0;
-  RTC_DCHECK_GE(inst->normData, 0);
-  for (i = 0; i < inst->anaLen; ++i) {
-    out[i] = in[i] << inst->normData;  // Q(normData)
-  }
-}
-
-// Declare function pointers.
-NoiseEstimation WebRtcNsx_NoiseEstimation;
-PrepareSpectrum WebRtcNsx_PrepareSpectrum;
-SynthesisUpdate WebRtcNsx_SynthesisUpdate;
-AnalysisUpdate WebRtcNsx_AnalysisUpdate;
-Denormalize WebRtcNsx_Denormalize;
-NormalizeRealBuffer WebRtcNsx_NormalizeRealBuffer;
-
-#if defined(WEBRTC_HAS_NEON)
-// Initialize function pointers for ARM Neon platform.
-static void WebRtcNsx_InitNeon(void) {
-  WebRtcNsx_NoiseEstimation = WebRtcNsx_NoiseEstimationNeon;
-  WebRtcNsx_PrepareSpectrum = WebRtcNsx_PrepareSpectrumNeon;
-  WebRtcNsx_SynthesisUpdate = WebRtcNsx_SynthesisUpdateNeon;
-  WebRtcNsx_AnalysisUpdate = WebRtcNsx_AnalysisUpdateNeon;
-}
-#endif
-
-#if defined(MIPS32_LE)
-// Initialize function pointers for MIPS platform.
-static void WebRtcNsx_InitMips(void) {
-  WebRtcNsx_PrepareSpectrum = WebRtcNsx_PrepareSpectrum_mips;
-  WebRtcNsx_SynthesisUpdate = WebRtcNsx_SynthesisUpdate_mips;
-  WebRtcNsx_AnalysisUpdate = WebRtcNsx_AnalysisUpdate_mips;
-  WebRtcNsx_NormalizeRealBuffer = WebRtcNsx_NormalizeRealBuffer_mips;
-#if defined(MIPS_DSP_R1_LE)
-  WebRtcNsx_Denormalize = WebRtcNsx_Denormalize_mips;
-#endif
-}
-#endif
-
-void WebRtcNsx_CalcParametricNoiseEstimate(NoiseSuppressionFixedC* inst,
-                                           int16_t pink_noise_exp_avg,
-                                           int32_t pink_noise_num_avg,
-                                           int freq_index,
-                                           uint32_t* noise_estimate,
-                                           uint32_t* noise_estimate_avg) {
-  int32_t tmp32no1 = 0;
-  int32_t tmp32no2 = 0;
-
-  int16_t int_part = 0;
-  int16_t frac_part = 0;
-
-  // Use pink noise estimate
-  // noise_estimate = 2^(pinkNoiseNumerator + pinkNoiseExp * log2(j))
-  RTC_DCHECK_GE(freq_index, 0);
-  RTC_DCHECK_LT(freq_index, 129);
-  tmp32no2 = (pink_noise_exp_avg * kLogIndex[freq_index]) >> 15;  // Q11
-  tmp32no1 = pink_noise_num_avg - tmp32no2; // Q11
-
-  // Calculate output: 2^tmp32no1
-  // Output in Q(minNorm-stages)
-  tmp32no1 += (inst->minNorm - inst->stages) << 11;
-  if (tmp32no1 > 0) {
-    int_part = (int16_t)(tmp32no1 >> 11);
-    frac_part = (int16_t)(tmp32no1 & 0x000007ff); // Q11
-    // Piecewise linear approximation of 'b' in
-    // 2^(int_part+frac_part) = 2^int_part * (1 + b)
-    // 'b' is given in Q11 and below stored in frac_part.
-    if (frac_part >> 10) {
-      // Upper fractional part
-      tmp32no2 = (2048 - frac_part) * 1244;  // Q21
-      tmp32no2 = 2048 - (tmp32no2 >> 10);
-    } else {
-      // Lower fractional part
-      tmp32no2 = (frac_part * 804) >> 10;
-    }
-    // Shift fractional part to Q(minNorm-stages)
-    tmp32no2 = WEBRTC_SPL_SHIFT_W32(tmp32no2, int_part - 11);
-    *noise_estimate_avg = (1 << int_part) + (uint32_t)tmp32no2;
-    // Scale up to initMagnEst, which is not block averaged
-    *noise_estimate = (*noise_estimate_avg) * (uint32_t)(inst->blockIndex + 1);
-  }
-}
-
-// Initialize state
-int32_t WebRtcNsx_InitCore(NoiseSuppressionFixedC* inst, uint32_t fs) {
-  int i;
-
-  //check for valid pointer
-  if (inst == NULL) {
-    return -1;
-  }
-  //
-
-  // Initialization of struct
-  if (fs == 8000 || fs == 16000 || fs == 32000 || fs == 48000) {
-    inst->fs = fs;
-  } else {
-    return -1;
-  }
-
-  if (fs == 8000) {
-    inst->blockLen10ms = 80;
-    inst->anaLen = 128;
-    inst->stages = 7;
-    inst->window = kBlocks80w128x;
-    inst->thresholdLogLrt = 131072; //default threshold for LRT feature
-    inst->maxLrt = 0x0040000;
-    inst->minLrt = 52429;
-  } else {
-    inst->blockLen10ms = 160;
-    inst->anaLen = 256;
-    inst->stages = 8;
-    inst->window = kBlocks160w256x;
-    inst->thresholdLogLrt = 212644; //default threshold for LRT feature
-    inst->maxLrt = 0x0080000;
-    inst->minLrt = 104858;
-  }
-  inst->anaLen2 = inst->anaLen / 2;
-  inst->magnLen = inst->anaLen2 + 1;
-
-  if (inst->real_fft != NULL) {
-    WebRtcSpl_FreeRealFFT(inst->real_fft);
-  }
-  inst->real_fft = WebRtcSpl_CreateRealFFT(inst->stages);
-  if (inst->real_fft == NULL) {
-    return -1;
-  }
-
-  WebRtcSpl_ZerosArrayW16(inst->analysisBuffer, ANAL_BLOCKL_MAX);
-  WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer, ANAL_BLOCKL_MAX);
-
-  // for HB processing
-  WebRtcSpl_ZerosArrayW16(inst->dataBufHBFX[0],
-                          NUM_HIGH_BANDS_MAX * ANAL_BLOCKL_MAX);
-  // for quantile noise estimation
-  WebRtcSpl_ZerosArrayW16(inst->noiseEstQuantile, HALF_ANAL_BLOCKL);
-  for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
-    inst->noiseEstLogQuantile[i] = 2048; // Q8
-    inst->noiseEstDensity[i] = 153; // Q9
-  }
-  for (i = 0; i < SIMULT; i++) {
-    inst->noiseEstCounter[i] = (int16_t)(END_STARTUP_LONG * (i + 1)) / SIMULT;
-  }
-
-  // Initialize suppression filter with ones
-  WebRtcSpl_MemSetW16((int16_t*)inst->noiseSupFilter, 16384, HALF_ANAL_BLOCKL);
-
-  // Set the aggressiveness: default
-  inst->aggrMode = 0;
-
-  //initialize variables for new method
-  inst->priorNonSpeechProb = 8192; // Q14(0.5) prior probability for speech/noise
-  for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
-    inst->prevMagnU16[i] = 0;
-    inst->prevNoiseU32[i] = 0; //previous noise-spectrum
-    inst->logLrtTimeAvgW32[i] = 0; //smooth LR ratio
-    inst->avgMagnPause[i] = 0; //conservative noise spectrum estimate
-    inst->initMagnEst[i] = 0; //initial average magnitude spectrum
-  }
-
-  //feature quantities
-  inst->thresholdSpecDiff = 50; //threshold for difference feature: determined on-line
-  inst->thresholdSpecFlat = 20480; //threshold for flatness: determined on-line
-  inst->featureLogLrt = inst->thresholdLogLrt; //average LRT factor (= threshold)
-  inst->featureSpecFlat = inst->thresholdSpecFlat; //spectral flatness (= threshold)
-  inst->featureSpecDiff = inst->thresholdSpecDiff; //spectral difference (= threshold)
-  inst->weightLogLrt = 6; //default weighting par for LRT feature
-  inst->weightSpecFlat = 0; //default weighting par for spectral flatness feature
-  inst->weightSpecDiff = 0; //default weighting par for spectral difference feature
-
-  inst->curAvgMagnEnergy = 0; //window time-average of input magnitude spectrum
-  inst->timeAvgMagnEnergy = 0; //normalization for spectral difference
-  inst->timeAvgMagnEnergyTmp = 0; //normalization for spectral difference
-
-  //histogram quantities: used to estimate/update thresholds for features
-  WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
-  WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
-  WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
-
-  inst->blockIndex = -1; //frame counter
-
-  //inst->modelUpdate    = 500;   //window for update
-  inst->modelUpdate = (1 << STAT_UPDATES); //window for update
-  inst->cntThresUpdate = 0; //counter feature thresholds updates
-
-  inst->sumMagn = 0;
-  inst->magnEnergy = 0;
-  inst->prevQMagn = 0;
-  inst->qNoise = 0;
-  inst->prevQNoise = 0;
-
-  inst->energyIn = 0;
-  inst->scaleEnergyIn = 0;
-
-  inst->whiteNoiseLevel = 0;
-  inst->pinkNoiseNumerator = 0;
-  inst->pinkNoiseExp = 0;
-  inst->minNorm = 15; // Start with full scale
-  inst->zeroInputSignal = 0;
-
-  //default mode
-  WebRtcNsx_set_policy_core(inst, 0);
-
-#ifdef NS_FILEDEBUG
-  inst->infile = fopen("indebug.pcm", "wb");
-  inst->outfile = fopen("outdebug.pcm", "wb");
-  inst->file1 = fopen("file1.pcm", "wb");
-  inst->file2 = fopen("file2.pcm", "wb");
-  inst->file3 = fopen("file3.pcm", "wb");
-  inst->file4 = fopen("file4.pcm", "wb");
-  inst->file5 = fopen("file5.pcm", "wb");
-#endif
-
-  // Initialize function pointers.
-  WebRtcNsx_NoiseEstimation = NoiseEstimationC;
-  WebRtcNsx_PrepareSpectrum = PrepareSpectrumC;
-  WebRtcNsx_SynthesisUpdate = SynthesisUpdateC;
-  WebRtcNsx_AnalysisUpdate = AnalysisUpdateC;
-  WebRtcNsx_Denormalize = DenormalizeC;
-  WebRtcNsx_NormalizeRealBuffer = NormalizeRealBufferC;
-
-#if defined(WEBRTC_HAS_NEON)
-  WebRtcNsx_InitNeon();
-#endif
-
-#if defined(MIPS32_LE)
-  WebRtcNsx_InitMips();
-#endif
-
-  inst->initFlag = 1;
-
-  return 0;
-}
-
-int WebRtcNsx_set_policy_core(NoiseSuppressionFixedC* inst, int mode) {
-  // allow for modes:0,1,2,3
-  if (mode < 0 || mode > 3) {
-    return -1;
-  }
-
-  inst->aggrMode = mode;
-  if (mode == 0) {
-    inst->overdrive = 256; // Q8(1.0)
-    inst->denoiseBound = 8192; // Q14(0.5)
-    inst->gainMap = 0; // No gain compensation
-  } else if (mode == 1) {
-    inst->overdrive = 256; // Q8(1.0)
-    inst->denoiseBound = 4096; // Q14(0.25)
-    inst->factor2Table = kFactor2Aggressiveness1;
-    inst->gainMap = 1;
-  } else if (mode == 2) {
-    inst->overdrive = 282; // ~= Q8(1.1)
-    inst->denoiseBound = 2048; // Q14(0.125)
-    inst->factor2Table = kFactor2Aggressiveness2;
-    inst->gainMap = 1;
-  } else if (mode == 3) {
-    inst->overdrive = 320; // Q8(1.25)
-    inst->denoiseBound = 1475; // ~= Q14(0.09)
-    inst->factor2Table = kFactor2Aggressiveness3;
-    inst->gainMap = 1;
-  }
-  return 0;
-}
-
-// Extract thresholds for feature parameters
-// histograms are computed over some window_size (given by window_pars)
-// thresholds and weights are extracted every window
-// flag 0 means update histogram only, flag 1 means compute the thresholds/weights
-// threshold and weights are returned in: inst->priorModelPars
-void WebRtcNsx_FeatureParameterExtraction(NoiseSuppressionFixedC* inst,
-                                          int flag) {
-  uint32_t tmpU32;
-  uint32_t histIndex;
-  uint32_t posPeak1SpecFlatFX, posPeak2SpecFlatFX;
-  uint32_t posPeak1SpecDiffFX, posPeak2SpecDiffFX;
-
-  int32_t tmp32;
-  int32_t fluctLrtFX, thresFluctLrtFX;
-  int32_t avgHistLrtFX, avgSquareHistLrtFX, avgHistLrtComplFX;
-
-  int16_t j;
-  int16_t numHistLrt;
-
-  int i;
-  int useFeatureSpecFlat, useFeatureSpecDiff, featureSum;
-  int maxPeak1, maxPeak2;
-  int weightPeak1SpecFlat, weightPeak2SpecFlat;
-  int weightPeak1SpecDiff, weightPeak2SpecDiff;
-
-  //update histograms
-  if (!flag) {
-    // LRT
-    // Type casting to UWord32 is safe since negative values will not be wrapped to larger
-    // values than HIST_PAR_EST
-    histIndex = (uint32_t)(inst->featureLogLrt);
-    if (histIndex < HIST_PAR_EST) {
-      inst->histLrt[histIndex]++;
-    }
-    // Spectral flatness
-    // (inst->featureSpecFlat*20)>>10 = (inst->featureSpecFlat*5)>>8
-    histIndex = (inst->featureSpecFlat * 5) >> 8;
-    if (histIndex < HIST_PAR_EST) {
-      inst->histSpecFlat[histIndex]++;
-    }
-    // Spectral difference
-    histIndex = HIST_PAR_EST;
-    if (inst->timeAvgMagnEnergy > 0) {
-      // Guard against division by zero
-      // If timeAvgMagnEnergy == 0 we have no normalizing statistics and
-      // therefore can't update the histogram
-      histIndex = ((inst->featureSpecDiff * 5) >> inst->stages) /
-          inst->timeAvgMagnEnergy;
-    }
-    if (histIndex < HIST_PAR_EST) {
-      inst->histSpecDiff[histIndex]++;
-    }
-  }
-
-  // extract parameters for speech/noise probability
-  if (flag) {
-    useFeatureSpecDiff = 1;
-    //for LRT feature:
-    // compute the average over inst->featureExtractionParams.rangeAvgHistLrt
-    avgHistLrtFX = 0;
-    avgSquareHistLrtFX = 0;
-    numHistLrt = 0;
-    for (i = 0; i < BIN_SIZE_LRT; i++) {
-      j = (2 * i + 1);
-      tmp32 = inst->histLrt[i] * j;
-      avgHistLrtFX += tmp32;
-      numHistLrt += inst->histLrt[i];
-      avgSquareHistLrtFX += tmp32 * j;
-    }
-    avgHistLrtComplFX = avgHistLrtFX;
-    for (; i < HIST_PAR_EST; i++) {
-      j = (2 * i + 1);
-      tmp32 = inst->histLrt[i] * j;
-      avgHistLrtComplFX += tmp32;
-      avgSquareHistLrtFX += tmp32 * j;
-    }
-    fluctLrtFX = avgSquareHistLrtFX * numHistLrt -
-        avgHistLrtFX * avgHistLrtComplFX;
-    thresFluctLrtFX = THRES_FLUCT_LRT * numHistLrt;
-    // get threshold for LRT feature:
-    tmpU32 = (FACTOR_1_LRT_DIFF * (uint32_t)avgHistLrtFX);
-    if ((fluctLrtFX < thresFluctLrtFX) || (numHistLrt == 0) ||
-        (tmpU32 > (uint32_t)(100 * numHistLrt))) {
-      //very low fluctuation, so likely noise
-      inst->thresholdLogLrt = inst->maxLrt;
-    } else {
-      tmp32 = (int32_t)((tmpU32 << (9 + inst->stages)) / numHistLrt /
-                              25);
-      // check if value is within min/max range
-      inst->thresholdLogLrt = WEBRTC_SPL_SAT(inst->maxLrt,
-                                             tmp32,
-                                             inst->minLrt);
-    }
-    if (fluctLrtFX < thresFluctLrtFX) {
-      // Do not use difference feature if fluctuation of LRT feature is very low:
-      // most likely just noise state
-      useFeatureSpecDiff = 0;
-    }
-
-    // for spectral flatness and spectral difference: compute the main peaks of histogram
-    maxPeak1 = 0;
-    maxPeak2 = 0;
-    posPeak1SpecFlatFX = 0;
-    posPeak2SpecFlatFX = 0;
-    weightPeak1SpecFlat = 0;
-    weightPeak2SpecFlat = 0;
-
-    // peaks for flatness
-    for (i = 0; i < HIST_PAR_EST; i++) {
-      if (inst->histSpecFlat[i] > maxPeak1) {
-        // Found new "first" peak
-        maxPeak2 = maxPeak1;
-        weightPeak2SpecFlat = weightPeak1SpecFlat;
-        posPeak2SpecFlatFX = posPeak1SpecFlatFX;
-
-        maxPeak1 = inst->histSpecFlat[i];
-        weightPeak1SpecFlat = inst->histSpecFlat[i];
-        posPeak1SpecFlatFX = (uint32_t)(2 * i + 1);
-      } else if (inst->histSpecFlat[i] > maxPeak2) {
-        // Found new "second" peak
-        maxPeak2 = inst->histSpecFlat[i];
-        weightPeak2SpecFlat = inst->histSpecFlat[i];
-        posPeak2SpecFlatFX = (uint32_t)(2 * i + 1);
-      }
-    }
-
-    // for spectral flatness feature
-    useFeatureSpecFlat = 1;
-    // merge the two peaks if they are close
-    if ((posPeak1SpecFlatFX - posPeak2SpecFlatFX < LIM_PEAK_SPACE_FLAT_DIFF)
-        && (weightPeak2SpecFlat * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecFlat)) {
-      weightPeak1SpecFlat += weightPeak2SpecFlat;
-      posPeak1SpecFlatFX = (posPeak1SpecFlatFX + posPeak2SpecFlatFX) >> 1;
-    }
-    //reject if weight of peaks is not large enough, or peak value too small
-    if (weightPeak1SpecFlat < THRES_WEIGHT_FLAT_DIFF || posPeak1SpecFlatFX
-        < THRES_PEAK_FLAT) {
-      useFeatureSpecFlat = 0;
-    } else { // if selected, get the threshold
-      // compute the threshold and check if value is within min/max range
-      inst->thresholdSpecFlat = WEBRTC_SPL_SAT(MAX_FLAT_Q10, FACTOR_2_FLAT_Q10
-                                               * posPeak1SpecFlatFX, MIN_FLAT_Q10); //Q10
-    }
-    // done with flatness feature
-
-    if (useFeatureSpecDiff) {
-      //compute two peaks for spectral difference
-      maxPeak1 = 0;
-      maxPeak2 = 0;
-      posPeak1SpecDiffFX = 0;
-      posPeak2SpecDiffFX = 0;
-      weightPeak1SpecDiff = 0;
-      weightPeak2SpecDiff = 0;
-      // peaks for spectral difference
-      for (i = 0; i < HIST_PAR_EST; i++) {
-        if (inst->histSpecDiff[i] > maxPeak1) {
-          // Found new "first" peak
-          maxPeak2 = maxPeak1;
-          weightPeak2SpecDiff = weightPeak1SpecDiff;
-          posPeak2SpecDiffFX = posPeak1SpecDiffFX;
-
-          maxPeak1 = inst->histSpecDiff[i];
-          weightPeak1SpecDiff = inst->histSpecDiff[i];
-          posPeak1SpecDiffFX = (uint32_t)(2 * i + 1);
-        } else if (inst->histSpecDiff[i] > maxPeak2) {
-          // Found new "second" peak
-          maxPeak2 = inst->histSpecDiff[i];
-          weightPeak2SpecDiff = inst->histSpecDiff[i];
-          posPeak2SpecDiffFX = (uint32_t)(2 * i + 1);
-        }
-      }
-
-      // merge the two peaks if they are close
-      if ((posPeak1SpecDiffFX - posPeak2SpecDiffFX < LIM_PEAK_SPACE_FLAT_DIFF)
-          && (weightPeak2SpecDiff * LIM_PEAK_WEIGHT_FLAT_DIFF > weightPeak1SpecDiff)) {
-        weightPeak1SpecDiff += weightPeak2SpecDiff;
-        posPeak1SpecDiffFX = (posPeak1SpecDiffFX + posPeak2SpecDiffFX) >> 1;
-      }
-      // get the threshold value and check if value is within min/max range
-      inst->thresholdSpecDiff = WEBRTC_SPL_SAT(MAX_DIFF, FACTOR_1_LRT_DIFF
-                                               * posPeak1SpecDiffFX, MIN_DIFF); //5x bigger
-      //reject if weight of peaks is not large enough
-      if (weightPeak1SpecDiff < THRES_WEIGHT_FLAT_DIFF) {
-        useFeatureSpecDiff = 0;
-      }
-      // done with spectral difference feature
-    }
-
-    // select the weights between the features
-    // inst->priorModelPars[4] is weight for LRT: always selected
-    featureSum = 6 / (1 + useFeatureSpecFlat + useFeatureSpecDiff);
-    inst->weightLogLrt = featureSum;
-    inst->weightSpecFlat = useFeatureSpecFlat * featureSum;
-    inst->weightSpecDiff = useFeatureSpecDiff * featureSum;
-
-    // set histograms to zero for next update
-    WebRtcSpl_ZerosArrayW16(inst->histLrt, HIST_PAR_EST);
-    WebRtcSpl_ZerosArrayW16(inst->histSpecDiff, HIST_PAR_EST);
-    WebRtcSpl_ZerosArrayW16(inst->histSpecFlat, HIST_PAR_EST);
-  }  // end of flag == 1
-}
-
-
-// Compute spectral flatness on input spectrum
-// magn is the magnitude spectrum
-// spectral flatness is returned in inst->featureSpecFlat
-void WebRtcNsx_ComputeSpectralFlatness(NoiseSuppressionFixedC* inst,
-                                       uint16_t* magn) {
-  uint32_t tmpU32;
-  uint32_t avgSpectralFlatnessNum, avgSpectralFlatnessDen;
-
-  int32_t tmp32;
-  int32_t currentSpectralFlatness, logCurSpectralFlatness;
-
-  int16_t zeros, frac, intPart;
-
-  size_t i;
-
-  // for flatness
-  avgSpectralFlatnessNum = 0;
-  avgSpectralFlatnessDen = inst->sumMagn - (uint32_t)magn[0]; // Q(normData-stages)
-
-  // compute log of ratio of the geometric to arithmetic mean: check for log(0) case
-  // flatness = exp( sum(log(magn[i]))/N - log(sum(magn[i])/N) )
-  //          = exp( sum(log(magn[i]))/N ) * N / sum(magn[i])
-  //          = 2^( sum(log2(magn[i]))/N - (log2(sum(magn[i])) - log2(N)) ) [This is used]
-  for (i = 1; i < inst->magnLen; i++) {
-    // First bin is excluded from spectrum measures. Number of bins is now a power of 2
-    if (magn[i]) {
-      zeros = WebRtcSpl_NormU32((uint32_t)magn[i]);
-      frac = (int16_t)(((uint32_t)((uint32_t)(magn[i]) << zeros)
-                              & 0x7FFFFFFF) >> 23);
-      // log2(magn(i))
-      RTC_DCHECK_LT(frac, 256);
-      tmpU32 = (uint32_t)(((31 - zeros) << 8)
-                                + WebRtcNsx_kLogTableFrac[frac]); // Q8
-      avgSpectralFlatnessNum += tmpU32; // Q8
-    } else {
-      //if at least one frequency component is zero, treat separately
-      tmpU32 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecFlat, SPECT_FLAT_TAVG_Q14); // Q24
-      inst->featureSpecFlat -= tmpU32 >> 14;  // Q10
-      return;
-    }
-  }
-  //ratio and inverse log: check for case of log(0)
-  zeros = WebRtcSpl_NormU32(avgSpectralFlatnessDen);
-  frac = (int16_t)(((avgSpectralFlatnessDen << zeros) & 0x7FFFFFFF) >> 23);
-  // log2(avgSpectralFlatnessDen)
-  RTC_DCHECK_LT(frac, 256);
-  tmp32 = (int32_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]); // Q8
-  logCurSpectralFlatness = (int32_t)avgSpectralFlatnessNum;
-  logCurSpectralFlatness += ((int32_t)(inst->stages - 1) << (inst->stages + 7)); // Q(8+stages-1)
-  logCurSpectralFlatness -= (tmp32 << (inst->stages - 1));
-  logCurSpectralFlatness <<= (10 - inst->stages);  // Q17
-  tmp32 = (int32_t)(0x00020000 | (WEBRTC_SPL_ABS_W32(logCurSpectralFlatness)
-                                        & 0x0001FFFF)); //Q17
-  intPart = 7 - (logCurSpectralFlatness >> 17);  // Add 7 for output in Q10.
-  if (intPart > 0) {
-    currentSpectralFlatness = tmp32 >> intPart;
-  } else {
-    currentSpectralFlatness = tmp32 << -intPart;
-  }
-
-  //time average update of spectral flatness feature
-  tmp32 = currentSpectralFlatness - (int32_t)inst->featureSpecFlat; // Q10
-  tmp32 *= SPECT_FLAT_TAVG_Q14;  // Q24
-  inst->featureSpecFlat += tmp32 >> 14;  // Q10
-  // done with flatness feature
-}
-
-
-// Compute the difference measure between input spectrum and a template/learned noise spectrum
-// magn_tmp is the input spectrum
-// the reference/template spectrum is  inst->magn_avg_pause[i]
-// returns (normalized) spectral difference in inst->featureSpecDiff
-void WebRtcNsx_ComputeSpectralDifference(NoiseSuppressionFixedC* inst,
-                                         uint16_t* magnIn) {
-  // This is to be calculated:
-  // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 / var(magnAvgPause)
-
-  uint32_t tmpU32no1, tmpU32no2;
-  uint32_t varMagnUFX, varPauseUFX, avgDiffNormMagnUFX;
-
-  int32_t tmp32no1, tmp32no2;
-  int32_t avgPauseFX, avgMagnFX, covMagnPauseFX;
-  int32_t maxPause, minPause;
-
-  int16_t tmp16no1;
-
-  size_t i;
-  int norm32, nShifts;
-
-  avgPauseFX = 0;
-  maxPause = 0;
-  minPause = inst->avgMagnPause[0]; // Q(prevQMagn)
-  // compute average quantities
-  for (i = 0; i < inst->magnLen; i++) {
-    // Compute mean of magn_pause
-    avgPauseFX += inst->avgMagnPause[i]; // in Q(prevQMagn)
-    maxPause = WEBRTC_SPL_MAX(maxPause, inst->avgMagnPause[i]);
-    minPause = WEBRTC_SPL_MIN(minPause, inst->avgMagnPause[i]);
-  }
-  // normalize by replacing div of "inst->magnLen" with "inst->stages-1" shifts
-  avgPauseFX >>= inst->stages - 1;
-  avgMagnFX = inst->sumMagn >> (inst->stages - 1);
-  // Largest possible deviation in magnPause for (co)var calculations
-  tmp32no1 = WEBRTC_SPL_MAX(maxPause - avgPauseFX, avgPauseFX - minPause);
-  // Get number of shifts to make sure we don't get wrap around in varPause
-  nShifts = WEBRTC_SPL_MAX(0, 10 + inst->stages - WebRtcSpl_NormW32(tmp32no1));
-
-  varMagnUFX = 0;
-  varPauseUFX = 0;
-  covMagnPauseFX = 0;
-  for (i = 0; i < inst->magnLen; i++) {
-    // Compute var and cov of magn and magn_pause
-    tmp16no1 = (int16_t)((int32_t)magnIn[i] - avgMagnFX);
-    tmp32no2 = inst->avgMagnPause[i] - avgPauseFX;
-    varMagnUFX += (uint32_t)(tmp16no1 * tmp16no1);  // Q(2*qMagn)
-    tmp32no1 = tmp32no2 * tmp16no1;  // Q(prevQMagn+qMagn)
-    covMagnPauseFX += tmp32no1; // Q(prevQMagn+qMagn)
-    tmp32no1 = tmp32no2 >> nShifts;  // Q(prevQMagn-minPause).
-    varPauseUFX += tmp32no1 * tmp32no1;  // Q(2*(prevQMagn-minPause))
-  }
-  //update of average magnitude spectrum: Q(-2*stages) and averaging replaced by shifts
-  inst->curAvgMagnEnergy +=
-      inst->magnEnergy >> (2 * inst->normData + inst->stages - 1);
-
-  avgDiffNormMagnUFX = varMagnUFX; // Q(2*qMagn)
-  if ((varPauseUFX) && (covMagnPauseFX)) {
-    tmpU32no1 = (uint32_t)WEBRTC_SPL_ABS_W32(covMagnPauseFX); // Q(prevQMagn+qMagn)
-    norm32 = WebRtcSpl_NormU32(tmpU32no1) - 16;
-    if (norm32 > 0) {
-      tmpU32no1 <<= norm32;  // Q(prevQMagn+qMagn+norm32)
-    } else {
-      tmpU32no1 >>= -norm32;  // Q(prevQMagn+qMagn+norm32)
-    }
-    tmpU32no2 = WEBRTC_SPL_UMUL(tmpU32no1, tmpU32no1); // Q(2*(prevQMagn+qMagn-norm32))
-
-    nShifts += norm32;
-    nShifts <<= 1;
-    if (nShifts < 0) {
-      varPauseUFX >>= (-nShifts); // Q(2*(qMagn+norm32+minPause))
-      nShifts = 0;
-    }
-    if (varPauseUFX > 0) {
-      // Q(2*(qMagn+norm32-16+minPause))
-      tmpU32no1 = tmpU32no2 / varPauseUFX;
-      tmpU32no1 >>= nShifts;
-
-      // Q(2*qMagn)
-      avgDiffNormMagnUFX -= WEBRTC_SPL_MIN(avgDiffNormMagnUFX, tmpU32no1);
-    } else {
-      avgDiffNormMagnUFX = 0;
-    }
-  }
-  //normalize and compute time average update of difference feature
-  tmpU32no1 = avgDiffNormMagnUFX >> (2 * inst->normData);
-  if (inst->featureSpecDiff > tmpU32no1) {
-    tmpU32no2 = WEBRTC_SPL_UMUL_32_16(inst->featureSpecDiff - tmpU32no1,
-                                      SPECT_DIFF_TAVG_Q8); // Q(8-2*stages)
-    inst->featureSpecDiff -= tmpU32no2 >> 8;  // Q(-2*stages)
-  } else {
-    tmpU32no2 = WEBRTC_SPL_UMUL_32_16(tmpU32no1 - inst->featureSpecDiff,
-                                      SPECT_DIFF_TAVG_Q8); // Q(8-2*stages)
-    inst->featureSpecDiff += tmpU32no2 >> 8;  // Q(-2*stages)
-  }
-}
-
-// Transform input (speechFrame) to frequency domain magnitude (magnU16)
-void WebRtcNsx_DataAnalysis(NoiseSuppressionFixedC* inst,
-                            short* speechFrame,
-                            uint16_t* magnU16) {
-  uint32_t tmpU32no1;
-
-  int32_t   tmp_1_w32 = 0;
-  int32_t   tmp_2_w32 = 0;
-  int32_t   sum_log_magn = 0;
-  int32_t   sum_log_i_log_magn = 0;
-
-  uint16_t  sum_log_magn_u16 = 0;
-  uint16_t  tmp_u16 = 0;
-
-  int16_t   sum_log_i = 0;
-  int16_t   sum_log_i_square = 0;
-  int16_t   frac = 0;
-  int16_t   log2 = 0;
-  int16_t   matrix_determinant = 0;
-  int16_t   maxWinData;
-
-  size_t i, j;
-  int zeros;
-  int net_norm = 0;
-  int right_shifts_in_magnU16 = 0;
-  int right_shifts_in_initMagnEst = 0;
-
-  int16_t winData_buff[ANAL_BLOCKL_MAX * 2 + 16];
-  int16_t realImag_buff[ANAL_BLOCKL_MAX * 2 + 16];
-
-  // Align the structures to 32-byte boundary for the FFT function.
-  int16_t* winData = (int16_t*) (((uintptr_t)winData_buff + 31) & ~31);
-  int16_t* realImag = (int16_t*) (((uintptr_t) realImag_buff + 31) & ~31);
-
-  // Update analysis buffer for lower band, and window data before FFT.
-  WebRtcNsx_AnalysisUpdate(inst, winData, speechFrame);
-
-  // Get input energy
-  inst->energyIn =
-      WebRtcSpl_Energy(winData, inst->anaLen, &inst->scaleEnergyIn);
-
-  // Reset zero input flag
-  inst->zeroInputSignal = 0;
-  // Acquire norm for winData
-  maxWinData = WebRtcSpl_MaxAbsValueW16(winData, inst->anaLen);
-  inst->normData = WebRtcSpl_NormW16(maxWinData);
-  if (maxWinData == 0) {
-    // Treat zero input separately.
-    inst->zeroInputSignal = 1;
-    return;
-  }
-
-  // Determine the net normalization in the frequency domain
-  net_norm = inst->stages - inst->normData;
-  // Track lowest normalization factor and use it to prevent wrap around in shifting
-  right_shifts_in_magnU16 = inst->normData - inst->minNorm;
-  right_shifts_in_initMagnEst = WEBRTC_SPL_MAX(-right_shifts_in_magnU16, 0);
-  inst->minNorm -= right_shifts_in_initMagnEst;
-  right_shifts_in_magnU16 = WEBRTC_SPL_MAX(right_shifts_in_magnU16, 0);
-
-  // create realImag as winData interleaved with zeros (= imag. part), normalize it
-  WebRtcNsx_NormalizeRealBuffer(inst, winData, realImag);
-
-  // FFT output will be in winData[].
-  WebRtcSpl_RealForwardFFT(inst->real_fft, realImag, winData);
-
-  inst->imag[0] = 0; // Q(normData-stages)
-  inst->imag[inst->anaLen2] = 0;
-  inst->real[0] = winData[0]; // Q(normData-stages)
-  inst->real[inst->anaLen2] = winData[inst->anaLen];
-  // Q(2*(normData-stages))
-  inst->magnEnergy = (uint32_t)(inst->real[0] * inst->real[0]);
-  inst->magnEnergy += (uint32_t)(inst->real[inst->anaLen2] *
-                                 inst->real[inst->anaLen2]);
-  magnU16[0] = (uint16_t)WEBRTC_SPL_ABS_W16(inst->real[0]); // Q(normData-stages)
-  magnU16[inst->anaLen2] = (uint16_t)WEBRTC_SPL_ABS_W16(inst->real[inst->anaLen2]);
-  inst->sumMagn = (uint32_t)magnU16[0]; // Q(normData-stages)
-  inst->sumMagn += (uint32_t)magnU16[inst->anaLen2];
-
-  if (inst->blockIndex >= END_STARTUP_SHORT) {
-    for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
-      inst->real[i] = winData[j];
-      inst->imag[i] = -winData[j + 1];
-      // magnitude spectrum
-      // energy in Q(2*(normData-stages))
-      tmpU32no1 = (uint32_t)(winData[j] * winData[j]);
-      tmpU32no1 += (uint32_t)(winData[j + 1] * winData[j + 1]);
-      inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages))
-
-      magnU16[i] = (uint16_t)WebRtcSpl_SqrtFloor(tmpU32no1); // Q(normData-stages)
-      inst->sumMagn += (uint32_t)magnU16[i]; // Q(normData-stages)
-    }
-  } else {
-    //
-    // Gather information during startup for noise parameter estimation
-    //
-
-    // Switch initMagnEst to Q(minNorm-stages)
-    inst->initMagnEst[0] >>= right_shifts_in_initMagnEst;
-    inst->initMagnEst[inst->anaLen2] >>= right_shifts_in_initMagnEst;
-
-    // Update initMagnEst with magnU16 in Q(minNorm-stages).
-    inst->initMagnEst[0] += magnU16[0] >> right_shifts_in_magnU16;
-    inst->initMagnEst[inst->anaLen2] +=
-        magnU16[inst->anaLen2] >> right_shifts_in_magnU16;
-
-    log2 = 0;
-    if (magnU16[inst->anaLen2]) {
-      // Calculate log2(magnU16[inst->anaLen2])
-      zeros = WebRtcSpl_NormU32((uint32_t)magnU16[inst->anaLen2]);
-      frac = (int16_t)((((uint32_t)magnU16[inst->anaLen2] << zeros) &
-                              0x7FFFFFFF) >> 23); // Q8
-      // log2(magnU16(i)) in Q8
-      RTC_DCHECK_LT(frac, 256);
-      log2 = (int16_t)(((31 - zeros) << 8) + WebRtcNsx_kLogTableFrac[frac]);
-    }
-
-    sum_log_magn = (int32_t)log2; // Q8
-    // sum_log_i_log_magn in Q17
-    sum_log_i_log_magn = (kLogIndex[inst->anaLen2] * log2) >> 3;
-
-    for (i = 1, j = 2; i < inst->anaLen2; i += 1, j += 2) {
-      inst->real[i] = winData[j];
-      inst->imag[i] = -winData[j + 1];
-      // magnitude spectrum
-      // energy in Q(2*(normData-stages))
-      tmpU32no1 = (uint32_t)(winData[j] * winData[j]);
-      tmpU32no1 += (uint32_t)(winData[j + 1] * winData[j + 1]);
-      inst->magnEnergy += tmpU32no1; // Q(2*(normData-stages))
-
-      magnU16[i] = (uint16_t)WebRtcSpl_SqrtFloor(tmpU32no1); // Q(normData-stages)
-      inst->sumMagn += (uint32_t)magnU16[i]; // Q(normData-stages)
-
-      // Switch initMagnEst to Q(minNorm-stages)
-      inst->initMagnEst[i] >>= right_shifts_in_initMagnEst;
-
-      // Update initMagnEst with magnU16 in Q(minNorm-stages).
-      inst->initMagnEst[i] += magnU16[i] >> right_shifts_in_magnU16;
-
-      if (i >= kStartBand) {
-        // For pink noise estimation. Collect data neglecting lower frequency band
-        log2 = 0;
-        if (magnU16[i]) {
-          zeros = WebRtcSpl_NormU32((uint32_t)magnU16[i]);
-          frac = (int16_t)((((uint32_t)magnU16[i] << zeros) &
-                                  0x7FFFFFFF) >> 23);
-          // log2(magnU16(i)) in Q8
-          RTC_DCHECK_LT(frac, 256);
-          log2 = (int16_t)(((31 - zeros) << 8)
-                                 + WebRtcNsx_kLogTableFrac[frac]);
-        }
-        sum_log_magn += (int32_t)log2; // Q8
-        // sum_log_i_log_magn in Q17
-        sum_log_i_log_magn += (kLogIndex[i] * log2) >> 3;
-      }
-    }
-
-    //
-    //compute simplified noise model during startup
-    //
-
-    // Estimate White noise
-
-    // Switch whiteNoiseLevel to Q(minNorm-stages)
-    inst->whiteNoiseLevel >>= right_shifts_in_initMagnEst;
-
-    // Update the average magnitude spectrum, used as noise estimate.
-    tmpU32no1 = WEBRTC_SPL_UMUL_32_16(inst->sumMagn, inst->overdrive);
-    tmpU32no1 >>= inst->stages + 8;
-
-    // Replacing division above with 'stages' shifts
-    // Shift to same Q-domain as whiteNoiseLevel
-    tmpU32no1 >>= right_shifts_in_magnU16;
-    // This operation is safe from wrap around as long as END_STARTUP_SHORT < 128
-    RTC_DCHECK_LT(END_STARTUP_SHORT, 128);
-    inst->whiteNoiseLevel += tmpU32no1; // Q(minNorm-stages)
-
-    // Estimate Pink noise parameters
-    // Denominator used in both parameter estimates.
-    // The value is only dependent on the size of the frequency band (kStartBand)
-    // and to reduce computational complexity stored in a table (kDeterminantEstMatrix[])
-    RTC_DCHECK_LT(kStartBand, 66);
-    matrix_determinant = kDeterminantEstMatrix[kStartBand]; // Q0
-    sum_log_i = kSumLogIndex[kStartBand]; // Q5
-    sum_log_i_square = kSumSquareLogIndex[kStartBand]; // Q2
-    if (inst->fs == 8000) {
-      // Adjust values to shorter blocks in narrow band.
-      tmp_1_w32 = (int32_t)matrix_determinant;
-      tmp_1_w32 += (kSumLogIndex[65] * sum_log_i) >> 9;
-      tmp_1_w32 -= (kSumLogIndex[65] * kSumLogIndex[65]) >> 10;
-      tmp_1_w32 -= (int32_t)sum_log_i_square << 4;
-      tmp_1_w32 -= ((inst->magnLen - kStartBand) * kSumSquareLogIndex[65]) >> 2;
-      matrix_determinant = (int16_t)tmp_1_w32;
-      sum_log_i -= kSumLogIndex[65]; // Q5
-      sum_log_i_square -= kSumSquareLogIndex[65]; // Q2
-    }
-
-    // Necessary number of shifts to fit sum_log_magn in a word16
-    zeros = 16 - WebRtcSpl_NormW32(sum_log_magn);
-    if (zeros < 0) {
-      zeros = 0;
-    }
-    tmp_1_w32 = sum_log_magn << 1;  // Q9
-    sum_log_magn_u16 = (uint16_t)(tmp_1_w32 >> zeros);  // Q(9-zeros).
-
-    // Calculate and update pinkNoiseNumerator. Result in Q11.
-    tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i_square, sum_log_magn_u16); // Q(11-zeros)
-    tmpU32no1 = sum_log_i_log_magn >> 12;  // Q5
-
-    // Shift the largest value of sum_log_i and tmp32no3 before multiplication
-    tmp_u16 = ((uint16_t)sum_log_i << 1);  // Q6
-    if ((uint32_t)sum_log_i > tmpU32no1) {
-      tmp_u16 >>= zeros;
-    } else {
-      tmpU32no1 >>= zeros;
-    }
-    tmp_2_w32 -= (int32_t)WEBRTC_SPL_UMUL_32_16(tmpU32no1, tmp_u16); // Q(11-zeros)
-    matrix_determinant >>= zeros;  // Q(-zeros)
-    tmp_2_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q11
-    tmp_2_w32 += (int32_t)net_norm << 11;  // Q11
-    if (tmp_2_w32 < 0) {
-      tmp_2_w32 = 0;
-    }
-    inst->pinkNoiseNumerator += tmp_2_w32; // Q11
-
-    // Calculate and update pinkNoiseExp. Result in Q14.
-    tmp_2_w32 = WEBRTC_SPL_MUL_16_U16(sum_log_i, sum_log_magn_u16); // Q(14-zeros)
-    tmp_1_w32 = sum_log_i_log_magn >> (3 + zeros);
-    tmp_1_w32 *= inst->magnLen - kStartBand;
-    tmp_2_w32 -= tmp_1_w32; // Q(14-zeros)
-    if (tmp_2_w32 > 0) {
-      // If the exponential parameter is negative force it to zero, which means a
-      // flat spectrum.
-      tmp_1_w32 = WebRtcSpl_DivW32W16(tmp_2_w32, matrix_determinant); // Q14
-      inst->pinkNoiseExp += WEBRTC_SPL_SAT(16384, tmp_1_w32, 0); // Q14
-    }
-  }
-}
-
-void WebRtcNsx_DataSynthesis(NoiseSuppressionFixedC* inst, short* outFrame) {
-  int32_t energyOut;
-
-  int16_t realImag_buff[ANAL_BLOCKL_MAX * 2 + 16];
-  int16_t rfft_out_buff[ANAL_BLOCKL_MAX * 2 + 16];
-
-  // Align the structures to 32-byte boundary for the FFT function.
-  int16_t* realImag = (int16_t*) (((uintptr_t)realImag_buff + 31) & ~31);
-  int16_t* rfft_out = (int16_t*) (((uintptr_t) rfft_out_buff + 31) & ~31);
-
-  int16_t tmp16no1, tmp16no2;
-  int16_t energyRatio;
-  int16_t gainFactor, gainFactor1, gainFactor2;
-
-  size_t i;
-  int outCIFFT;
-  int scaleEnergyOut = 0;
-
-  if (inst->zeroInputSignal) {
-    // synthesize the special case of zero input
-    // read out fully processed segment
-    for (i = 0; i < inst->blockLen10ms; i++) {
-      outFrame[i] = inst->synthesisBuffer[i]; // Q0
-    }
-    // update synthesis buffer
-    memcpy(inst->synthesisBuffer, inst->synthesisBuffer + inst->blockLen10ms,
-        (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->synthesisBuffer));
-    WebRtcSpl_ZerosArrayW16(inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms,
-                            inst->blockLen10ms);
-    return;
-  }
-
-  // Filter the data in the frequency domain, and create spectrum.
-  WebRtcNsx_PrepareSpectrum(inst, realImag);
-
-  // Inverse FFT output will be in rfft_out[].
-  outCIFFT = WebRtcSpl_RealInverseFFT(inst->real_fft, realImag, rfft_out);
-
-  WebRtcNsx_Denormalize(inst, rfft_out, outCIFFT);
-
-  //scale factor: only do it after END_STARTUP_LONG time
-  gainFactor = 8192; // 8192 = Q13(1.0)
-  if (inst->gainMap == 1 &&
-      inst->blockIndex > END_STARTUP_LONG &&
-      inst->energyIn > 0) {
-    // Q(-scaleEnergyOut)
-    energyOut = WebRtcSpl_Energy(inst->real, inst->anaLen, &scaleEnergyOut);
-    if (scaleEnergyOut == 0 && !(energyOut & 0x7f800000)) {
-      energyOut = WEBRTC_SPL_SHIFT_W32(energyOut, 8 + scaleEnergyOut
-                                       - inst->scaleEnergyIn);
-    } else {
-      // |energyIn| is currently in Q(|scaleEnergyIn|), but to later on end up
-      // with an |energyRatio| in Q8 we need to change the Q-domain to
-      // Q(-8-scaleEnergyOut).
-      inst->energyIn >>= 8 + scaleEnergyOut - inst->scaleEnergyIn;
-    }
-
-    RTC_DCHECK_GT(inst->energyIn, 0);
-    energyRatio = (energyOut + inst->energyIn / 2) / inst->energyIn;  // Q8
-    // Limit the ratio to [0, 1] in Q8, i.e., [0, 256]
-    energyRatio = WEBRTC_SPL_SAT(256, energyRatio, 0);
-
-    // all done in lookup tables now
-    RTC_DCHECK_LT(energyRatio, 257);
-    gainFactor1 = kFactor1Table[energyRatio]; // Q8
-    gainFactor2 = inst->factor2Table[energyRatio]; // Q8
-
-    //combine both scales with speech/noise prob: note prior (priorSpeechProb) is not frequency dependent
-
-    // factor = inst->priorSpeechProb*factor1 + (1.0-inst->priorSpeechProb)*factor2; // original code
-    tmp16no1 = (int16_t)(((16384 - inst->priorNonSpeechProb) * gainFactor1) >>
-        14);  // in Q13, where 16384 = Q14(1.0)
-    tmp16no2 = (int16_t)((inst->priorNonSpeechProb * gainFactor2) >> 14);
-    gainFactor = tmp16no1 + tmp16no2; // Q13
-  }  // out of flag_gain_map==1
-
-  // Synthesis, read out fully processed segment, and update synthesis buffer.
-  WebRtcNsx_SynthesisUpdate(inst, outFrame, gainFactor);
-}
-
-void WebRtcNsx_ProcessCore(NoiseSuppressionFixedC* inst,
-                           const short* const* speechFrame,
-                           int num_bands,
-                           short* const* outFrame) {
-  // main routine for noise suppression
-
-  uint32_t tmpU32no1, tmpU32no2, tmpU32no3;
-  uint32_t satMax, maxNoiseU32;
-  uint32_t tmpMagnU32, tmpNoiseU32;
-  uint32_t nearMagnEst;
-  uint32_t noiseUpdateU32;
-  uint32_t noiseU32[HALF_ANAL_BLOCKL];
-  uint32_t postLocSnr[HALF_ANAL_BLOCKL];
-  uint32_t priorLocSnr[HALF_ANAL_BLOCKL];
-  uint32_t prevNearSnr[HALF_ANAL_BLOCKL];
-  uint32_t curNearSnr;
-  uint32_t priorSnr;
-  uint32_t noise_estimate = 0;
-  uint32_t noise_estimate_avg = 0;
-  uint32_t numerator = 0;
-
-  int32_t tmp32no1, tmp32no2;
-  int32_t pink_noise_num_avg = 0;
-
-  uint16_t tmpU16no1;
-  uint16_t magnU16[HALF_ANAL_BLOCKL];
-  uint16_t prevNoiseU16[HALF_ANAL_BLOCKL];
-  uint16_t nonSpeechProbFinal[HALF_ANAL_BLOCKL];
-  uint16_t gammaNoise, prevGammaNoise;
-  uint16_t noiseSupFilterTmp[HALF_ANAL_BLOCKL];
-
-  int16_t qMagn, qNoise;
-  int16_t avgProbSpeechHB, gainModHB, avgFilterGainHB, gainTimeDomainHB;
-  int16_t pink_noise_exp_avg = 0;
-
-  size_t i, j;
-  int nShifts, postShifts;
-  int norm32no1, norm32no2;
-  int flag, sign;
-  int q_domain_to_use = 0;
-
-  // Code for ARMv7-Neon platform assumes the following:
-  RTC_DCHECK_GT(inst->anaLen, 0);
-  RTC_DCHECK_GT(inst->anaLen2, 0);
-  RTC_DCHECK_EQ(0, inst->anaLen % 16);
-  RTC_DCHECK_EQ(0, inst->anaLen2 % 8);
-  RTC_DCHECK_GT(inst->blockLen10ms, 0);
-  RTC_DCHECK_EQ(0, inst->blockLen10ms % 16);
-  RTC_DCHECK_EQ(inst->magnLen, inst->anaLen2 + 1);
-
-#ifdef NS_FILEDEBUG
-  if (fwrite(spframe, sizeof(short),
-             inst->blockLen10ms, inst->infile) != inst->blockLen10ms) {
-    RTC_NOTREACHED();
-  }
-#endif
-
-  // Check that initialization has been done
-  RTC_DCHECK_EQ(1, inst->initFlag);
-  RTC_DCHECK_LE(num_bands - 1, NUM_HIGH_BANDS_MAX);
-
-  const short* const* speechFrameHB = NULL;
-  short* const* outFrameHB = NULL;
-  size_t num_high_bands = 0;
-  if (num_bands > 1) {
-    speechFrameHB = &speechFrame[1];
-    outFrameHB = &outFrame[1];
-    num_high_bands = (size_t)(num_bands - 1);
-  }
-
-  // Store speechFrame and transform to frequency domain
-  WebRtcNsx_DataAnalysis(inst, (short*)speechFrame[0], magnU16);
-
-  if (inst->zeroInputSignal) {
-    WebRtcNsx_DataSynthesis(inst, outFrame[0]);
-
-    if (num_bands > 1) {
-      // update analysis buffer for H band
-      // append new data to buffer FX
-      for (i = 0; i < num_high_bands; ++i) {
-        int block_shift = inst->anaLen - inst->blockLen10ms;
-        memcpy(inst->dataBufHBFX[i], inst->dataBufHBFX[i] + inst->blockLen10ms,
-            block_shift * sizeof(*inst->dataBufHBFX[i]));
-        memcpy(inst->dataBufHBFX[i] + block_shift, speechFrameHB[i],
-            inst->blockLen10ms * sizeof(*inst->dataBufHBFX[i]));
-        for (j = 0; j < inst->blockLen10ms; j++) {
-          outFrameHB[i][j] = inst->dataBufHBFX[i][j]; // Q0
-        }
-      }
-    }  // end of H band gain computation
-    return;
-  }
-
-  // Update block index when we have something to process
-  inst->blockIndex++;
-  //
-
-  // Norm of magn
-  qMagn = inst->normData - inst->stages;
-
-  // Compute spectral flatness on input spectrum
-  WebRtcNsx_ComputeSpectralFlatness(inst, magnU16);
-
-  // quantile noise estimate
-  WebRtcNsx_NoiseEstimation(inst, magnU16, noiseU32, &qNoise);
-
-  //noise estimate from previous frame
-  for (i = 0; i < inst->magnLen; i++) {
-    prevNoiseU16[i] = (uint16_t)(inst->prevNoiseU32[i] >> 11);  // Q(prevQNoise)
-  }
-
-  if (inst->blockIndex < END_STARTUP_SHORT) {
-    // Noise Q-domain to be used later; see description at end of section.
-    q_domain_to_use = WEBRTC_SPL_MIN((int)qNoise, inst->minNorm - inst->stages);
-
-    // Calculate frequency independent parts in parametric noise estimate and calculate
-    // the estimate for the lower frequency band (same values for all frequency bins)
-    if (inst->pinkNoiseExp) {
-      pink_noise_exp_avg = (int16_t)WebRtcSpl_DivW32W16(inst->pinkNoiseExp,
-                                                              (int16_t)(inst->blockIndex + 1)); // Q14
-      pink_noise_num_avg = WebRtcSpl_DivW32W16(inst->pinkNoiseNumerator,
-                                               (int16_t)(inst->blockIndex + 1)); // Q11
-      WebRtcNsx_CalcParametricNoiseEstimate(inst,
-                                            pink_noise_exp_avg,
-                                            pink_noise_num_avg,
-                                            kStartBand,
-                                            &noise_estimate,
-                                            &noise_estimate_avg);
-    } else {
-      // Use white noise estimate if we have poor pink noise parameter estimates
-      noise_estimate = inst->whiteNoiseLevel; // Q(minNorm-stages)
-      noise_estimate_avg = noise_estimate / (inst->blockIndex + 1); // Q(minNorm-stages)
-    }
-    for (i = 0; i < inst->magnLen; i++) {
-      // Estimate the background noise using the pink noise parameters if permitted
-      if ((inst->pinkNoiseExp) && (i >= kStartBand)) {
-        // Reset noise_estimate
-        noise_estimate = 0;
-        noise_estimate_avg = 0;
-        // Calculate the parametric noise estimate for current frequency bin
-        WebRtcNsx_CalcParametricNoiseEstimate(inst,
-                                              pink_noise_exp_avg,
-                                              pink_noise_num_avg,
-                                              i,
-                                              &noise_estimate,
-                                              &noise_estimate_avg);
-      }
-      // Calculate parametric Wiener filter
-      noiseSupFilterTmp[i] = inst->denoiseBound;
-      if (inst->initMagnEst[i]) {
-        // numerator = (initMagnEst - noise_estimate * overdrive)
-        // Result in Q(8+minNorm-stages)
-        tmpU32no1 = WEBRTC_SPL_UMUL_32_16(noise_estimate, inst->overdrive);
-        numerator = inst->initMagnEst[i] << 8;
-        if (numerator > tmpU32no1) {
-          // Suppression filter coefficient larger than zero, so calculate.
-          numerator -= tmpU32no1;
-
-          // Determine number of left shifts in numerator for best accuracy after
-          // division
-          nShifts = WebRtcSpl_NormU32(numerator);
-          nShifts = WEBRTC_SPL_SAT(6, nShifts, 0);
-
-          // Shift numerator to Q(nShifts+8+minNorm-stages)
-          numerator <<= nShifts;
-
-          // Shift denominator to Q(nShifts-6+minNorm-stages)
-          tmpU32no1 = inst->initMagnEst[i] >> (6 - nShifts);
-          if (tmpU32no1 == 0) {
-            // This is only possible if numerator = 0, in which case
-            // we don't need any division.
-            tmpU32no1 = 1;
-          }
-          tmpU32no2 = numerator / tmpU32no1;  // Q14
-          noiseSupFilterTmp[i] = (uint16_t)WEBRTC_SPL_SAT(16384, tmpU32no2,
-              (uint32_t)(inst->denoiseBound)); // Q14
-        }
-      }
-      // Weight quantile noise 'noiseU32' with modeled noise 'noise_estimate_avg'
-      // 'noiseU32 is in Q(qNoise) and 'noise_estimate' in Q(minNorm-stages)
-      // To guarantee that we do not get wrap around when shifting to the same domain
-      // we use the lowest one. Furthermore, we need to save 6 bits for the weighting.
-      // 'noise_estimate_avg' can handle this operation by construction, but 'noiseU32'
-      // may not.
-
-      // Shift 'noiseU32' to 'q_domain_to_use'
-      tmpU32no1 = noiseU32[i] >> (qNoise - q_domain_to_use);
-      // Shift 'noise_estimate_avg' to 'q_domain_to_use'
-      tmpU32no2 = noise_estimate_avg >>
-          (inst->minNorm - inst->stages - q_domain_to_use);
-      // Make a simple check to see if we have enough room for weighting 'tmpU32no1'
-      // without wrap around
-      nShifts = 0;
-      if (tmpU32no1 & 0xfc000000) {
-        tmpU32no1 >>= 6;
-        tmpU32no2 >>= 6;
-        nShifts = 6;
-      }
-      tmpU32no1 *= inst->blockIndex;
-      tmpU32no2 *= (END_STARTUP_SHORT - inst->blockIndex);
-      // Add them together and divide by startup length
-      noiseU32[i] = WebRtcSpl_DivU32U16(tmpU32no1 + tmpU32no2, END_STARTUP_SHORT);
-      // Shift back if necessary
-      noiseU32[i] <<= nShifts;
-    }
-    // Update new Q-domain for 'noiseU32'
-    qNoise = q_domain_to_use;
-  }
-  // compute average signal during END_STARTUP_LONG time:
-  // used to normalize spectral difference measure
-  if (inst->blockIndex < END_STARTUP_LONG) {
-    // substituting division with shift ending up in Q(-2*stages)
-    inst->timeAvgMagnEnergyTmp +=
-        inst->magnEnergy >> (2 * inst->normData + inst->stages - 1);
-    inst->timeAvgMagnEnergy = WebRtcSpl_DivU32U16(inst->timeAvgMagnEnergyTmp,
-                                                  inst->blockIndex + 1);
-  }
-
-  //start processing at frames == converged+1
-  // STEP 1: compute prior and post SNR based on quantile noise estimates
-
-  // compute direct decision (DD) estimate of prior SNR: needed for new method
-  satMax = (uint32_t)1048575;// Largest possible value without getting overflow despite shifting 12 steps
-  postShifts = 6 + qMagn - qNoise;
-  nShifts = 5 - inst->prevQMagn + inst->prevQNoise;
-  for (i = 0; i < inst->magnLen; i++) {
-    // FLOAT:
-    // post SNR
-    // postLocSnr[i] = 0.0;
-    // if (magn[i] > noise[i])
-    // {
-    //   postLocSnr[i] = magn[i] / (noise[i] + 0.0001);
-    // }
-    // // previous post SNR
-    // // previous estimate: based on previous frame with gain filter (smooth is previous filter)
-    //
-    // prevNearSnr[i] = inst->prevMagnU16[i] / (inst->noisePrev[i] + 0.0001) * (inst->smooth[i]);
-    //
-    // // DD estimate is sum of two terms: current estimate and previous estimate
-    // // directed decision update of priorSnr (or we actually store [2*priorSnr+1])
-    //
-    // priorLocSnr[i] = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * (postLocSnr[i] - 1.0);
-
-    // calculate post SNR: output in Q11
-    postLocSnr[i] = 2048; // 1.0 in Q11
-    tmpU32no1 = (uint32_t)magnU16[i] << 6;  // Q(6+qMagn)
-    if (postShifts < 0) {
-      tmpU32no2 = noiseU32[i] >> -postShifts;  // Q(6+qMagn)
-    } else {
-      tmpU32no2 = noiseU32[i] << postShifts;  // Q(6+qMagn)
-    }
-    if (tmpU32no1 > tmpU32no2) {
-      // Current magnitude larger than noise
-      tmpU32no1 <<= 11;  // Q(17+qMagn)
-      if (tmpU32no2 > 0) {
-        tmpU32no1 /= tmpU32no2;  // Q11
-        postLocSnr[i] = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
-      } else {
-        postLocSnr[i] = satMax;
-      }
-    }
-
-    // calculate prevNearSnr[i] and save for later instead of recalculating it later
-    // |nearMagnEst| in Q(prevQMagn + 14)
-    nearMagnEst = inst->prevMagnU16[i] * inst->noiseSupFilter[i];
-    tmpU32no1 = nearMagnEst << 3;  // Q(prevQMagn+17)
-    tmpU32no2 = inst->prevNoiseU32[i] >> nShifts;  // Q(prevQMagn+6)
-
-    if (tmpU32no2 > 0) {
-      tmpU32no1 /= tmpU32no2;  // Q11
-      tmpU32no1 = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
-    } else {
-      tmpU32no1 = satMax; // Q11
-    }
-    prevNearSnr[i] = tmpU32no1; // Q11
-
-    //directed decision update of priorSnr
-    tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22
-    tmpU32no2 = WEBRTC_SPL_UMUL_32_16(postLocSnr[i] - 2048, ONE_MINUS_DD_PR_SNR_Q11); // Q22
-    priorSnr = tmpU32no1 + tmpU32no2 + 512; // Q22 (added 512 for rounding)
-    // priorLocSnr = 1 + 2*priorSnr
-    priorLocSnr[i] = 2048 + (priorSnr >> 10);  // Q11
-  }  // end of loop over frequencies
-  // done with step 1: DD computation of prior and post SNR
-
-  // STEP 2: compute speech/noise likelihood
-
-  //compute difference of input spectrum with learned/estimated noise spectrum
-  WebRtcNsx_ComputeSpectralDifference(inst, magnU16);
-  //compute histograms for determination of parameters (thresholds and weights for features)
-  //parameters are extracted once every window time (=inst->modelUpdate)
-  //counter update
-  inst->cntThresUpdate++;
-  flag = (int)(inst->cntThresUpdate == inst->modelUpdate);
-  //update histogram
-  WebRtcNsx_FeatureParameterExtraction(inst, flag);
-  //compute model parameters
-  if (flag) {
-    inst->cntThresUpdate = 0; // Reset counter
-    //update every window:
-    // get normalization for spectral difference for next window estimate
-
-    // Shift to Q(-2*stages)
-    inst->curAvgMagnEnergy >>= STAT_UPDATES;
-
-    tmpU32no1 = (inst->curAvgMagnEnergy + inst->timeAvgMagnEnergy + 1) >> 1; //Q(-2*stages)
-    // Update featureSpecDiff
-    if ((tmpU32no1 != inst->timeAvgMagnEnergy) && (inst->featureSpecDiff) &&
-        (inst->timeAvgMagnEnergy > 0)) {
-      norm32no1 = 0;
-      tmpU32no3 = tmpU32no1;
-      while (0xFFFF0000 & tmpU32no3) {
-        tmpU32no3 >>= 1;
-        norm32no1++;
-      }
-      tmpU32no2 = inst->featureSpecDiff;
-      while (0xFFFF0000 & tmpU32no2) {
-        tmpU32no2 >>= 1;
-        norm32no1++;
-      }
-      tmpU32no3 = WEBRTC_SPL_UMUL(tmpU32no3, tmpU32no2);
-      tmpU32no3 /= inst->timeAvgMagnEnergy;
-      if (WebRtcSpl_NormU32(tmpU32no3) < norm32no1) {
-        inst->featureSpecDiff = 0x007FFFFF;
-      } else {
-        inst->featureSpecDiff = WEBRTC_SPL_MIN(0x007FFFFF,
-                                               tmpU32no3 << norm32no1);
-      }
-    }
-
-    inst->timeAvgMagnEnergy = tmpU32no1; // Q(-2*stages)
-    inst->curAvgMagnEnergy = 0;
-  }
-
-  //compute speech/noise probability
-  WebRtcNsx_SpeechNoiseProb(inst, nonSpeechProbFinal, priorLocSnr, postLocSnr);
-
-  //time-avg parameter for noise update
-  gammaNoise = NOISE_UPDATE_Q8; // Q8
-
-  maxNoiseU32 = 0;
-  postShifts = inst->prevQNoise - qMagn;
-  nShifts = inst->prevQMagn - qMagn;
-  for (i = 0; i < inst->magnLen; i++) {
-    // temporary noise update: use it for speech frames if update value is less than previous
-    // the formula has been rewritten into:
-    // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i])
-
-    if (postShifts < 0) {
-      tmpU32no2 = magnU16[i] >> -postShifts;  // Q(prevQNoise)
-    } else {
-      tmpU32no2 = (uint32_t)magnU16[i] << postShifts;  // Q(prevQNoise)
-    }
-    if (prevNoiseU16[i] > tmpU32no2) {
-      sign = -1;
-      tmpU32no1 = prevNoiseU16[i] - tmpU32no2;
-    } else {
-      sign = 1;
-      tmpU32no1 = tmpU32no2 - prevNoiseU16[i];
-    }
-    noiseUpdateU32 = inst->prevNoiseU32[i]; // Q(prevQNoise+11)
-    tmpU32no3 = 0;
-    if ((tmpU32no1) && (nonSpeechProbFinal[i])) {
-      // This value will be used later, if gammaNoise changes
-      tmpU32no3 = WEBRTC_SPL_UMUL_32_16(tmpU32no1, nonSpeechProbFinal[i]); // Q(prevQNoise+8)
-      if (0x7c000000 & tmpU32no3) {
-        // Shifting required before multiplication
-        tmpU32no2 = (tmpU32no3 >> 5) * gammaNoise;  // Q(prevQNoise+11)
-      } else {
-        // We can do shifting after multiplication
-        tmpU32no2 = (tmpU32no3 * gammaNoise) >> 5;  // Q(prevQNoise+11)
-      }
-      if (sign > 0) {
-        noiseUpdateU32 += tmpU32no2; // Q(prevQNoise+11)
-      } else {
-        // This operation is safe. We can never get wrap around, since worst
-        // case scenario means magnU16 = 0
-        noiseUpdateU32 -= tmpU32no2; // Q(prevQNoise+11)
-      }
-    }
-
-    //increase gamma (i.e., less noise update) for frame likely to be speech
-    prevGammaNoise = gammaNoise;
-    gammaNoise = NOISE_UPDATE_Q8;
-    //time-constant based on speech/noise state
-    //increase gamma (i.e., less noise update) for frames likely to be speech
-    if (nonSpeechProbFinal[i] < ONE_MINUS_PROB_RANGE_Q8) {
-      gammaNoise = GAMMA_NOISE_TRANS_AND_SPEECH_Q8;
-    }
-
-    if (prevGammaNoise != gammaNoise) {
-      // new noise update
-      // this line is the same as above, only that the result is stored in a different variable and the gammaNoise
-      // has changed
-      //
-      // noiseUpdate = noisePrev[i] + (1 - gammaNoise) * nonSpeechProb * (magn[i] - noisePrev[i])
-
-      if (0x7c000000 & tmpU32no3) {
-        // Shifting required before multiplication
-        tmpU32no2 = (tmpU32no3 >> 5) * gammaNoise;  // Q(prevQNoise+11)
-      } else {
-        // We can do shifting after multiplication
-        tmpU32no2 = (tmpU32no3 * gammaNoise) >> 5;  // Q(prevQNoise+11)
-      }
-      if (sign > 0) {
-        tmpU32no1 = inst->prevNoiseU32[i] + tmpU32no2; // Q(prevQNoise+11)
-      } else {
-        tmpU32no1 = inst->prevNoiseU32[i] - tmpU32no2; // Q(prevQNoise+11)
-      }
-      if (noiseUpdateU32 > tmpU32no1) {
-        noiseUpdateU32 = tmpU32no1; // Q(prevQNoise+11)
-      }
-    }
-    noiseU32[i] = noiseUpdateU32; // Q(prevQNoise+11)
-    if (noiseUpdateU32 > maxNoiseU32) {
-      maxNoiseU32 = noiseUpdateU32;
-    }
-
-    // conservative noise update
-    // // original FLOAT code
-    // if (prob_speech < PROB_RANGE) {
-    // inst->avgMagnPause[i] = inst->avgMagnPause[i] + (1.0 - gamma_pause)*(magn[i] - inst->avgMagnPause[i]);
-    // }
-
-    tmp32no2 = WEBRTC_SPL_SHIFT_W32(inst->avgMagnPause[i], -nShifts);
-    if (nonSpeechProbFinal[i] > ONE_MINUS_PROB_RANGE_Q8) {
-      if (nShifts < 0) {
-        tmp32no1 = (int32_t)magnU16[i] - tmp32no2; // Q(qMagn)
-        tmp32no1 *= ONE_MINUS_GAMMA_PAUSE_Q8;  // Q(8+prevQMagn+nShifts)
-        tmp32no1 = (tmp32no1 + 128) >> 8;  // Q(qMagn).
-      } else {
-        // In Q(qMagn+nShifts)
-        tmp32no1 = ((int32_t)magnU16[i] << nShifts) - inst->avgMagnPause[i];
-        tmp32no1 *= ONE_MINUS_GAMMA_PAUSE_Q8;  // Q(8+prevQMagn+nShifts)
-        tmp32no1 = (tmp32no1 + (128 << nShifts)) >> (8 + nShifts);  // Q(qMagn).
-      }
-      tmp32no2 += tmp32no1; // Q(qMagn)
-    }
-    inst->avgMagnPause[i] = tmp32no2;
-  }  // end of frequency loop
-
-  norm32no1 = WebRtcSpl_NormU32(maxNoiseU32);
-  qNoise = inst->prevQNoise + norm32no1 - 5;
-  // done with step 2: noise update
-
-  // STEP 3: compute dd update of prior snr and post snr based on new noise estimate
-  nShifts = inst->prevQNoise + 11 - qMagn;
-  for (i = 0; i < inst->magnLen; i++) {
-    // FLOAT code
-    // // post and prior SNR
-    // curNearSnr = 0.0;
-    // if (magn[i] > noise[i])
-    // {
-    // curNearSnr = magn[i] / (noise[i] + 0.0001) - 1.0;
-    // }
-    // // DD estimate is sum of two terms: current estimate and previous estimate
-    // // directed decision update of snrPrior
-    // snrPrior = DD_PR_SNR * prevNearSnr[i] + (1.0 - DD_PR_SNR) * curNearSnr;
-    // // gain filter
-    // tmpFloat1 = inst->overdrive + snrPrior;
-    // tmpFloat2 = snrPrior / tmpFloat1;
-    // theFilter[i] = tmpFloat2;
-
-    // calculate curNearSnr again, this is necessary because a new noise estimate has been made since then. for the original
-    curNearSnr = 0; // Q11
-    if (nShifts < 0) {
-      // This case is equivalent with magn < noise which implies curNearSnr = 0;
-      tmpMagnU32 = (uint32_t)magnU16[i]; // Q(qMagn)
-      tmpNoiseU32 = noiseU32[i] << -nShifts;  // Q(qMagn)
-    } else if (nShifts > 17) {
-      tmpMagnU32 = (uint32_t)magnU16[i] << 17;  // Q(qMagn+17)
-      tmpNoiseU32 = noiseU32[i] >> (nShifts - 17);  // Q(qMagn+17)
-    } else {
-      tmpMagnU32 = (uint32_t)magnU16[i] << nShifts;  // Q(qNoise_prev+11)
-      tmpNoiseU32 = noiseU32[i]; // Q(qNoise_prev+11)
-    }
-    if (tmpMagnU32 > tmpNoiseU32) {
-      tmpU32no1 = tmpMagnU32 - tmpNoiseU32; // Q(qCur)
-      norm32no2 = WEBRTC_SPL_MIN(11, WebRtcSpl_NormU32(tmpU32no1));
-      tmpU32no1 <<= norm32no2;  // Q(qCur+norm32no2)
-      tmpU32no2 = tmpNoiseU32 >> (11 - norm32no2);  // Q(qCur+norm32no2-11)
-      if (tmpU32no2 > 0) {
-        tmpU32no1 /= tmpU32no2;  // Q11
-      }
-      curNearSnr = WEBRTC_SPL_MIN(satMax, tmpU32no1); // Q11
-    }
-
-    //directed decision update of priorSnr
-    // FLOAT
-    // priorSnr = DD_PR_SNR * prevNearSnr + (1.0-DD_PR_SNR) * curNearSnr;
-
-    tmpU32no1 = WEBRTC_SPL_UMUL_32_16(prevNearSnr[i], DD_PR_SNR_Q11); // Q22
-    tmpU32no2 = WEBRTC_SPL_UMUL_32_16(curNearSnr, ONE_MINUS_DD_PR_SNR_Q11); // Q22
-    priorSnr = tmpU32no1 + tmpU32no2; // Q22
-
-    //gain filter
-    tmpU32no1 = inst->overdrive + ((priorSnr + 8192) >> 14);  // Q8
-    RTC_DCHECK_GT(inst->overdrive, 0);
-    tmpU16no1 = (priorSnr + tmpU32no1 / 2) / tmpU32no1;  // Q14
-    inst->noiseSupFilter[i] = WEBRTC_SPL_SAT(16384, tmpU16no1, inst->denoiseBound); // 16384 = Q14(1.0) // Q14
-
-    // Weight in the parametric Wiener filter during startup
-    if (inst->blockIndex < END_STARTUP_SHORT) {
-      // Weight the two suppression filters
-      tmpU32no1 = inst->noiseSupFilter[i] * inst->blockIndex;
-      tmpU32no2 = noiseSupFilterTmp[i] *
-          (END_STARTUP_SHORT - inst->blockIndex);
-      tmpU32no1 += tmpU32no2;
-      inst->noiseSupFilter[i] = (uint16_t)WebRtcSpl_DivU32U16(tmpU32no1,
-                                                                    END_STARTUP_SHORT);
-    }
-  }  // end of loop over frequencies
-  //done with step3
-
-  // save noise and magnitude spectrum for next frame
-  inst->prevQNoise = qNoise;
-  inst->prevQMagn = qMagn;
-  if (norm32no1 > 5) {
-    for (i = 0; i < inst->magnLen; i++) {
-      inst->prevNoiseU32[i] = noiseU32[i] << (norm32no1 - 5);  // Q(qNoise+11)
-      inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn)
-    }
-  } else {
-    for (i = 0; i < inst->magnLen; i++) {
-      inst->prevNoiseU32[i] = noiseU32[i] >> (5 - norm32no1);  // Q(qNoise+11)
-      inst->prevMagnU16[i] = magnU16[i]; // Q(qMagn)
-    }
-  }
-
-  WebRtcNsx_DataSynthesis(inst, outFrame[0]);
-#ifdef NS_FILEDEBUG
-  if (fwrite(outframe, sizeof(short),
-             inst->blockLen10ms, inst->outfile) != inst->blockLen10ms) {
-    RTC_NOTREACHED();
-  }
-#endif
-
-  //for H band:
-  // only update data buffer, then apply time-domain gain is applied derived from L band
-  if (num_bands > 1) {
-    // update analysis buffer for H band
-    // append new data to buffer FX
-    for (i = 0; i < num_high_bands; ++i) {
-      memcpy(inst->dataBufHBFX[i], inst->dataBufHBFX[i] + inst->blockLen10ms,
-          (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->dataBufHBFX[i]));
-      memcpy(inst->dataBufHBFX[i] + inst->anaLen - inst->blockLen10ms,
-          speechFrameHB[i], inst->blockLen10ms * sizeof(*inst->dataBufHBFX[i]));
-    }
-    // range for averaging low band quantities for H band gain
-
-    gainTimeDomainHB = 16384; // 16384 = Q14(1.0)
-    //average speech prob from low band
-    //average filter gain from low band
-    //avg over second half (i.e., 4->8kHz) of freq. spectrum
-    tmpU32no1 = 0; // Q12
-    tmpU16no1 = 0; // Q8
-    for (i = inst->anaLen2 - (inst->anaLen2 >> 2); i < inst->anaLen2; i++) {
-      tmpU16no1 += nonSpeechProbFinal[i]; // Q8
-      tmpU32no1 += (uint32_t)(inst->noiseSupFilter[i]); // Q14
-    }
-    RTC_DCHECK_GE(inst->stages, 7);
-    avgProbSpeechHB = (4096 - (tmpU16no1 >> (inst->stages - 7)));  // Q12
-    avgFilterGainHB = (int16_t)(tmpU32no1 >> (inst->stages - 3));  // Q14
-
-    // // original FLOAT code
-    // // gain based on speech probability:
-    // avg_prob_speech_tt=(float)2.0*avg_prob_speech-(float)1.0;
-    // gain_mod=(float)0.5*((float)1.0+(float)tanh(avg_prob_speech_tt)); // between 0 and 1
-
-    // gain based on speech probability:
-    // original expression: "0.5 * (1 + tanh(2x-1))"
-    // avgProbSpeechHB has been anyway saturated to a value between 0 and 1 so the other cases don't have to be dealt with
-    // avgProbSpeechHB and gainModHB are in Q12, 3607 = Q12(0.880615234375) which is a zero point of
-    // |0.5 * (1 + tanh(2x-1)) - x| - |0.5 * (1 + tanh(2x-1)) - 0.880615234375| meaning that from that point the error of approximating
-    // the expression with f(x) = x would be greater than the error of approximating the expression with f(x) = 0.880615234375
-    // error: "|0.5 * (1 + tanh(2x-1)) - x| from x=0 to 0.880615234375" -> http://www.wolframalpha.com/input/?i=|0.5+*+(1+%2B+tanh(2x-1))+-+x|+from+x%3D0+to+0.880615234375
-    // and:  "|0.5 * (1 + tanh(2x-1)) - 0.880615234375| from x=0.880615234375 to 1" -> http://www.wolframalpha.com/input/?i=+|0.5+*+(1+%2B+tanh(2x-1))+-+0.880615234375|+from+x%3D0.880615234375+to+1
-    gainModHB = WEBRTC_SPL_MIN(avgProbSpeechHB, 3607);
-
-    // // original FLOAT code
-    // //combine gain with low band gain
-    // if (avg_prob_speech < (float)0.5) {
-    // gain_time_domain_HB=(float)0.5*gain_mod+(float)0.5*avg_filter_gain;
-    // }
-    // else {
-    // gain_time_domain_HB=(float)0.25*gain_mod+(float)0.75*avg_filter_gain;
-    // }
-
-
-    //combine gain with low band gain
-    if (avgProbSpeechHB < 2048) {
-      // 2048 = Q12(0.5)
-      // the next two lines in float are  "gain_time_domain = 0.5 * gain_mod + 0.5 * avg_filter_gain"; Q2(0.5) = 2 equals one left shift
-      gainTimeDomainHB = (gainModHB << 1) + (avgFilterGainHB >> 1); // Q14
-    } else {
-      // "gain_time_domain = 0.25 * gain_mod + 0.75 * agv_filter_gain;"
-      gainTimeDomainHB = (int16_t)((3 * avgFilterGainHB) >> 2);  // 3 = Q2(0.75)
-      gainTimeDomainHB += gainModHB; // Q14
-    }
-    //make sure gain is within flooring range
-    gainTimeDomainHB
-      = WEBRTC_SPL_SAT(16384, gainTimeDomainHB, (int16_t)(inst->denoiseBound)); // 16384 = Q14(1.0)
-
-
-    //apply gain
-    for (i = 0; i < num_high_bands; ++i) {
-      for (j = 0; j < inst->blockLen10ms; j++) {
-        outFrameHB[i][j] = (int16_t)((gainTimeDomainHB *
-            inst->dataBufHBFX[i][j]) >> 14);  // Q0
-      }
-    }
-  }  // end of H band gain computation
-}
diff --git a/modules/audio_processing/ns/prior_signal_model.cc b/modules/audio_processing/ns/prior_signal_model.cc
new file mode 100644
index 0000000..f25a1e2
--- /dev/null
+++ b/modules/audio_processing/ns/prior_signal_model.cc
@@ -0,0 +1,18 @@
+/*
+ *  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/ns/prior_signal_model.h"
+
+namespace webrtc {
+
+PriorSignalModel::PriorSignalModel(float lrt_initial_value)
+    : lrt(lrt_initial_value) {}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/prior_signal_model.h b/modules/audio_processing/ns/prior_signal_model.h
new file mode 100644
index 0000000..dcfa7ea
--- /dev/null
+++ b/modules/audio_processing/ns/prior_signal_model.h
@@ -0,0 +1,32 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_
+#define MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_
+
+namespace webrtc {
+
+// Struct for storing the prior signal model parameters.
+struct PriorSignalModel {
+  explicit PriorSignalModel(float lrt_initial_value);
+  PriorSignalModel(const PriorSignalModel&) = delete;
+  PriorSignalModel& operator=(const PriorSignalModel&) = delete;
+
+  float lrt;
+  float flatness_threshold = .5f;
+  float template_diff_threshold = .5f;
+  float lrt_weighting = 1.f;
+  float flatness_weighting = 0.f;
+  float difference_weighting = 0.f;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_H_
diff --git a/modules/audio_processing/ns/prior_signal_model_estimator.cc b/modules/audio_processing/ns/prior_signal_model_estimator.cc
new file mode 100644
index 0000000..c814658
--- /dev/null
+++ b/modules/audio_processing/ns/prior_signal_model_estimator.cc
@@ -0,0 +1,170 @@
+/*
+ *  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/ns/prior_signal_model_estimator.h"
+
+#include <math.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+namespace {
+
+// Identifies the first of the two largest peaks in the histogram.
+void FindFirstOfTwoLargestPeaks(
+    float bin_size,
+    rtc::ArrayView<const int, kHistogramSize> spectral_flatness,
+    float* peak_position,
+    int* peak_weight) {
+  RTC_DCHECK(peak_position);
+  RTC_DCHECK(peak_weight);
+
+  int peak_value = 0;
+  int secondary_peak_value = 0;
+  *peak_position = 0.f;
+  float secondary_peak_position = 0.f;
+  *peak_weight = 0;
+  int secondary_peak_weight = 0;
+
+  // Identify the two largest peaks.
+  for (int i = 0; i < kHistogramSize; ++i) {
+    const float bin_mid = (i + 0.5f) * bin_size;
+    if (spectral_flatness[i] > peak_value) {
+      // Found new "first" peak candidate.
+      secondary_peak_value = peak_value;
+      secondary_peak_weight = *peak_weight;
+      secondary_peak_position = *peak_position;
+
+      peak_value = spectral_flatness[i];
+      *peak_weight = spectral_flatness[i];
+      *peak_position = bin_mid;
+    } else if (spectral_flatness[i] > secondary_peak_value) {
+      // Found new "second" peak candidate.
+      secondary_peak_value = spectral_flatness[i];
+      secondary_peak_weight = spectral_flatness[i];
+      secondary_peak_position = bin_mid;
+    }
+  }
+
+  // Merge the peaks if they are close.
+  if ((fabs(secondary_peak_position - *peak_position) < 2 * bin_size) &&
+      (secondary_peak_weight > 0.5f * (*peak_weight))) {
+    *peak_weight += secondary_peak_weight;
+    *peak_position = 0.5f * (*peak_position + secondary_peak_position);
+  }
+}
+
+void UpdateLrt(rtc::ArrayView<const int, kHistogramSize> lrt_histogram,
+               float* prior_model_lrt,
+               bool* low_lrt_fluctuations) {
+  RTC_DCHECK(prior_model_lrt);
+  RTC_DCHECK(low_lrt_fluctuations);
+
+  float average = 0.f;
+  float average_compl = 0.f;
+  float average_squared = 0.f;
+  int count = 0;
+
+  for (int i = 0; i < 10; ++i) {
+    float bin_mid = (i + 0.5f) * kBinSizeLrt;
+    average += lrt_histogram[i] * bin_mid;
+    count += lrt_histogram[i];
+  }
+  if (count > 0) {
+    average = average / count;
+  }
+
+  for (int i = 0; i < kHistogramSize; ++i) {
+    float bin_mid = (i + 0.5f) * kBinSizeLrt;
+    average_squared += lrt_histogram[i] * bin_mid * bin_mid;
+    average_compl += lrt_histogram[i] * bin_mid;
+  }
+  constexpr float kOneFeatureUpdateWindowSize = 1.f / kFeatureUpdateWindowSize;
+  average_squared = average_squared * kOneFeatureUpdateWindowSize;
+  average_compl = average_compl * kOneFeatureUpdateWindowSize;
+
+  // Fluctuation limit of LRT feature.
+  *low_lrt_fluctuations = average_squared - average * average_compl < 0.05f;
+
+  // Get threshold for LRT feature.
+  constexpr float kMaxLrt = 1.f;
+  constexpr float kMinLrt = .2f;
+  if (*low_lrt_fluctuations) {
+    // Very low fluctuation, so likely noise.
+    *prior_model_lrt = kMaxLrt;
+  } else {
+    *prior_model_lrt = std::min(kMaxLrt, std::max(kMinLrt, 1.2f * average));
+  }
+}
+
+}  // namespace
+
+PriorSignalModelEstimator::PriorSignalModelEstimator(float lrt_initial_value)
+    : prior_model_(lrt_initial_value) {}
+
+// Extract thresholds for feature parameters and computes the threshold/weights.
+void PriorSignalModelEstimator::Update(const Histograms& histograms) {
+  bool low_lrt_fluctuations;
+  UpdateLrt(histograms.get_lrt(), &prior_model_.lrt, &low_lrt_fluctuations);
+
+  // For spectral flatness and spectral difference: compute the main peaks of
+  // the histograms.
+  float spectral_flatness_peak_position;
+  int spectral_flatness_peak_weight;
+  FindFirstOfTwoLargestPeaks(
+      kBinSizeSpecFlat, histograms.get_spectral_flatness(),
+      &spectral_flatness_peak_position, &spectral_flatness_peak_weight);
+
+  float spectral_diff_peak_position = 0.f;
+  int spectral_diff_peak_weight = 0;
+  FindFirstOfTwoLargestPeaks(kBinSizeSpecDiff, histograms.get_spectral_diff(),
+                             &spectral_diff_peak_position,
+                             &spectral_diff_peak_weight);
+
+  // Reject if weight of peaks is not large enough, or peak value too small.
+  // Peak limit for spectral flatness (varies between 0 and 1).
+  const int use_spec_flat = spectral_flatness_peak_weight < 0.3f * 500 ||
+                                    spectral_flatness_peak_position < 0.6f
+                                ? 0
+                                : 1;
+
+  // Reject if weight of peaks is not large enough or if fluctuation of the LRT
+  // feature are very low, indicating a noise state.
+  const int use_spec_diff =
+      spectral_diff_peak_weight < 0.3f * 500 || low_lrt_fluctuations ? 0 : 1;
+
+  // Update the model.
+  prior_model_.template_diff_threshold = 1.2f * spectral_diff_peak_position;
+  prior_model_.template_diff_threshold =
+      std::min(1.f, std::max(0.16f, prior_model_.template_diff_threshold));
+
+  float one_by_feature_sum = 1.f / (1.f + use_spec_flat + use_spec_diff);
+  prior_model_.lrt_weighting = one_by_feature_sum;
+
+  if (use_spec_flat == 1) {
+    prior_model_.flatness_threshold = 0.9f * spectral_flatness_peak_position;
+    prior_model_.flatness_threshold =
+        std::min(.95f, std::max(0.1f, prior_model_.flatness_threshold));
+    prior_model_.flatness_weighting = one_by_feature_sum;
+  } else {
+    prior_model_.flatness_weighting = 0.f;
+  }
+
+  if (use_spec_diff == 1) {
+    prior_model_.difference_weighting = one_by_feature_sum;
+  } else {
+    prior_model_.difference_weighting = 0.f;
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/prior_signal_model_estimator.h b/modules/audio_processing/ns/prior_signal_model_estimator.h
new file mode 100644
index 0000000..d178323
--- /dev/null
+++ b/modules/audio_processing/ns/prior_signal_model_estimator.h
@@ -0,0 +1,39 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_
+
+#include "modules/audio_processing/ns/histograms.h"
+#include "modules/audio_processing/ns/prior_signal_model.h"
+
+namespace webrtc {
+
+// Estimator of the prior signal model parameters.
+class PriorSignalModelEstimator {
+ public:
+  explicit PriorSignalModelEstimator(float lrt_initial_value);
+  PriorSignalModelEstimator(const PriorSignalModelEstimator&) = delete;
+  PriorSignalModelEstimator& operator=(const PriorSignalModelEstimator&) =
+      delete;
+
+  // Updates the model estimate.
+  void Update(const Histograms& h);
+
+  // Returns the estimated model.
+  const PriorSignalModel& get_prior_model() const { return prior_model_; }
+
+ private:
+  PriorSignalModel prior_model_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_PRIOR_SIGNAL_MODEL_ESTIMATOR_H_
diff --git a/modules/audio_processing/ns/quantile_noise_estimator.cc b/modules/audio_processing/ns/quantile_noise_estimator.cc
new file mode 100644
index 0000000..bab494f
--- /dev/null
+++ b/modules/audio_processing/ns/quantile_noise_estimator.cc
@@ -0,0 +1,88 @@
+/*
+ *  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/ns/quantile_noise_estimator.h"
+
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+
+namespace webrtc {
+
+QuantileNoiseEstimator::QuantileNoiseEstimator() {
+  quantile_.fill(0.f);
+  density_.fill(0.3f);
+  log_quantile_.fill(8.f);
+
+  constexpr float kOneBySimult = 1.f / kSimult;
+  for (size_t i = 0; i < kSimult; ++i) {
+    counter_[i] = floor(kLongStartupPhaseBlocks * (i + 1.f) * kOneBySimult);
+  }
+}
+
+void QuantileNoiseEstimator::Estimate(
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+    rtc::ArrayView<float, kFftSizeBy2Plus1> noise_spectrum) {
+  std::array<float, kFftSizeBy2Plus1> log_spectrum;
+  LogApproximation(signal_spectrum, log_spectrum);
+
+  int quantile_index_to_return = -1;
+  // Loop over simultaneous estimates.
+  for (int s = 0, k = 0; s < kSimult;
+       ++s, k += static_cast<int>(kFftSizeBy2Plus1)) {
+    const float one_by_counter_plus_1 = 1.f / (counter_[s] + 1.f);
+    for (int i = 0, j = k; i < static_cast<int>(kFftSizeBy2Plus1); ++i, ++j) {
+      // Update log quantile estimate.
+      const float delta = density_[j] > 1.f ? 40.f / density_[j] : 40.f;
+
+      const float multiplier = delta * one_by_counter_plus_1;
+      if (log_spectrum[i] > log_quantile_[j]) {
+        log_quantile_[j] += 0.25f * multiplier;
+      } else {
+        log_quantile_[j] -= 0.75f * multiplier;
+      }
+
+      // Update density estimate.
+      constexpr float kWidth = 0.01f;
+      constexpr float kOneByWidthPlus2 = 1.f / (2.f * kWidth);
+      if (fabs(log_spectrum[i] - log_quantile_[j]) < kWidth) {
+        density_[j] = (counter_[s] * density_[j] + kOneByWidthPlus2) *
+                      one_by_counter_plus_1;
+      }
+    }
+
+    if (counter_[s] >= kLongStartupPhaseBlocks) {
+      counter_[s] = 0;
+      if (num_updates_ >= kLongStartupPhaseBlocks) {
+        quantile_index_to_return = k;
+      }
+    }
+
+    ++counter_[s];
+  }
+
+  // Sequentially update the noise during startup.
+  if (num_updates_ < kLongStartupPhaseBlocks) {
+    // Use the last "s" to get noise during startup that differ from zero.
+    quantile_index_to_return = kFftSizeBy2Plus1 * (kSimult - 1);
+    ++num_updates_;
+  }
+
+  if (quantile_index_to_return >= 0) {
+    ExpApproximation(
+        rtc::ArrayView<const float>(&log_quantile_[quantile_index_to_return],
+                                    kFftSizeBy2Plus1),
+        quantile_);
+  }
+
+  std::copy(quantile_.begin(), quantile_.end(), noise_spectrum.begin());
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/quantile_noise_estimator.h b/modules/audio_processing/ns/quantile_noise_estimator.h
new file mode 100644
index 0000000..67d1512
--- /dev/null
+++ b/modules/audio_processing/ns/quantile_noise_estimator.h
@@ -0,0 +1,45 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_
+
+#include <math.h>
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+
+namespace webrtc {
+
+constexpr int kSimult = 3;
+
+// For quantile noise estimation.
+class QuantileNoiseEstimator {
+ public:
+  QuantileNoiseEstimator();
+  QuantileNoiseEstimator(const QuantileNoiseEstimator&) = delete;
+  QuantileNoiseEstimator& operator=(const QuantileNoiseEstimator&) = delete;
+
+  // Estimate noise.
+  void Estimate(rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+                rtc::ArrayView<float, kFftSizeBy2Plus1> noise_spectrum);
+
+ private:
+  std::array<float, kSimult * kFftSizeBy2Plus1> density_;
+  std::array<float, kSimult * kFftSizeBy2Plus1> log_quantile_;
+  std::array<float, kFftSizeBy2Plus1> quantile_;
+  std::array<int, kSimult> counter_;
+  int num_updates_ = 1;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_QUANTILE_NOISE_ESTIMATOR_H_
diff --git a/modules/audio_processing/ns/signal_model.cc b/modules/audio_processing/ns/signal_model.cc
new file mode 100644
index 0000000..364bfd0
--- /dev/null
+++ b/modules/audio_processing/ns/signal_model.cc
@@ -0,0 +1,24 @@
+/*
+ *  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/ns/signal_model.h"
+
+namespace webrtc {
+
+SignalModel::SignalModel() {
+  constexpr float kSfFeatureThr = 0.5f;
+
+  lrt = kLtrFeatureThr;
+  spectral_flatness = kSfFeatureThr;
+  spectral_diff = kSfFeatureThr;
+  avg_log_lrt.fill(kLtrFeatureThr);
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/signal_model.h b/modules/audio_processing/ns/signal_model.h
new file mode 100644
index 0000000..6614d38
--- /dev/null
+++ b/modules/audio_processing/ns/signal_model.h
@@ -0,0 +1,34 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_
+#define MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_
+
+#include <array>
+
+#include "modules/audio_processing/ns/ns_common.h"
+
+namespace webrtc {
+
+struct SignalModel {
+  SignalModel();
+  SignalModel(const SignalModel&) = delete;
+  SignalModel& operator=(const SignalModel&) = delete;
+
+  float lrt;
+  float spectral_diff;
+  float spectral_flatness;
+  // Log LRT factor with time-smoothing.
+  std::array<float, kFftSizeBy2Plus1> avg_log_lrt;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_H_
diff --git a/modules/audio_processing/ns/signal_model_estimator.cc b/modules/audio_processing/ns/signal_model_estimator.cc
new file mode 100644
index 0000000..67dd3bb
--- /dev/null
+++ b/modules/audio_processing/ns/signal_model_estimator.cc
@@ -0,0 +1,175 @@
+/*
+ *  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/ns/signal_model_estimator.h"
+
+#include "modules/audio_processing/ns/fast_math.h"
+
+namespace webrtc {
+
+namespace {
+
+constexpr float kOneByFftSizeBy2Plus1 = 1.f / kFftSizeBy2Plus1;
+
+// Computes the difference measure between input spectrum and a template/learned
+// noise spectrum.
+float ComputeSpectralDiff(
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> conservative_noise_spectrum,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+    float signal_spectral_sum,
+    float diff_normalization) {
+  // spectral_diff = var(signal_spectrum) - cov(signal_spectrum, magnAvgPause)^2
+  // / var(magnAvgPause)
+
+  // Compute average quantities.
+  float noise_average = 0.f;
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    // Conservative smooth noise spectrum from pause frames.
+    noise_average += conservative_noise_spectrum[i];
+  }
+  noise_average = noise_average * kOneByFftSizeBy2Plus1;
+  float signal_average = signal_spectral_sum * kOneByFftSizeBy2Plus1;
+
+  // Compute variance and covariance quantities.
+  float covariance = 0.f;
+  float noise_variance = 0.f;
+  float signal_variance = 0.f;
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    float signal_diff = signal_spectrum[i] - signal_average;
+    float noise_diff = conservative_noise_spectrum[i] - noise_average;
+    covariance += signal_diff * noise_diff;
+    noise_variance += noise_diff * noise_diff;
+    signal_variance += signal_diff * signal_diff;
+  }
+  covariance *= kOneByFftSizeBy2Plus1;
+  noise_variance *= kOneByFftSizeBy2Plus1;
+  signal_variance *= kOneByFftSizeBy2Plus1;
+
+  // Update of average magnitude spectrum.
+  float spectral_diff =
+      signal_variance - (covariance * covariance) / (noise_variance + 0.0001f);
+  // Normalize.
+  return spectral_diff / (diff_normalization + 0.0001f);
+}
+
+// Updates the spectral flatness based on the input spectrum.
+void UpdateSpectralFlatness(
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum,
+    float signal_spectral_sum,
+    float* spectral_flatness) {
+  RTC_DCHECK(spectral_flatness);
+
+  // Compute log of ratio of the geometric to arithmetic mean (handle the log(0)
+  // separately).
+  constexpr float kAveraging = 0.3f;
+  float avg_spect_flatness_num = 0.f;
+  for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) {
+    if (signal_spectrum[i] == 0.f) {
+      *spectral_flatness -= kAveraging * (*spectral_flatness);
+      return;
+    }
+  }
+
+  for (size_t i = 1; i < kFftSizeBy2Plus1; ++i) {
+    avg_spect_flatness_num += LogApproximation(signal_spectrum[i]);
+  }
+
+  float avg_spect_flatness_denom = signal_spectral_sum - signal_spectrum[0];
+
+  avg_spect_flatness_denom = avg_spect_flatness_denom * kOneByFftSizeBy2Plus1;
+  avg_spect_flatness_num = avg_spect_flatness_num * kOneByFftSizeBy2Plus1;
+
+  float spectral_tmp =
+      ExpApproximation(avg_spect_flatness_num) / avg_spect_flatness_denom;
+
+  // Time-avg update of spectral flatness feature.
+  *spectral_flatness += kAveraging * (spectral_tmp - *spectral_flatness);
+}
+
+// Updates the log LRT measures.
+void UpdateSpectralLrt(rtc::ArrayView<const float, kFftSizeBy2Plus1> prior_snr,
+                       rtc::ArrayView<const float, kFftSizeBy2Plus1> post_snr,
+                       rtc::ArrayView<float, kFftSizeBy2Plus1> avg_log_lrt,
+                       float* lrt) {
+  RTC_DCHECK(lrt);
+
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    float tmp1 = 1.f + 2.f * prior_snr[i];
+    float tmp2 = 2.f * prior_snr[i] / (tmp1 + 0.0001f);
+    float bessel_tmp = (post_snr[i] + 1.f) * tmp2;
+    avg_log_lrt[i] +=
+        .5f * (bessel_tmp - LogApproximation(tmp1) - avg_log_lrt[i]);
+  }
+
+  float log_lrt_time_avg_k_sum = 0.f;
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    log_lrt_time_avg_k_sum += avg_log_lrt[i];
+  }
+  *lrt = log_lrt_time_avg_k_sum * kOneByFftSizeBy2Plus1;
+}
+
+}  // namespace
+
+SignalModelEstimator::SignalModelEstimator()
+    : prior_model_estimator_(kLtrFeatureThr) {}
+
+void SignalModelEstimator::AdjustNormalization(int32_t num_analyzed_frames,
+                                               float signal_energy) {
+  diff_normalization_ *= num_analyzed_frames;
+  diff_normalization_ += signal_energy;
+  diff_normalization_ /= (num_analyzed_frames + 1);
+}
+
+// Update the noise features.
+void SignalModelEstimator::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) {
+  // Compute spectral flatness on input spectrum.
+  UpdateSpectralFlatness(signal_spectrum, signal_spectral_sum,
+                         &features_.spectral_flatness);
+
+  // Compute difference of input spectrum with learned/estimated noise spectrum.
+  float spectral_diff =
+      ComputeSpectralDiff(conservative_noise_spectrum, signal_spectrum,
+                          signal_spectral_sum, diff_normalization_);
+  // Compute time-avg update of difference feature.
+  features_.spectral_diff += 0.3f * (spectral_diff - features_.spectral_diff);
+
+  signal_energy_sum_ += signal_energy;
+
+  // Compute histograms for parameter decisions (thresholds and weights for
+  // features). Parameters are extracted periodically.
+  if (--histogram_analysis_counter_ > 0) {
+    histograms_.Update(features_);
+  } else {
+    // Compute model parameters.
+    prior_model_estimator_.Update(histograms_);
+
+    // Clear histograms for next update.
+    histograms_.Clear();
+
+    histogram_analysis_counter_ = kFeatureUpdateWindowSize;
+
+    // Update every window:
+    // Compute normalization for the spectral difference for next estimation.
+    signal_energy_sum_ = signal_energy_sum_ / kFeatureUpdateWindowSize;
+    diff_normalization_ = 0.5f * (signal_energy_sum_ + diff_normalization_);
+    signal_energy_sum_ = 0.f;
+  }
+
+  // Compute the LRT.
+  UpdateSpectralLrt(prior_snr, post_snr, features_.avg_log_lrt, &features_.lrt);
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/signal_model_estimator.h b/modules/audio_processing/ns/signal_model_estimator.h
new file mode 100644
index 0000000..58ce00a
--- /dev/null
+++ b/modules/audio_processing/ns/signal_model_estimator.h
@@ -0,0 +1,58 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/histograms.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/prior_signal_model.h"
+#include "modules/audio_processing/ns/prior_signal_model_estimator.h"
+#include "modules/audio_processing/ns/signal_model.h"
+
+namespace webrtc {
+
+class SignalModelEstimator {
+ public:
+  SignalModelEstimator();
+  SignalModelEstimator(const SignalModelEstimator&) = delete;
+  SignalModelEstimator& operator=(const SignalModelEstimator&) = delete;
+
+  // Compute signal normalization during the initial startup phase.
+  void AdjustNormalization(int32_t num_analyzed_frames, float signal_energy);
+
+  void 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);
+
+  const PriorSignalModel& get_prior_model() const {
+    return prior_model_estimator_.get_prior_model();
+  }
+  const SignalModel& get_model() { return features_; }
+
+ private:
+  float diff_normalization_ = 0.f;
+  float signal_energy_sum_ = 0.f;
+  Histograms histograms_;
+  int histogram_analysis_counter_ = 500;
+  PriorSignalModelEstimator prior_model_estimator_;
+  SignalModel features_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_SIGNAL_MODEL_ESTIMATOR_H_
diff --git a/modules/audio_processing/ns/speech_probability_estimator.cc b/modules/audio_processing/ns/speech_probability_estimator.cc
new file mode 100644
index 0000000..fce9bc8
--- /dev/null
+++ b/modules/audio_processing/ns/speech_probability_estimator.cc
@@ -0,0 +1,103 @@
+/*
+ *  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/ns/speech_probability_estimator.h"
+
+#include <math.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+SpeechProbabilityEstimator::SpeechProbabilityEstimator() {
+  speech_probability_.fill(0.f);
+}
+
+void SpeechProbabilityEstimator::Update(
+    int32_t num_analyzed_frames,
+    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) {
+  // Update models.
+  if (num_analyzed_frames < kLongStartupPhaseBlocks) {
+    signal_model_estimator_.AdjustNormalization(num_analyzed_frames,
+                                                signal_energy);
+  }
+  signal_model_estimator_.Update(prior_snr, post_snr,
+                                 conservative_noise_spectrum, signal_spectrum,
+                                 signal_spectral_sum, signal_energy);
+
+  const SignalModel& model = signal_model_estimator_.get_model();
+  const PriorSignalModel& prior_model =
+      signal_model_estimator_.get_prior_model();
+
+  // Width parameter in sigmoid map for prior model.
+  constexpr float kWidthPrior0 = 4.f;
+  // Width for pause region: lower range, so increase width in tanh map.
+  constexpr float kWidthPrior1 = 2.f * kWidthPrior0;
+
+  // Average LRT feature: use larger width in tanh map for pause regions.
+  float width_prior = model.lrt < prior_model.lrt ? kWidthPrior1 : kWidthPrior0;
+
+  // Compute indicator function: sigmoid map.
+  float indicator0 =
+      0.5f * (tanh(width_prior * (model.lrt - prior_model.lrt)) + 1.f);
+
+  // Spectral flatness feature: use larger width in tanh map for pause regions.
+  width_prior = model.spectral_flatness > prior_model.flatness_threshold
+                    ? kWidthPrior1
+                    : kWidthPrior0;
+
+  // Compute indicator function: sigmoid map.
+  float indicator1 =
+      0.5f * (tanh(1.f * width_prior *
+                   (prior_model.flatness_threshold - model.spectral_flatness)) +
+              1.f);
+
+  // For template spectrum-difference : use larger width in tanh map for pause
+  // regions.
+  width_prior = model.spectral_diff < prior_model.template_diff_threshold
+                    ? kWidthPrior1
+                    : kWidthPrior0;
+
+  // Compute indicator function: sigmoid map.
+  float indicator2 =
+      0.5f * (tanh(width_prior * (model.spectral_diff -
+                                  prior_model.template_diff_threshold)) +
+              1.f);
+
+  // Combine the indicator function with the feature weights.
+  float ind_prior = prior_model.lrt_weighting * indicator0 +
+                    prior_model.flatness_weighting * indicator1 +
+                    prior_model.difference_weighting * indicator2;
+
+  // Compute the prior probability.
+  prior_speech_prob_ += 0.1f * (ind_prior - prior_speech_prob_);
+
+  // Make sure probabilities are within range: keep floor to 0.01.
+  prior_speech_prob_ = std::max(std::min(prior_speech_prob_, 1.f), 0.01f);
+
+  // Final speech probability: combine prior model with LR factor:.
+  float gain_prior =
+      (1.f - prior_speech_prob_) / (prior_speech_prob_ + 0.0001f);
+
+  std::array<float, kFftSizeBy2Plus1> inv_lrt;
+  ExpApproximationSignFlip(model.avg_log_lrt, inv_lrt);
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    speech_probability_[i] = 1.f / (1.f + gain_prior * inv_lrt[i]);
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/speech_probability_estimator.h b/modules/audio_processing/ns/speech_probability_estimator.h
new file mode 100644
index 0000000..259c3b6
--- /dev/null
+++ b/modules/audio_processing/ns/speech_probability_estimator.h
@@ -0,0 +1,51 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/signal_model_estimator.h"
+
+namespace webrtc {
+
+// Class for estimating the probability of speech.
+class SpeechProbabilityEstimator {
+ public:
+  SpeechProbabilityEstimator();
+  SpeechProbabilityEstimator(const SpeechProbabilityEstimator&) = delete;
+  SpeechProbabilityEstimator& operator=(const SpeechProbabilityEstimator&) =
+      delete;
+
+  // Compute speech probability.
+  void Update(
+      int32_t num_analyzed_frames,
+      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);
+
+  float get_prior_probability() const { return prior_speech_prob_; }
+  rtc::ArrayView<const float> get_probability() { return speech_probability_; }
+
+ private:
+  SignalModelEstimator signal_model_estimator_;
+  float prior_speech_prob_ = .5f;
+  std::array<float, kFftSizeBy2Plus1> speech_probability_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_SPEECH_PROBABILITY_ESTIMATOR_H_
diff --git a/modules/audio_processing/ns/suppression_params.cc b/modules/audio_processing/ns/suppression_params.cc
new file mode 100644
index 0000000..9a6bd5a
--- /dev/null
+++ b/modules/audio_processing/ns/suppression_params.cc
@@ -0,0 +1,49 @@
+/*
+ *  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/ns/suppression_params.h"
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+SuppressionParams::SuppressionParams(
+    NsConfig::SuppressionLevel suppression_level) {
+  switch (suppression_level) {
+    case NsConfig::SuppressionLevel::k6dB:
+      over_subtraction_factor = 1.f;
+      // 6 dB attenuation.
+      minimum_attenuating_gain = 0.5f;
+      use_attenuation_adjustment = false;
+      break;
+    case NsConfig::SuppressionLevel::k12dB:
+      over_subtraction_factor = 1.f;
+      // 12 dB attenuation.
+      minimum_attenuating_gain = 0.25f;
+      use_attenuation_adjustment = true;
+      break;
+    case NsConfig::SuppressionLevel::k18dB:
+      over_subtraction_factor = 1.1f;
+      // 18 dB attenuation.
+      minimum_attenuating_gain = 0.125f;
+      use_attenuation_adjustment = true;
+      break;
+    case NsConfig::SuppressionLevel::k21dB:
+      over_subtraction_factor = 1.25f;
+      // 20.9 dB attenuation.
+      minimum_attenuating_gain = 0.09f;
+      use_attenuation_adjustment = true;
+      break;
+    default:
+      RTC_NOTREACHED();
+  }
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/suppression_params.h b/modules/audio_processing/ns/suppression_params.h
new file mode 100644
index 0000000..ad11977
--- /dev/null
+++ b/modules/audio_processing/ns/suppression_params.h
@@ -0,0 +1,30 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_
+#define MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_
+
+#include "modules/audio_processing/ns/ns_config.h"
+
+namespace webrtc {
+
+struct SuppressionParams {
+  explicit SuppressionParams(NsConfig::SuppressionLevel suppression_level);
+  SuppressionParams(const SuppressionParams&) = delete;
+  SuppressionParams& operator=(const SuppressionParams&) = delete;
+
+  float over_subtraction_factor;
+  float minimum_attenuating_gain;
+  bool use_attenuation_adjustment;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_SUPPRESSION_PARAMS_H_
diff --git a/modules/audio_processing/ns/wiener_filter.cc b/modules/audio_processing/ns/wiener_filter.cc
new file mode 100644
index 0000000..e14b797
--- /dev/null
+++ b/modules/audio_processing/ns/wiener_filter.cc
@@ -0,0 +1,120 @@
+/*
+ *  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/ns/wiener_filter.h"
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <algorithm>
+
+#include "modules/audio_processing/ns/fast_math.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+WienerFilter::WienerFilter(const SuppressionParams& suppression_params)
+    : suppression_params_(suppression_params) {
+  filter_.fill(1.f);
+  initial_spectral_estimate_.fill(0.f);
+  spectrum_prev_process_.fill(0.f);
+}
+
+void WienerFilter::Update(
+    int32_t num_analyzed_frames,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> noise_spectrum,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> prev_noise_spectrum,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> parametric_noise_spectrum,
+    rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum) {
+  for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+    // Previous estimate based on previous frame with gain filter.
+    float prev_tsa = spectrum_prev_process_[i] /
+                     (prev_noise_spectrum[i] + 0.0001f) * filter_[i];
+
+    // Current estimate.
+    float current_tsa;
+    if (signal_spectrum[i] > noise_spectrum[i]) {
+      current_tsa = signal_spectrum[i] / (noise_spectrum[i] + 0.0001f) - 1.f;
+    } else {
+      current_tsa = 0.f;
+    }
+
+    // Directed decision estimate is sum of two terms: current estimate and
+    // previous estimate.
+    float snr_prior = 0.98f * prev_tsa + (1.f - 0.98f) * current_tsa;
+    filter_[i] =
+        snr_prior / (suppression_params_.over_subtraction_factor + snr_prior);
+    filter_[i] = std::max(std::min(filter_[i], 1.f),
+                          suppression_params_.minimum_attenuating_gain);
+  }
+
+  if (num_analyzed_frames < kShortStartupPhaseBlocks) {
+    for (size_t i = 0; i < kFftSizeBy2Plus1; ++i) {
+      initial_spectral_estimate_[i] += signal_spectrum[i];
+      float filter_initial = initial_spectral_estimate_[i] -
+                             suppression_params_.over_subtraction_factor *
+                                 parametric_noise_spectrum[i];
+      filter_initial /= initial_spectral_estimate_[i] + 0.0001f;
+
+      filter_initial = std::max(std::min(filter_initial, 1.f),
+                                suppression_params_.minimum_attenuating_gain);
+
+      // Weight the two suppression filters.
+      constexpr float kOnyByShortStartupPhaseBlocks =
+          1.f / kShortStartupPhaseBlocks;
+      filter_initial *= kShortStartupPhaseBlocks - num_analyzed_frames;
+      filter_[i] *= num_analyzed_frames;
+      filter_[i] += filter_initial;
+      filter_[i] *= kOnyByShortStartupPhaseBlocks;
+    }
+  }
+
+  std::copy(signal_spectrum.begin(), signal_spectrum.end(),
+            spectrum_prev_process_.begin());
+}
+
+float WienerFilter::ComputeOverallScalingFactor(
+    int32_t num_analyzed_frames,
+    float prior_speech_probability,
+    float energy_before_filtering,
+    float energy_after_filtering) const {
+  if (!suppression_params_.use_attenuation_adjustment ||
+      num_analyzed_frames <= kLongStartupPhaseBlocks) {
+    return 1.f;
+  }
+
+  float gain = SqrtFastApproximation(energy_after_filtering /
+                                     (energy_before_filtering + 1.f));
+
+  // Scaling for new version. Threshold in final energy gain factor calculation.
+  constexpr float kBLim = 0.5f;
+  float scale_factor1 = 1.f;
+  if (gain > kBLim) {
+    scale_factor1 = 1.f + 1.3f * (gain - kBLim);
+    if (gain * scale_factor1 > 1.f) {
+      scale_factor1 = 1.f / gain;
+    }
+  }
+
+  float scale_factor2 = 1.f;
+  if (gain < kBLim) {
+    // Do not reduce scale too much for pause regions: attenuation here should
+    // be controlled by flooring.
+    gain = std::max(gain, suppression_params_.minimum_attenuating_gain);
+    scale_factor2 = 1.f - 0.3f * (kBLim - gain);
+  }
+
+  // Combine both scales with speech/noise prob: note prior
+  // (prior_speech_probability) is not frequency dependent.
+  return prior_speech_probability * scale_factor1 +
+         (1.f - prior_speech_probability) * scale_factor2;
+}
+
+}  // namespace webrtc
diff --git a/modules/audio_processing/ns/wiener_filter.h b/modules/audio_processing/ns/wiener_filter.h
new file mode 100644
index 0000000..b55c5dc
--- /dev/null
+++ b/modules/audio_processing/ns/wiener_filter.h
@@ -0,0 +1,57 @@
+/*
+ *  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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_
+#define MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_
+
+#include <array>
+
+#include "api/array_view.h"
+#include "modules/audio_processing/ns/ns_common.h"
+#include "modules/audio_processing/ns/suppression_params.h"
+
+namespace webrtc {
+
+// Estimates a Wiener-filter based frequency domain noise reduction filter.
+class WienerFilter {
+ public:
+  explicit WienerFilter(const SuppressionParams& suppression_params);
+  WienerFilter(const WienerFilter&) = delete;
+  WienerFilter& operator=(const WienerFilter&) = delete;
+
+  // Updates the filter estimate.
+  void Update(
+      int32_t num_analyzed_frames,
+      rtc::ArrayView<const float, kFftSizeBy2Plus1> noise_spectrum,
+      rtc::ArrayView<const float, kFftSizeBy2Plus1> prev_noise_spectrum,
+      rtc::ArrayView<const float, kFftSizeBy2Plus1> parametric_noise_spectrum,
+      rtc::ArrayView<const float, kFftSizeBy2Plus1> signal_spectrum);
+
+  // Compute an overall gain scaling factor.
+  float ComputeOverallScalingFactor(int32_t num_analyzed_frames,
+                                    float prior_speech_probability,
+                                    float energy_before_filtering,
+                                    float energy_after_filtering) const;
+
+  // Returns the filter.
+  rtc::ArrayView<const float, kFftSizeBy2Plus1> get_filter() const {
+    return filter_;
+  }
+
+ private:
+  const SuppressionParams& suppression_params_;
+  std::array<float, kFftSizeBy2Plus1> spectrum_prev_process_;
+  std::array<float, kFftSizeBy2Plus1> initial_spectral_estimate_;
+  std::array<float, kFftSizeBy2Plus1> filter_;
+};
+
+}  // namespace webrtc
+
+#endif  // MODULES_AUDIO_PROCESSING_NS_WIENER_FILTER_H_
diff --git a/modules/audio_processing/ns/windows_private.h b/modules/audio_processing/ns/windows_private.h
deleted file mode 100644
index 17792ec..0000000
--- a/modules/audio_processing/ns/windows_private.h
+++ /dev/null
@@ -1,672 +0,0 @@
-/*
- *  Copyright (c) 2011 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.
- */
-
-#ifndef MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_
-#define MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_
-
-// Hanning window for 4ms 16kHz
-static const float kHanning64w128[128] = {
-    0.00000000000000f, 0.02454122852291f, 0.04906767432742f, 0.07356456359967f,
-    0.09801714032956f, 0.12241067519922f, 0.14673047445536f, 0.17096188876030f,
-    0.19509032201613f, 0.21910124015687f, 0.24298017990326f, 0.26671275747490f,
-    0.29028467725446f, 0.31368174039889f, 0.33688985339222f, 0.35989503653499f,
-    0.38268343236509f, 0.40524131400499f, 0.42755509343028f, 0.44961132965461f,
-    0.47139673682600f, 0.49289819222978f, 0.51410274419322f, 0.53499761988710f,
-    0.55557023301960f, 0.57580819141785f, 0.59569930449243f, 0.61523159058063f,
-    0.63439328416365f, 0.65317284295378f, 0.67155895484702f, 0.68954054473707f,
-    0.70710678118655f, 0.72424708295147f, 0.74095112535496f, 0.75720884650648f,
-    0.77301045336274f, 0.78834642762661f, 0.80320753148064f, 0.81758481315158f,
-    0.83146961230255f, 0.84485356524971f, 0.85772861000027f, 0.87008699110871f,
-    0.88192126434835f, 0.89322430119552f, 0.90398929312344f, 0.91420975570353f,
-    0.92387953251129f, 0.93299279883474f, 0.94154406518302f, 0.94952818059304f,
-    0.95694033573221f, 0.96377606579544f, 0.97003125319454f, 0.97570213003853f,
-    0.98078528040323f, 0.98527764238894f, 0.98917650996478f, 0.99247953459871f,
-    0.99518472667220f, 0.99729045667869f, 0.99879545620517f, 0.99969881869620f,
-    1.00000000000000f, 0.99969881869620f, 0.99879545620517f, 0.99729045667869f,
-    0.99518472667220f, 0.99247953459871f, 0.98917650996478f, 0.98527764238894f,
-    0.98078528040323f, 0.97570213003853f, 0.97003125319454f, 0.96377606579544f,
-    0.95694033573221f, 0.94952818059304f, 0.94154406518302f, 0.93299279883474f,
-    0.92387953251129f, 0.91420975570353f, 0.90398929312344f, 0.89322430119552f,
-    0.88192126434835f, 0.87008699110871f, 0.85772861000027f, 0.84485356524971f,
-    0.83146961230255f, 0.81758481315158f, 0.80320753148064f, 0.78834642762661f,
-    0.77301045336274f, 0.75720884650648f, 0.74095112535496f, 0.72424708295147f,
-    0.70710678118655f, 0.68954054473707f, 0.67155895484702f, 0.65317284295378f,
-    0.63439328416365f, 0.61523159058063f, 0.59569930449243f, 0.57580819141785f,
-    0.55557023301960f, 0.53499761988710f, 0.51410274419322f, 0.49289819222978f,
-    0.47139673682600f, 0.44961132965461f, 0.42755509343028f, 0.40524131400499f,
-    0.38268343236509f, 0.35989503653499f, 0.33688985339222f, 0.31368174039889f,
-    0.29028467725446f, 0.26671275747490f, 0.24298017990326f, 0.21910124015687f,
-    0.19509032201613f, 0.17096188876030f, 0.14673047445536f, 0.12241067519922f,
-    0.09801714032956f, 0.07356456359967f, 0.04906767432742f, 0.02454122852291f};
-
-// hybrib Hanning & flat window
-static const float kBlocks80w128[128] = {
-    (float)0.00000000, (float)0.03271908, (float)0.06540313, (float)0.09801714,
-    (float)0.13052619, (float)0.16289547, (float)0.19509032, (float)0.22707626,
-    (float)0.25881905, (float)0.29028468, (float)0.32143947, (float)0.35225005,
-    (float)0.38268343, (float)0.41270703, (float)0.44228869, (float)0.47139674,
-    (float)0.50000000, (float)0.52806785, (float)0.55557023, (float)0.58247770,
-    (float)0.60876143, (float)0.63439328, (float)0.65934582, (float)0.68359230,
-    (float)0.70710678, (float)0.72986407, (float)0.75183981, (float)0.77301045,
-    (float)0.79335334, (float)0.81284668, (float)0.83146961, (float)0.84920218,
-    (float)0.86602540, (float)0.88192126, (float)0.89687274, (float)0.91086382,
-    (float)0.92387953, (float)0.93590593, (float)0.94693013, (float)0.95694034,
-    (float)0.96592583, (float)0.97387698, (float)0.98078528, (float)0.98664333,
-    (float)0.99144486, (float)0.99518473, (float)0.99785892, (float)0.99946459,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)0.99946459, (float)0.99785892, (float)0.99518473,
-    (float)0.99144486, (float)0.98664333, (float)0.98078528, (float)0.97387698,
-    (float)0.96592583, (float)0.95694034, (float)0.94693013, (float)0.93590593,
-    (float)0.92387953, (float)0.91086382, (float)0.89687274, (float)0.88192126,
-    (float)0.86602540, (float)0.84920218, (float)0.83146961, (float)0.81284668,
-    (float)0.79335334, (float)0.77301045, (float)0.75183981, (float)0.72986407,
-    (float)0.70710678, (float)0.68359230, (float)0.65934582, (float)0.63439328,
-    (float)0.60876143, (float)0.58247770, (float)0.55557023, (float)0.52806785,
-    (float)0.50000000, (float)0.47139674, (float)0.44228869, (float)0.41270703,
-    (float)0.38268343, (float)0.35225005, (float)0.32143947, (float)0.29028468,
-    (float)0.25881905, (float)0.22707626, (float)0.19509032, (float)0.16289547,
-    (float)0.13052619, (float)0.09801714, (float)0.06540313, (float)0.03271908};
-
-// hybrib Hanning & flat window
-static const float kBlocks160w256[256] = {
-    (float)0.00000000, (float)0.01636173, (float)0.03271908, (float)0.04906767,
-    (float)0.06540313, (float)0.08172107, (float)0.09801714, (float)0.11428696,
-    (float)0.13052619, (float)0.14673047, (float)0.16289547, (float)0.17901686,
-    (float)0.19509032, (float)0.21111155, (float)0.22707626, (float)0.24298018,
-    (float)0.25881905, (float)0.27458862, (float)0.29028468, (float)0.30590302,
-    (float)0.32143947, (float)0.33688985, (float)0.35225005, (float)0.36751594,
-    (float)0.38268343, (float)0.39774847, (float)0.41270703, (float)0.42755509,
-    (float)0.44228869, (float)0.45690388, (float)0.47139674, (float)0.48576339,
-    (float)0.50000000, (float)0.51410274, (float)0.52806785, (float)0.54189158,
-    (float)0.55557023, (float)0.56910015, (float)0.58247770, (float)0.59569930,
-    (float)0.60876143, (float)0.62166057, (float)0.63439328, (float)0.64695615,
-    (float)0.65934582, (float)0.67155895, (float)0.68359230, (float)0.69544264,
-    (float)0.70710678, (float)0.71858162, (float)0.72986407, (float)0.74095113,
-    (float)0.75183981, (float)0.76252720, (float)0.77301045, (float)0.78328675,
-    (float)0.79335334, (float)0.80320753, (float)0.81284668, (float)0.82226822,
-    (float)0.83146961, (float)0.84044840, (float)0.84920218, (float)0.85772861,
-    (float)0.86602540, (float)0.87409034, (float)0.88192126, (float)0.88951608,
-    (float)0.89687274, (float)0.90398929, (float)0.91086382, (float)0.91749450,
-    (float)0.92387953, (float)0.93001722, (float)0.93590593, (float)0.94154407,
-    (float)0.94693013, (float)0.95206268, (float)0.95694034, (float)0.96156180,
-    (float)0.96592583, (float)0.97003125, (float)0.97387698, (float)0.97746197,
-    (float)0.98078528, (float)0.98384601, (float)0.98664333, (float)0.98917651,
-    (float)0.99144486, (float)0.99344778, (float)0.99518473, (float)0.99665524,
-    (float)0.99785892, (float)0.99879546, (float)0.99946459, (float)0.99986614,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)0.99986614, (float)0.99946459, (float)0.99879546,
-    (float)0.99785892, (float)0.99665524, (float)0.99518473, (float)0.99344778,
-    (float)0.99144486, (float)0.98917651, (float)0.98664333, (float)0.98384601,
-    (float)0.98078528, (float)0.97746197, (float)0.97387698, (float)0.97003125,
-    (float)0.96592583, (float)0.96156180, (float)0.95694034, (float)0.95206268,
-    (float)0.94693013, (float)0.94154407, (float)0.93590593, (float)0.93001722,
-    (float)0.92387953, (float)0.91749450, (float)0.91086382, (float)0.90398929,
-    (float)0.89687274, (float)0.88951608, (float)0.88192126, (float)0.87409034,
-    (float)0.86602540, (float)0.85772861, (float)0.84920218, (float)0.84044840,
-    (float)0.83146961, (float)0.82226822, (float)0.81284668, (float)0.80320753,
-    (float)0.79335334, (float)0.78328675, (float)0.77301045, (float)0.76252720,
-    (float)0.75183981, (float)0.74095113, (float)0.72986407, (float)0.71858162,
-    (float)0.70710678, (float)0.69544264, (float)0.68359230, (float)0.67155895,
-    (float)0.65934582, (float)0.64695615, (float)0.63439328, (float)0.62166057,
-    (float)0.60876143, (float)0.59569930, (float)0.58247770, (float)0.56910015,
-    (float)0.55557023, (float)0.54189158, (float)0.52806785, (float)0.51410274,
-    (float)0.50000000, (float)0.48576339, (float)0.47139674, (float)0.45690388,
-    (float)0.44228869, (float)0.42755509, (float)0.41270703, (float)0.39774847,
-    (float)0.38268343, (float)0.36751594, (float)0.35225005, (float)0.33688985,
-    (float)0.32143947, (float)0.30590302, (float)0.29028468, (float)0.27458862,
-    (float)0.25881905, (float)0.24298018, (float)0.22707626, (float)0.21111155,
-    (float)0.19509032, (float)0.17901686, (float)0.16289547, (float)0.14673047,
-    (float)0.13052619, (float)0.11428696, (float)0.09801714, (float)0.08172107,
-    (float)0.06540313, (float)0.04906767, (float)0.03271908, (float)0.01636173};
-
-// hybrib Hanning & flat window: for 20ms
-static const float kBlocks320w512[512] = {
-    (float)0.00000000, (float)0.00818114, (float)0.01636173, (float)0.02454123,
-    (float)0.03271908, (float)0.04089475, (float)0.04906767, (float)0.05723732,
-    (float)0.06540313, (float)0.07356456, (float)0.08172107, (float)0.08987211,
-    (float)0.09801714, (float)0.10615561, (float)0.11428696, (float)0.12241068,
-    (float)0.13052619, (float)0.13863297, (float)0.14673047, (float)0.15481816,
-    (float)0.16289547, (float)0.17096189, (float)0.17901686, (float)0.18705985,
-    (float)0.19509032, (float)0.20310773, (float)0.21111155, (float)0.21910124,
-    (float)0.22707626, (float)0.23503609, (float)0.24298018, (float)0.25090801,
-    (float)0.25881905, (float)0.26671276, (float)0.27458862, (float)0.28244610,
-    (float)0.29028468, (float)0.29810383, (float)0.30590302, (float)0.31368174,
-    (float)0.32143947, (float)0.32917568, (float)0.33688985, (float)0.34458148,
-    (float)0.35225005, (float)0.35989504, (float)0.36751594, (float)0.37511224,
-    (float)0.38268343, (float)0.39022901, (float)0.39774847, (float)0.40524131,
-    (float)0.41270703, (float)0.42014512, (float)0.42755509, (float)0.43493645,
-    (float)0.44228869, (float)0.44961133, (float)0.45690388, (float)0.46416584,
-    (float)0.47139674, (float)0.47859608, (float)0.48576339, (float)0.49289819,
-    (float)0.50000000, (float)0.50706834, (float)0.51410274, (float)0.52110274,
-    (float)0.52806785, (float)0.53499762, (float)0.54189158, (float)0.54874927,
-    (float)0.55557023, (float)0.56235401, (float)0.56910015, (float)0.57580819,
-    (float)0.58247770, (float)0.58910822, (float)0.59569930, (float)0.60225052,
-    (float)0.60876143, (float)0.61523159, (float)0.62166057, (float)0.62804795,
-    (float)0.63439328, (float)0.64069616, (float)0.64695615, (float)0.65317284,
-    (float)0.65934582, (float)0.66547466, (float)0.67155895, (float)0.67759830,
-    (float)0.68359230, (float)0.68954054, (float)0.69544264, (float)0.70129818,
-    (float)0.70710678, (float)0.71286806, (float)0.71858162, (float)0.72424708,
-    (float)0.72986407, (float)0.73543221, (float)0.74095113, (float)0.74642045,
-    (float)0.75183981, (float)0.75720885, (float)0.76252720, (float)0.76779452,
-    (float)0.77301045, (float)0.77817464, (float)0.78328675, (float)0.78834643,
-    (float)0.79335334, (float)0.79830715, (float)0.80320753, (float)0.80805415,
-    (float)0.81284668, (float)0.81758481, (float)0.82226822, (float)0.82689659,
-    (float)0.83146961, (float)0.83598698, (float)0.84044840, (float)0.84485357,
-    (float)0.84920218, (float)0.85349396, (float)0.85772861, (float)0.86190585,
-    (float)0.86602540, (float)0.87008699, (float)0.87409034, (float)0.87803519,
-    (float)0.88192126, (float)0.88574831, (float)0.88951608, (float)0.89322430,
-    (float)0.89687274, (float)0.90046115, (float)0.90398929, (float)0.90745693,
-    (float)0.91086382, (float)0.91420976, (float)0.91749450, (float)0.92071783,
-    (float)0.92387953, (float)0.92697940, (float)0.93001722, (float)0.93299280,
-    (float)0.93590593, (float)0.93875641, (float)0.94154407, (float)0.94426870,
-    (float)0.94693013, (float)0.94952818, (float)0.95206268, (float)0.95453345,
-    (float)0.95694034, (float)0.95928317, (float)0.96156180, (float)0.96377607,
-    (float)0.96592583, (float)0.96801094, (float)0.97003125, (float)0.97198664,
-    (float)0.97387698, (float)0.97570213, (float)0.97746197, (float)0.97915640,
-    (float)0.98078528, (float)0.98234852, (float)0.98384601, (float)0.98527764,
-    (float)0.98664333, (float)0.98794298, (float)0.98917651, (float)0.99034383,
-    (float)0.99144486, (float)0.99247953, (float)0.99344778, (float)0.99434953,
-    (float)0.99518473, (float)0.99595331, (float)0.99665524, (float)0.99729046,
-    (float)0.99785892, (float)0.99836060, (float)0.99879546, (float)0.99916346,
-    (float)0.99946459, (float)0.99969882, (float)0.99986614, (float)0.99996653,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)1.00000000, (float)1.00000000, (float)1.00000000,
-    (float)1.00000000, (float)0.99996653, (float)0.99986614, (float)0.99969882,
-    (float)0.99946459, (float)0.99916346, (float)0.99879546, (float)0.99836060,
-    (float)0.99785892, (float)0.99729046, (float)0.99665524, (float)0.99595331,
-    (float)0.99518473, (float)0.99434953, (float)0.99344778, (float)0.99247953,
-    (float)0.99144486, (float)0.99034383, (float)0.98917651, (float)0.98794298,
-    (float)0.98664333, (float)0.98527764, (float)0.98384601, (float)0.98234852,
-    (float)0.98078528, (float)0.97915640, (float)0.97746197, (float)0.97570213,
-    (float)0.97387698, (float)0.97198664, (float)0.97003125, (float)0.96801094,
-    (float)0.96592583, (float)0.96377607, (float)0.96156180, (float)0.95928317,
-    (float)0.95694034, (float)0.95453345, (float)0.95206268, (float)0.94952818,
-    (float)0.94693013, (float)0.94426870, (float)0.94154407, (float)0.93875641,
-    (float)0.93590593, (float)0.93299280, (float)0.93001722, (float)0.92697940,
-    (float)0.92387953, (float)0.92071783, (float)0.91749450, (float)0.91420976,
-    (float)0.91086382, (float)0.90745693, (float)0.90398929, (float)0.90046115,
-    (float)0.89687274, (float)0.89322430, (float)0.88951608, (float)0.88574831,
-    (float)0.88192126, (float)0.87803519, (float)0.87409034, (float)0.87008699,
-    (float)0.86602540, (float)0.86190585, (float)0.85772861, (float)0.85349396,
-    (float)0.84920218, (float)0.84485357, (float)0.84044840, (float)0.83598698,
-    (float)0.83146961, (float)0.82689659, (float)0.82226822, (float)0.81758481,
-    (float)0.81284668, (float)0.80805415, (float)0.80320753, (float)0.79830715,
-    (float)0.79335334, (float)0.78834643, (float)0.78328675, (float)0.77817464,
-    (float)0.77301045, (float)0.76779452, (float)0.76252720, (float)0.75720885,
-    (float)0.75183981, (float)0.74642045, (float)0.74095113, (float)0.73543221,
-    (float)0.72986407, (float)0.72424708, (float)0.71858162, (float)0.71286806,
-    (float)0.70710678, (float)0.70129818, (float)0.69544264, (float)0.68954054,
-    (float)0.68359230, (float)0.67759830, (float)0.67155895, (float)0.66547466,
-    (float)0.65934582, (float)0.65317284, (float)0.64695615, (float)0.64069616,
-    (float)0.63439328, (float)0.62804795, (float)0.62166057, (float)0.61523159,
-    (float)0.60876143, (float)0.60225052, (float)0.59569930, (float)0.58910822,
-    (float)0.58247770, (float)0.57580819, (float)0.56910015, (float)0.56235401,
-    (float)0.55557023, (float)0.54874927, (float)0.54189158, (float)0.53499762,
-    (float)0.52806785, (float)0.52110274, (float)0.51410274, (float)0.50706834,
-    (float)0.50000000, (float)0.49289819, (float)0.48576339, (float)0.47859608,
-    (float)0.47139674, (float)0.46416584, (float)0.45690388, (float)0.44961133,
-    (float)0.44228869, (float)0.43493645, (float)0.42755509, (float)0.42014512,
-    (float)0.41270703, (float)0.40524131, (float)0.39774847, (float)0.39022901,
-    (float)0.38268343, (float)0.37511224, (float)0.36751594, (float)0.35989504,
-    (float)0.35225005, (float)0.34458148, (float)0.33688985, (float)0.32917568,
-    (float)0.32143947, (float)0.31368174, (float)0.30590302, (float)0.29810383,
-    (float)0.29028468, (float)0.28244610, (float)0.27458862, (float)0.26671276,
-    (float)0.25881905, (float)0.25090801, (float)0.24298018, (float)0.23503609,
-    (float)0.22707626, (float)0.21910124, (float)0.21111155, (float)0.20310773,
-    (float)0.19509032, (float)0.18705985, (float)0.17901686, (float)0.17096189,
-    (float)0.16289547, (float)0.15481816, (float)0.14673047, (float)0.13863297,
-    (float)0.13052619, (float)0.12241068, (float)0.11428696, (float)0.10615561,
-    (float)0.09801714, (float)0.08987211, (float)0.08172107, (float)0.07356456,
-    (float)0.06540313, (float)0.05723732, (float)0.04906767, (float)0.04089475,
-    (float)0.03271908, (float)0.02454123, (float)0.01636173, (float)0.00818114};
-
-// Hanning window: for 15ms at 16kHz with symmetric zeros
-static const float kBlocks240w512[512] = {
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00654494, (float)0.01308960, (float)0.01963369,
-    (float)0.02617695, (float)0.03271908, (float)0.03925982, (float)0.04579887,
-    (float)0.05233596, (float)0.05887080, (float)0.06540313, (float)0.07193266,
-    (float)0.07845910, (float)0.08498218, (float)0.09150162, (float)0.09801714,
-    (float)0.10452846, (float)0.11103531, (float)0.11753740, (float)0.12403446,
-    (float)0.13052620, (float)0.13701233, (float)0.14349262, (float)0.14996676,
-    (float)0.15643448, (float)0.16289547, (float)0.16934951, (float)0.17579629,
-    (float)0.18223552, (float)0.18866697, (float)0.19509032, (float)0.20150533,
-    (float)0.20791170, (float)0.21430916, (float)0.22069745, (float)0.22707628,
-    (float)0.23344538, (float)0.23980446, (float)0.24615330, (float)0.25249159,
-    (float)0.25881904, (float)0.26513544, (float)0.27144045, (float)0.27773386,
-    (float)0.28401536, (float)0.29028466, (float)0.29654160, (float)0.30278578,
-    (float)0.30901700, (float)0.31523499, (float)0.32143945, (float)0.32763019,
-    (float)0.33380687, (float)0.33996925, (float)0.34611708, (float)0.35225007,
-    (float)0.35836795, (float)0.36447051, (float)0.37055743, (float)0.37662852,
-    (float)0.38268346, (float)0.38872197, (float)0.39474389, (float)0.40074885,
-    (float)0.40673664, (float)0.41270703, (float)0.41865975, (float)0.42459452,
-    (float)0.43051112, (float)0.43640924, (float)0.44228873, (float)0.44814920,
-    (float)0.45399052, (float)0.45981237, (float)0.46561453, (float)0.47139674,
-    (float)0.47715878, (float)0.48290035, (float)0.48862126, (float)0.49432120,
-    (float)0.50000000, (float)0.50565743, (float)0.51129311, (float)0.51690692,
-    (float)0.52249855, (float)0.52806789, (float)0.53361452, (float)0.53913832,
-    (float)0.54463905, (float)0.55011642, (float)0.55557024, (float)0.56100029,
-    (float)0.56640625, (float)0.57178795, (float)0.57714522, (float)0.58247769,
-    (float)0.58778524, (float)0.59306765, (float)0.59832460, (float)0.60355598,
-    (float)0.60876143, (float)0.61394083, (float)0.61909395, (float)0.62422055,
-    (float)0.62932038, (float)0.63439333, (float)0.63943899, (float)0.64445734,
-    (float)0.64944810, (float)0.65441096, (float)0.65934587, (float)0.66425246,
-    (float)0.66913062, (float)0.67398012, (float)0.67880076, (float)0.68359232,
-    (float)0.68835455, (float)0.69308740, (float)0.69779050, (float)0.70246369,
-    (float)0.70710677, (float)0.71171963, (float)0.71630198, (float)0.72085363,
-    (float)0.72537440, (float)0.72986406, (float)0.73432255, (float)0.73874950,
-    (float)0.74314487, (float)0.74750835, (float)0.75183982, (float)0.75613910,
-    (float)0.76040596, (float)0.76464027, (float)0.76884186, (float)0.77301043,
-    (float)0.77714598, (float)0.78124821, (float)0.78531694, (float)0.78935206,
-    (float)0.79335338, (float)0.79732066, (float)0.80125386, (float)0.80515265,
-    (float)0.80901700, (float)0.81284672, (float)0.81664157, (float)0.82040149,
-    (float)0.82412618, (float)0.82781565, (float)0.83146966, (float)0.83508795,
-    (float)0.83867061, (float)0.84221727, (float)0.84572780, (float)0.84920216,
-    (float)0.85264021, (float)0.85604161, (float)0.85940641, (float)0.86273444,
-    (float)0.86602545, (float)0.86927933, (float)0.87249607, (float)0.87567532,
-    (float)0.87881714, (float)0.88192129, (float)0.88498765, (float)0.88801610,
-    (float)0.89100653, (float)0.89395881, (float)0.89687276, (float)0.89974827,
-    (float)0.90258533, (float)0.90538365, (float)0.90814316, (float)0.91086388,
-    (float)0.91354549, (float)0.91618794, (float)0.91879123, (float)0.92135513,
-    (float)0.92387950, (float)0.92636442, (float)0.92880958, (float)0.93121493,
-    (float)0.93358046, (float)0.93590593, (float)0.93819135, (float)0.94043654,
-    (float)0.94264150, (float)0.94480604, (float)0.94693011, (float)0.94901365,
-    (float)0.95105654, (float)0.95305866, (float)0.95501995, (float)0.95694035,
-    (float)0.95881975, (float)0.96065807, (float)0.96245527, (float)0.96421117,
-    (float)0.96592581, (float)0.96759909, (float)0.96923089, (float)0.97082120,
-    (float)0.97236991, (float)0.97387701, (float)0.97534233, (float)0.97676587,
-    (float)0.97814763, (float)0.97948742, (float)0.98078531, (float)0.98204112,
-    (float)0.98325491, (float)0.98442656, (float)0.98555607, (float)0.98664331,
-    (float)0.98768836, (float)0.98869103, (float)0.98965138, (float)0.99056935,
-    (float)0.99144489, (float)0.99227792, (float)0.99306846, (float)0.99381649,
-    (float)0.99452192, (float)0.99518472, (float)0.99580491, (float)0.99638247,
-    (float)0.99691731, (float)0.99740952, (float)0.99785894, (float)0.99826562,
-    (float)0.99862951, (float)0.99895066, (float)0.99922901, (float)0.99946457,
-    (float)0.99965733, (float)0.99980724, (float)0.99991435, (float)0.99997860,
-    (float)1.00000000, (float)0.99997860, (float)0.99991435, (float)0.99980724,
-    (float)0.99965733, (float)0.99946457, (float)0.99922901, (float)0.99895066,
-    (float)0.99862951, (float)0.99826562, (float)0.99785894, (float)0.99740946,
-    (float)0.99691731, (float)0.99638247, (float)0.99580491, (float)0.99518472,
-    (float)0.99452192, (float)0.99381644, (float)0.99306846, (float)0.99227792,
-    (float)0.99144489, (float)0.99056935, (float)0.98965138, (float)0.98869103,
-    (float)0.98768836, (float)0.98664331, (float)0.98555607, (float)0.98442656,
-    (float)0.98325491, (float)0.98204112, (float)0.98078525, (float)0.97948742,
-    (float)0.97814757, (float)0.97676587, (float)0.97534227, (float)0.97387695,
-    (float)0.97236991, (float)0.97082120, (float)0.96923089, (float)0.96759909,
-    (float)0.96592581, (float)0.96421117, (float)0.96245521, (float)0.96065807,
-    (float)0.95881969, (float)0.95694029, (float)0.95501995, (float)0.95305860,
-    (float)0.95105648, (float)0.94901365, (float)0.94693011, (float)0.94480604,
-    (float)0.94264150, (float)0.94043654, (float)0.93819129, (float)0.93590593,
-    (float)0.93358046, (float)0.93121493, (float)0.92880952, (float)0.92636436,
-    (float)0.92387950, (float)0.92135507, (float)0.91879123, (float)0.91618794,
-    (float)0.91354543, (float)0.91086382, (float)0.90814310, (float)0.90538365,
-    (float)0.90258527, (float)0.89974827, (float)0.89687276, (float)0.89395875,
-    (float)0.89100647, (float)0.88801610, (float)0.88498759, (float)0.88192123,
-    (float)0.87881714, (float)0.87567532, (float)0.87249595, (float)0.86927933,
-    (float)0.86602539, (float)0.86273432, (float)0.85940641, (float)0.85604161,
-    (float)0.85264009, (float)0.84920216, (float)0.84572780, (float)0.84221715,
-    (float)0.83867055, (float)0.83508795, (float)0.83146954, (float)0.82781565,
-    (float)0.82412612, (float)0.82040137, (float)0.81664157, (float)0.81284660,
-    (float)0.80901700, (float)0.80515265, (float)0.80125374, (float)0.79732066,
-    (float)0.79335332, (float)0.78935200, (float)0.78531694, (float)0.78124815,
-    (float)0.77714586, (float)0.77301049, (float)0.76884180, (float)0.76464021,
-    (float)0.76040596, (float)0.75613904, (float)0.75183970, (float)0.74750835,
-    (float)0.74314481, (float)0.73874938, (float)0.73432249, (float)0.72986400,
-    (float)0.72537428, (float)0.72085363, (float)0.71630186, (float)0.71171951,
-    (float)0.70710677, (float)0.70246363, (float)0.69779032, (float)0.69308734,
-    (float)0.68835449, (float)0.68359220, (float)0.67880070, (float)0.67398006,
-    (float)0.66913044, (float)0.66425240, (float)0.65934575, (float)0.65441096,
-    (float)0.64944804, (float)0.64445722, (float)0.63943905, (float)0.63439327,
-    (float)0.62932026, (float)0.62422055, (float)0.61909389, (float)0.61394072,
-    (float)0.60876143, (float)0.60355592, (float)0.59832448, (float)0.59306765,
-    (float)0.58778518, (float)0.58247757, (float)0.57714522, (float)0.57178789,
-    (float)0.56640613, (float)0.56100023, (float)0.55557019, (float)0.55011630,
-    (float)0.54463905, (float)0.53913826, (float)0.53361434, (float)0.52806783,
-    (float)0.52249849, (float)0.51690674, (float)0.51129305, (float)0.50565726,
-    (float)0.50000006, (float)0.49432117, (float)0.48862115, (float)0.48290038,
-    (float)0.47715873, (float)0.47139663, (float)0.46561456, (float)0.45981231,
-    (float)0.45399037, (float)0.44814920, (float)0.44228864, (float)0.43640912,
-    (float)0.43051112, (float)0.42459446, (float)0.41865960, (float)0.41270703,
-    (float)0.40673658, (float)0.40074870, (float)0.39474386, (float)0.38872188,
-    (float)0.38268328, (float)0.37662849, (float)0.37055734, (float)0.36447033,
-    (float)0.35836792, (float)0.35224995, (float)0.34611690, (float)0.33996922,
-    (float)0.33380675, (float)0.32763001, (float)0.32143945, (float)0.31523487,
-    (float)0.30901679, (float)0.30278572, (float)0.29654145, (float)0.29028472,
-    (float)0.28401530, (float)0.27773371, (float)0.27144048, (float)0.26513538,
-    (float)0.25881892, (float)0.25249159, (float)0.24615324, (float)0.23980433,
-    (float)0.23344538, (float)0.22707619, (float)0.22069728, (float)0.21430916,
-    (float)0.20791161, (float)0.20150517, (float)0.19509031, (float)0.18866688,
-    (float)0.18223536, (float)0.17579627, (float)0.16934940, (float)0.16289529,
-    (float)0.15643445, (float)0.14996666, (float)0.14349243, (float)0.13701232,
-    (float)0.13052608, (float)0.12403426, (float)0.11753736, (float)0.11103519,
-    (float)0.10452849, (float)0.09801710, (float)0.09150149, (float)0.08498220,
-    (float)0.07845904, (float)0.07193252, (float)0.06540315, (float)0.05887074,
-    (float)0.05233581, (float)0.04579888, (float)0.03925974, (float)0.03271893,
-    (float)0.02617695, (float)0.01963361, (float)0.01308943, (float)0.00654493,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000};
-
-// Hanning window: for 30ms with 1024 fft with symmetric zeros at 16kHz
-static const float kBlocks480w1024[1024] = {
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00327249, (float)0.00654494, (float)0.00981732,
-    (float)0.01308960, (float)0.01636173, (float)0.01963369, (float)0.02290544,
-    (float)0.02617695, (float)0.02944817, (float)0.03271908, (float)0.03598964,
-    (float)0.03925982, (float)0.04252957, (float)0.04579887, (float)0.04906768,
-    (float)0.05233596, (float)0.05560368, (float)0.05887080, (float)0.06213730,
-    (float)0.06540313, (float)0.06866825, (float)0.07193266, (float)0.07519628,
-    (float)0.07845910, (float)0.08172107, (float)0.08498218, (float)0.08824237,
-    (float)0.09150162, (float)0.09475989, (float)0.09801714, (float)0.10127335,
-    (float)0.10452846, (float)0.10778246, (float)0.11103531, (float)0.11428697,
-    (float)0.11753740, (float)0.12078657, (float)0.12403446, (float)0.12728101,
-    (float)0.13052620, (float)0.13376999, (float)0.13701233, (float)0.14025325,
-    (float)0.14349262, (float)0.14673047, (float)0.14996676, (float)0.15320145,
-    (float)0.15643448, (float)0.15966582, (float)0.16289547, (float)0.16612339,
-    (float)0.16934951, (float)0.17257382, (float)0.17579629, (float)0.17901687,
-    (float)0.18223552, (float)0.18545224, (float)0.18866697, (float)0.19187967,
-    (float)0.19509032, (float)0.19829889, (float)0.20150533, (float)0.20470962,
-    (float)0.20791170, (float)0.21111156, (float)0.21430916, (float)0.21750447,
-    (float)0.22069745, (float)0.22388805, (float)0.22707628, (float)0.23026206,
-    (float)0.23344538, (float)0.23662618, (float)0.23980446, (float)0.24298020,
-    (float)0.24615330, (float)0.24932377, (float)0.25249159, (float)0.25565669,
-    (float)0.25881904, (float)0.26197866, (float)0.26513544, (float)0.26828939,
-    (float)0.27144045, (float)0.27458861, (float)0.27773386, (float)0.28087610,
-    (float)0.28401536, (float)0.28715158, (float)0.29028466, (float)0.29341471,
-    (float)0.29654160, (float)0.29966527, (float)0.30278578, (float)0.30590302,
-    (float)0.30901700, (float)0.31212768, (float)0.31523499, (float)0.31833893,
-    (float)0.32143945, (float)0.32453656, (float)0.32763019, (float)0.33072028,
-    (float)0.33380687, (float)0.33688986, (float)0.33996925, (float)0.34304500,
-    (float)0.34611708, (float)0.34918544, (float)0.35225007, (float)0.35531089,
-    (float)0.35836795, (float)0.36142117, (float)0.36447051, (float)0.36751595,
-    (float)0.37055743, (float)0.37359497, (float)0.37662852, (float)0.37965801,
-    (float)0.38268346, (float)0.38570479, (float)0.38872197, (float)0.39173502,
-    (float)0.39474389, (float)0.39774847, (float)0.40074885, (float)0.40374491,
-    (float)0.40673664, (float)0.40972406, (float)0.41270703, (float)0.41568562,
-    (float)0.41865975, (float)0.42162940, (float)0.42459452, (float)0.42755508,
-    (float)0.43051112, (float)0.43346250, (float)0.43640924, (float)0.43935132,
-    (float)0.44228873, (float)0.44522133, (float)0.44814920, (float)0.45107228,
-    (float)0.45399052, (float)0.45690390, (float)0.45981237, (float)0.46271592,
-    (float)0.46561453, (float)0.46850815, (float)0.47139674, (float)0.47428030,
-    (float)0.47715878, (float)0.48003215, (float)0.48290035, (float)0.48576337,
-    (float)0.48862126, (float)0.49147385, (float)0.49432120, (float)0.49716330,
-    (float)0.50000000, (float)0.50283140, (float)0.50565743, (float)0.50847799,
-    (float)0.51129311, (float)0.51410276, (float)0.51690692, (float)0.51970553,
-    (float)0.52249855, (float)0.52528602, (float)0.52806789, (float)0.53084403,
-    (float)0.53361452, (float)0.53637928, (float)0.53913832, (float)0.54189163,
-    (float)0.54463905, (float)0.54738063, (float)0.55011642, (float)0.55284631,
-    (float)0.55557024, (float)0.55828828, (float)0.56100029, (float)0.56370628,
-    (float)0.56640625, (float)0.56910014, (float)0.57178795, (float)0.57446963,
-    (float)0.57714522, (float)0.57981455, (float)0.58247769, (float)0.58513463,
-    (float)0.58778524, (float)0.59042960, (float)0.59306765, (float)0.59569931,
-    (float)0.59832460, (float)0.60094351, (float)0.60355598, (float)0.60616195,
-    (float)0.60876143, (float)0.61135441, (float)0.61394083, (float)0.61652070,
-    (float)0.61909395, (float)0.62166059, (float)0.62422055, (float)0.62677383,
-    (float)0.62932038, (float)0.63186020, (float)0.63439333, (float)0.63691956,
-    (float)0.63943899, (float)0.64195162, (float)0.64445734, (float)0.64695615,
-    (float)0.64944810, (float)0.65193301, (float)0.65441096, (float)0.65688187,
-    (float)0.65934587, (float)0.66180271, (float)0.66425246, (float)0.66669512,
-    (float)0.66913062, (float)0.67155898, (float)0.67398012, (float)0.67639405,
-    (float)0.67880076, (float)0.68120021, (float)0.68359232, (float)0.68597710,
-    (float)0.68835455, (float)0.69072467, (float)0.69308740, (float)0.69544262,
-    (float)0.69779050, (float)0.70013082, (float)0.70246369, (float)0.70478904,
-    (float)0.70710677, (float)0.70941699, (float)0.71171963, (float)0.71401459,
-    (float)0.71630198, (float)0.71858168, (float)0.72085363, (float)0.72311789,
-    (float)0.72537440, (float)0.72762316, (float)0.72986406, (float)0.73209721,
-    (float)0.73432255, (float)0.73653996, (float)0.73874950, (float)0.74095118,
-    (float)0.74314487, (float)0.74533057, (float)0.74750835, (float)0.74967808,
-    (float)0.75183982, (float)0.75399351, (float)0.75613910, (float)0.75827658,
-    (float)0.76040596, (float)0.76252723, (float)0.76464027, (float)0.76674515,
-    (float)0.76884186, (float)0.77093029, (float)0.77301043, (float)0.77508241,
-    (float)0.77714598, (float)0.77920127, (float)0.78124821, (float)0.78328675,
-    (float)0.78531694, (float)0.78733873, (float)0.78935206, (float)0.79135692,
-    (float)0.79335338, (float)0.79534125, (float)0.79732066, (float)0.79929149,
-    (float)0.80125386, (float)0.80320752, (float)0.80515265, (float)0.80708915,
-    (float)0.80901700, (float)0.81093621, (float)0.81284672, (float)0.81474853,
-    (float)0.81664157, (float)0.81852591, (float)0.82040149, (float)0.82226825,
-    (float)0.82412618, (float)0.82597536, (float)0.82781565, (float)0.82964706,
-    (float)0.83146966, (float)0.83328325, (float)0.83508795, (float)0.83688378,
-    (float)0.83867061, (float)0.84044838, (float)0.84221727, (float)0.84397703,
-    (float)0.84572780, (float)0.84746957, (float)0.84920216, (float)0.85092574,
-    (float)0.85264021, (float)0.85434544, (float)0.85604161, (float)0.85772866,
-    (float)0.85940641, (float)0.86107504, (float)0.86273444, (float)0.86438453,
-    (float)0.86602545, (float)0.86765707, (float)0.86927933, (float)0.87089235,
-    (float)0.87249607, (float)0.87409031, (float)0.87567532, (float)0.87725097,
-    (float)0.87881714, (float)0.88037390, (float)0.88192129, (float)0.88345921,
-    (float)0.88498765, (float)0.88650668, (float)0.88801610, (float)0.88951612,
-    (float)0.89100653, (float)0.89248741, (float)0.89395881, (float)0.89542055,
-    (float)0.89687276, (float)0.89831537, (float)0.89974827, (float)0.90117162,
-    (float)0.90258533, (float)0.90398932, (float)0.90538365, (float)0.90676826,
-    (float)0.90814316, (float)0.90950841, (float)0.91086388, (float)0.91220951,
-    (float)0.91354549, (float)0.91487163, (float)0.91618794, (float)0.91749454,
-    (float)0.91879123, (float)0.92007810, (float)0.92135513, (float)0.92262226,
-    (float)0.92387950, (float)0.92512691, (float)0.92636442, (float)0.92759192,
-    (float)0.92880958, (float)0.93001723, (float)0.93121493, (float)0.93240267,
-    (float)0.93358046, (float)0.93474817, (float)0.93590593, (float)0.93705362,
-    (float)0.93819135, (float)0.93931901, (float)0.94043654, (float)0.94154406,
-    (float)0.94264150, (float)0.94372880, (float)0.94480604, (float)0.94587320,
-    (float)0.94693011, (float)0.94797695, (float)0.94901365, (float)0.95004016,
-    (float)0.95105654, (float)0.95206273, (float)0.95305866, (float)0.95404440,
-    (float)0.95501995, (float)0.95598525, (float)0.95694035, (float)0.95788521,
-    (float)0.95881975, (float)0.95974404, (float)0.96065807, (float)0.96156180,
-    (float)0.96245527, (float)0.96333838, (float)0.96421117, (float)0.96507370,
-    (float)0.96592581, (float)0.96676767, (float)0.96759909, (float)0.96842021,
-    (float)0.96923089, (float)0.97003126, (float)0.97082120, (float)0.97160077,
-    (float)0.97236991, (float)0.97312868, (float)0.97387701, (float)0.97461486,
-    (float)0.97534233, (float)0.97605932, (float)0.97676587, (float)0.97746199,
-    (float)0.97814763, (float)0.97882277, (float)0.97948742, (float)0.98014158,
-    (float)0.98078531, (float)0.98141843, (float)0.98204112, (float)0.98265332,
-    (float)0.98325491, (float)0.98384601, (float)0.98442656, (float)0.98499662,
-    (float)0.98555607, (float)0.98610497, (float)0.98664331, (float)0.98717111,
-    (float)0.98768836, (float)0.98819500, (float)0.98869103, (float)0.98917651,
-    (float)0.98965138, (float)0.99011570, (float)0.99056935, (float)0.99101239,
-    (float)0.99144489, (float)0.99186671, (float)0.99227792, (float)0.99267852,
-    (float)0.99306846, (float)0.99344778, (float)0.99381649, (float)0.99417448,
-    (float)0.99452192, (float)0.99485862, (float)0.99518472, (float)0.99550015,
-    (float)0.99580491, (float)0.99609905, (float)0.99638247, (float)0.99665523,
-    (float)0.99691731, (float)0.99716878, (float)0.99740952, (float)0.99763954,
-    (float)0.99785894, (float)0.99806762, (float)0.99826562, (float)0.99845290,
-    (float)0.99862951, (float)0.99879545, (float)0.99895066, (float)0.99909520,
-    (float)0.99922901, (float)0.99935216, (float)0.99946457, (float)0.99956632,
-    (float)0.99965733, (float)0.99973762, (float)0.99980724, (float)0.99986613,
-    (float)0.99991435, (float)0.99995178, (float)0.99997860, (float)0.99999464,
-    (float)1.00000000, (float)0.99999464, (float)0.99997860, (float)0.99995178,
-    (float)0.99991435, (float)0.99986613, (float)0.99980724, (float)0.99973762,
-    (float)0.99965733, (float)0.99956632, (float)0.99946457, (float)0.99935216,
-    (float)0.99922901, (float)0.99909520, (float)0.99895066, (float)0.99879545,
-    (float)0.99862951, (float)0.99845290, (float)0.99826562, (float)0.99806762,
-    (float)0.99785894, (float)0.99763954, (float)0.99740946, (float)0.99716872,
-    (float)0.99691731, (float)0.99665523, (float)0.99638247, (float)0.99609905,
-    (float)0.99580491, (float)0.99550015, (float)0.99518472, (float)0.99485862,
-    (float)0.99452192, (float)0.99417448, (float)0.99381644, (float)0.99344778,
-    (float)0.99306846, (float)0.99267852, (float)0.99227792, (float)0.99186671,
-    (float)0.99144489, (float)0.99101239, (float)0.99056935, (float)0.99011564,
-    (float)0.98965138, (float)0.98917651, (float)0.98869103, (float)0.98819494,
-    (float)0.98768836, (float)0.98717111, (float)0.98664331, (float)0.98610497,
-    (float)0.98555607, (float)0.98499656, (float)0.98442656, (float)0.98384601,
-    (float)0.98325491, (float)0.98265326, (float)0.98204112, (float)0.98141843,
-    (float)0.98078525, (float)0.98014158, (float)0.97948742, (float)0.97882277,
-    (float)0.97814757, (float)0.97746193, (float)0.97676587, (float)0.97605932,
-    (float)0.97534227, (float)0.97461486, (float)0.97387695, (float)0.97312862,
-    (float)0.97236991, (float)0.97160077, (float)0.97082120, (float)0.97003126,
-    (float)0.96923089, (float)0.96842015, (float)0.96759909, (float)0.96676761,
-    (float)0.96592581, (float)0.96507365, (float)0.96421117, (float)0.96333838,
-    (float)0.96245521, (float)0.96156180, (float)0.96065807, (float)0.95974404,
-    (float)0.95881969, (float)0.95788515, (float)0.95694029, (float)0.95598525,
-    (float)0.95501995, (float)0.95404440, (float)0.95305860, (float)0.95206267,
-    (float)0.95105648, (float)0.95004016, (float)0.94901365, (float)0.94797695,
-    (float)0.94693011, (float)0.94587314, (float)0.94480604, (float)0.94372880,
-    (float)0.94264150, (float)0.94154406, (float)0.94043654, (float)0.93931895,
-    (float)0.93819129, (float)0.93705362, (float)0.93590593, (float)0.93474817,
-    (float)0.93358046, (float)0.93240267, (float)0.93121493, (float)0.93001723,
-    (float)0.92880952, (float)0.92759192, (float)0.92636436, (float)0.92512691,
-    (float)0.92387950, (float)0.92262226, (float)0.92135507, (float)0.92007804,
-    (float)0.91879123, (float)0.91749448, (float)0.91618794, (float)0.91487157,
-    (float)0.91354543, (float)0.91220951, (float)0.91086382, (float)0.90950835,
-    (float)0.90814310, (float)0.90676820, (float)0.90538365, (float)0.90398932,
-    (float)0.90258527, (float)0.90117157, (float)0.89974827, (float)0.89831525,
-    (float)0.89687276, (float)0.89542055, (float)0.89395875, (float)0.89248741,
-    (float)0.89100647, (float)0.88951600, (float)0.88801610, (float)0.88650662,
-    (float)0.88498759, (float)0.88345915, (float)0.88192123, (float)0.88037384,
-    (float)0.87881714, (float)0.87725091, (float)0.87567532, (float)0.87409031,
-    (float)0.87249595, (float)0.87089223, (float)0.86927933, (float)0.86765701,
-    (float)0.86602539, (float)0.86438447, (float)0.86273432, (float)0.86107504,
-    (float)0.85940641, (float)0.85772860, (float)0.85604161, (float)0.85434544,
-    (float)0.85264009, (float)0.85092574, (float)0.84920216, (float)0.84746951,
-    (float)0.84572780, (float)0.84397697, (float)0.84221715, (float)0.84044844,
-    (float)0.83867055, (float)0.83688372, (float)0.83508795, (float)0.83328319,
-    (float)0.83146954, (float)0.82964706, (float)0.82781565, (float)0.82597530,
-    (float)0.82412612, (float)0.82226813, (float)0.82040137, (float)0.81852591,
-    (float)0.81664157, (float)0.81474847, (float)0.81284660, (float)0.81093609,
-    (float)0.80901700, (float)0.80708915, (float)0.80515265, (float)0.80320752,
-    (float)0.80125374, (float)0.79929143, (float)0.79732066, (float)0.79534125,
-    (float)0.79335332, (float)0.79135686, (float)0.78935200, (float)0.78733861,
-    (float)0.78531694, (float)0.78328675, (float)0.78124815, (float)0.77920121,
-    (float)0.77714586, (float)0.77508223, (float)0.77301049, (float)0.77093029,
-    (float)0.76884180, (float)0.76674509, (float)0.76464021, (float)0.76252711,
-    (float)0.76040596, (float)0.75827658, (float)0.75613904, (float)0.75399339,
-    (float)0.75183970, (float)0.74967796, (float)0.74750835, (float)0.74533057,
-    (float)0.74314481, (float)0.74095106, (float)0.73874938, (float)0.73653996,
-    (float)0.73432249, (float)0.73209721, (float)0.72986400, (float)0.72762305,
-    (float)0.72537428, (float)0.72311789, (float)0.72085363, (float)0.71858162,
-    (float)0.71630186, (float)0.71401453, (float)0.71171951, (float)0.70941705,
-    (float)0.70710677, (float)0.70478898, (float)0.70246363, (float)0.70013070,
-    (float)0.69779032, (float)0.69544268, (float)0.69308734, (float)0.69072461,
-    (float)0.68835449, (float)0.68597704, (float)0.68359220, (float)0.68120021,
-    (float)0.67880070, (float)0.67639399, (float)0.67398006, (float)0.67155886,
-    (float)0.66913044, (float)0.66669512, (float)0.66425240, (float)0.66180259,
-    (float)0.65934575, (float)0.65688181, (float)0.65441096, (float)0.65193301,
-    (float)0.64944804, (float)0.64695609, (float)0.64445722, (float)0.64195150,
-    (float)0.63943905, (float)0.63691956, (float)0.63439327, (float)0.63186014,
-    (float)0.62932026, (float)0.62677372, (float)0.62422055, (float)0.62166059,
-    (float)0.61909389, (float)0.61652064, (float)0.61394072, (float)0.61135429,
-    (float)0.60876143, (float)0.60616189, (float)0.60355592, (float)0.60094339,
-    (float)0.59832448, (float)0.59569913, (float)0.59306765, (float)0.59042960,
-    (float)0.58778518, (float)0.58513451, (float)0.58247757, (float)0.57981461,
-    (float)0.57714522, (float)0.57446963, (float)0.57178789, (float)0.56910002,
-    (float)0.56640613, (float)0.56370628, (float)0.56100023, (float)0.55828822,
-    (float)0.55557019, (float)0.55284619, (float)0.55011630, (float)0.54738069,
-    (float)0.54463905, (float)0.54189152, (float)0.53913826, (float)0.53637916,
-    (float)0.53361434, (float)0.53084403, (float)0.52806783, (float)0.52528596,
-    (float)0.52249849, (float)0.51970541, (float)0.51690674, (float)0.51410276,
-    (float)0.51129305, (float)0.50847787, (float)0.50565726, (float)0.50283122,
-    (float)0.50000006, (float)0.49716327, (float)0.49432117, (float)0.49147379,
-    (float)0.48862115, (float)0.48576325, (float)0.48290038, (float)0.48003212,
-    (float)0.47715873, (float)0.47428021, (float)0.47139663, (float)0.46850798,
-    (float)0.46561456, (float)0.46271589, (float)0.45981231, (float)0.45690379,
-    (float)0.45399037, (float)0.45107210, (float)0.44814920, (float)0.44522130,
-    (float)0.44228864, (float)0.43935123, (float)0.43640912, (float)0.43346232,
-    (float)0.43051112, (float)0.42755505, (float)0.42459446, (float)0.42162928,
-    (float)0.41865960, (float)0.41568545, (float)0.41270703, (float)0.40972400,
-    (float)0.40673658, (float)0.40374479, (float)0.40074870, (float)0.39774850,
-    (float)0.39474386, (float)0.39173496, (float)0.38872188, (float)0.38570464,
-    (float)0.38268328, (float)0.37965804, (float)0.37662849, (float)0.37359491,
-    (float)0.37055734, (float)0.36751580, (float)0.36447033, (float)0.36142117,
-    (float)0.35836792, (float)0.35531086, (float)0.35224995, (float)0.34918529,
-    (float)0.34611690, (float)0.34304500, (float)0.33996922, (float)0.33688980,
-    (float)0.33380675, (float)0.33072016, (float)0.32763001, (float)0.32453656,
-    (float)0.32143945, (float)0.31833887, (float)0.31523487, (float)0.31212750,
-    (float)0.30901679, (float)0.30590302, (float)0.30278572, (float)0.29966521,
-    (float)0.29654145, (float)0.29341453, (float)0.29028472, (float)0.28715155,
-    (float)0.28401530, (float)0.28087601, (float)0.27773371, (float)0.27458847,
-    (float)0.27144048, (float)0.26828936, (float)0.26513538, (float)0.26197854,
-    (float)0.25881892, (float)0.25565651, (float)0.25249159, (float)0.24932374,
-    (float)0.24615324, (float)0.24298008, (float)0.23980433, (float)0.23662600,
-    (float)0.23344538, (float)0.23026201, (float)0.22707619, (float)0.22388794,
-    (float)0.22069728, (float)0.21750426, (float)0.21430916, (float)0.21111152,
-    (float)0.20791161, (float)0.20470949, (float)0.20150517, (float)0.19829892,
-    (float)0.19509031, (float)0.19187963, (float)0.18866688, (float)0.18545210,
-    (float)0.18223536, (float)0.17901689, (float)0.17579627, (float)0.17257376,
-    (float)0.16934940, (float)0.16612324, (float)0.16289529, (float)0.15966584,
-    (float)0.15643445, (float)0.15320137, (float)0.14996666, (float)0.14673033,
-    (float)0.14349243, (float)0.14025325, (float)0.13701232, (float)0.13376991,
-    (float)0.13052608, (float)0.12728085, (float)0.12403426, (float)0.12078657,
-    (float)0.11753736, (float)0.11428688, (float)0.11103519, (float)0.10778230,
-    (float)0.10452849, (float)0.10127334, (float)0.09801710, (float)0.09475980,
-    (float)0.09150149, (float)0.08824220, (float)0.08498220, (float)0.08172106,
-    (float)0.07845904, (float)0.07519618, (float)0.07193252, (float)0.06866808,
-    (float)0.06540315, (float)0.06213728, (float)0.05887074, (float)0.05560357,
-    (float)0.05233581, (float)0.04906749, (float)0.04579888, (float)0.04252954,
-    (float)0.03925974, (float)0.03598953, (float)0.03271893, (float)0.02944798,
-    (float)0.02617695, (float)0.02290541, (float)0.01963361, (float)0.01636161,
-    (float)0.01308943, (float)0.00981712, (float)0.00654493, (float)0.00327244,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000,
-    (float)0.00000000, (float)0.00000000, (float)0.00000000, (float)0.00000000};
-
-#endif  // MODULES_AUDIO_PROCESSING_NS_MAIN_SOURCE_WINDOWS_PRIVATE_H_
diff --git a/modules/audio_processing/test/audio_processing_simulator.cc b/modules/audio_processing/test/audio_processing_simulator.cc
index 8c6a46d..7f354a9 100644
--- a/modules/audio_processing/test/audio_processing_simulator.cc
+++ b/modules/audio_processing/test/audio_processing_simulator.cc
@@ -504,6 +504,12 @@
         *settings_.maximum_internal_processing_rate;
   }
 
+  const bool use_legacy_ns =
+      settings_.use_legacy_ns && *settings_.use_legacy_ns;
+  if (use_legacy_ns) {
+    apm_config.noise_suppression.use_legacy_ns = use_legacy_ns;
+  }
+
   if (settings_.use_ns) {
     apm_config.noise_suppression.enabled = *settings_.use_ns;
   }
diff --git a/modules/audio_processing/test/audio_processing_simulator.h b/modules/audio_processing/test/audio_processing_simulator.h
index 340c9d3..bf718b2 100644
--- a/modules/audio_processing/test/audio_processing_simulator.h
+++ b/modules/audio_processing/test/audio_processing_simulator.h
@@ -65,6 +65,7 @@
   absl::optional<bool> use_extended_filter;
   absl::optional<bool> use_drift_compensation;
   absl::optional<bool> use_legacy_aec;
+  absl::optional<bool> use_legacy_ns;
   absl::optional<bool> use_experimental_agc;
   absl::optional<bool> use_experimental_agc_agc2_level_estimator;
   absl::optional<bool> experimental_agc_disable_digital_adaptive;
diff --git a/modules/audio_processing/test/audioproc_float_impl.cc b/modules/audio_processing/test/audioproc_float_impl.cc
index 6428e9d..3e755b5 100644
--- a/modules/audio_processing/test/audioproc_float_impl.cc
+++ b/modules/audio_processing/test/audioproc_float_impl.cc
@@ -130,6 +130,10 @@
           kParameterNotSpecifiedValue,
           "Activate (1) or deactivate(0) the legacy AEC");
 ABSL_FLAG(int,
+          use_legacy_ns,
+          kParameterNotSpecifiedValue,
+          "Activate (1) or deactivate(0) the legacy AEC");
+ABSL_FLAG(int,
           experimental_agc,
           kParameterNotSpecifiedValue,
           "Activate (1) or deactivate(0) the experimental AGC");
@@ -393,6 +397,8 @@
 
   SetSettingIfFlagSet(absl::GetFlag(FLAGS_use_legacy_aec),
                       &settings.use_legacy_aec);
+  SetSettingIfFlagSet(absl::GetFlag(FLAGS_use_legacy_ns),
+                      &settings.use_legacy_ns);
   SetSettingIfFlagSet(absl::GetFlag(FLAGS_experimental_agc),
                       &settings.use_experimental_agc);
   SetSettingIfFlagSet(
diff --git a/modules/audio_processing/transient/transient_suppressor.cc b/modules/audio_processing/transient/transient_suppressor.cc
index 2463efa..b10b055 100644
--- a/modules/audio_processing/transient/transient_suppressor.cc
+++ b/modules/audio_processing/transient/transient_suppressor.cc
@@ -20,7 +20,7 @@
 #include "common_audio/include/audio_util.h"
 #include "common_audio/signal_processing/include/signal_processing_library.h"
 #include "common_audio/third_party/fft4g/fft4g.h"
-#include "modules/audio_processing/ns/windows_private.h"
+#include "modules/audio_processing/legacy_ns/windows_private.h"
 #include "modules/audio_processing/transient/common.h"
 #include "modules/audio_processing/transient/transient_detector.h"
 #include "rtc_base/checks.h"