Reland "Refactoring of the noise suppressor and adding true multichannel support"
This is a reland of 87a7b82520b83a6cf42da27cdc46142c2eb6248c
Original change's description:
> Refactoring of the noise suppressor and adding true multichannel support
>
> This CL adds proper multichannel support to the noise suppressor.
> To accomplish that in a safe way, a full refactoring of the noise
> suppressor code has been done.
>
> Due to floating point precision, the changes made are not entirely
> bitexact. They are, however, very close to being bitexact.
>
> As a safety measure, the former noise suppressor code is preserved
> and a kill-switch is added to allow revering to the legacy noise
> suppressor in case issues arise.
>
> Bug: webrtc:10895, b/143344262
> Change-Id: I0b071011b23265ac12e6d4b3956499d122286657
> Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158407
> Commit-Queue: Per Åhgren <peah@webrtc.org>
> Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
> Cr-Commit-Position: refs/heads/master@{#29646}
Bug: webrtc:10895, b/143344262
Change-Id: I236f1e67bb0baa4e30908a4cf7a8a7bb55fbced3
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/158747
Reviewed-by: Gustaf Ullberg <gustaf@webrtc.org>
Commit-Queue: Per Åhgren <peah@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#29663}
diff --git a/modules/audio_processing/legacy_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/legacy_ns/noise_suppression.c b/modules/audio_processing/legacy_ns/noise_suppression.c
new file mode 100644
index 0000000..8b95640
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/noise_suppression.c
@@ -0,0 +1,71 @@
+/*
+ * 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.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "common_audio/signal_processing/include/signal_processing_library.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));
+ self->initFlag = 0;
+ return (NsHandle*)self;
+}
+
+void WebRtcNs_Free(NsHandle* NS_inst) {
+ free(NS_inst);
+}
+
+int WebRtcNs_Init(NsHandle* NS_inst, uint32_t fs) {
+ return WebRtcNs_InitCore((NoiseSuppressionC*)NS_inst, fs);
+}
+
+int WebRtcNs_set_policy(NsHandle* NS_inst, int mode) {
+ return WebRtcNs_set_policy_core((NoiseSuppressionC*)NS_inst, mode);
+}
+
+void WebRtcNs_Analyze(NsHandle* NS_inst, const float* spframe) {
+ WebRtcNs_AnalyzeCore((NoiseSuppressionC*)NS_inst, spframe);
+}
+
+void WebRtcNs_Process(NsHandle* NS_inst,
+ const float* const* spframe,
+ size_t num_bands,
+ float* const* outframe) {
+ WebRtcNs_ProcessCore((NoiseSuppressionC*)NS_inst, spframe, num_bands,
+ outframe);
+}
+
+float WebRtcNs_prior_speech_probability(NsHandle* handle) {
+ NoiseSuppressionC* self = (NoiseSuppressionC*)handle;
+ if (handle == NULL) {
+ return -1;
+ }
+ if (self->initFlag == 0) {
+ return -1;
+ }
+ return self->priorSpeechProb;
+}
+
+const float* WebRtcNs_noise_estimate(const NsHandle* handle) {
+ const NoiseSuppressionC* self = (const NoiseSuppressionC*)handle;
+ if (handle == NULL || self->initFlag == 0) {
+ return NULL;
+ }
+ return self->noise;
+}
+
+size_t WebRtcNs_num_freq() {
+ return HALF_ANAL_BLOCKL;
+}
diff --git a/modules/audio_processing/legacy_ns/noise_suppression.h b/modules/audio_processing/legacy_ns/noise_suppression.h
new file mode 100644
index 0000000..01f04cc
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/noise_suppression.h
@@ -0,0 +1,134 @@
+/*
+ * 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_LEGACY_NS_NOISE_SUPPRESSION_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct NsHandleT NsHandle;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This function creates an instance of the floating point Noise Suppression.
+ */
+NsHandle* WebRtcNs_Create(void);
+
+/*
+ * This function frees the dynamic memory of a specified noise suppression
+ * instance.
+ *
+ * Input:
+ * - NS_inst : Pointer to NS instance that should be freed
+ */
+void WebRtcNs_Free(NsHandle* NS_inst);
+
+/*
+ * This function initializes a NS instance and has to be called before any other
+ * processing is made.
+ *
+ * Input:
+ * - NS_inst : Instance that should be initialized
+ * - fs : sampling frequency
+ *
+ * Output:
+ * - NS_inst : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcNs_Init(NsHandle* NS_inst, uint32_t fs);
+
+/*
+ * This changes the aggressiveness of the noise suppression method.
+ *
+ * Input:
+ * - NS_inst : Noise suppression instance.
+ * - mode : 0: Mild, 1: Medium , 2: Aggressive
+ *
+ * Output:
+ * - NS_inst : Updated instance.
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcNs_set_policy(NsHandle* NS_inst, int mode);
+
+/*
+ * This functions estimates the background noise for the inserted speech frame.
+ * The input and output signals should always be 10ms (80 or 160 samples).
+ *
+ * Input
+ * - NS_inst : Noise suppression instance.
+ * - spframe : Pointer to speech frame buffer for L band
+ *
+ * Output:
+ * - NS_inst : Updated NS instance
+ */
+void WebRtcNs_Analyze(NsHandle* NS_inst, const float* spframe);
+
+/*
+ * This functions does Noise Suppression for the inserted speech frame. The
+ * input and output signals should always be 10ms (80 or 160 samples).
+ *
+ * Input
+ * - NS_inst : Noise suppression instance.
+ * - spframe : Pointer to speech frame buffer for each band
+ * - num_bands : Number of bands
+ *
+ * Output:
+ * - NS_inst : Updated NS instance
+ * - outframe : Pointer to output frame for each band
+ */
+void WebRtcNs_Process(NsHandle* NS_inst,
+ const float* const* spframe,
+ size_t num_bands,
+ float* const* outframe);
+
+/* Returns the internally used prior speech probability of the current frame.
+ * There is a frequency bin based one as well, with which this should not be
+ * confused.
+ *
+ * Input
+ * - handle : Noise suppression instance.
+ *
+ * Return value : Prior speech probability in interval [0.0, 1.0].
+ * -1 - NULL pointer or uninitialized instance.
+ */
+float WebRtcNs_prior_speech_probability(NsHandle* handle);
+
+/* Returns a pointer to the noise estimate per frequency bin. The number of
+ * frequency bins can be provided using WebRtcNs_num_freq().
+ *
+ * Input
+ * - handle : Noise suppression instance.
+ *
+ * Return value : Pointer to the noise estimate per frequency bin.
+ * Returns NULL if the input is a NULL pointer or an
+ * uninitialized instance.
+ */
+const float* WebRtcNs_noise_estimate(const NsHandle* handle);
+
+/* Returns the number of frequency bins, which is the length of the noise
+ * estimate for example.
+ *
+ * Return value : Number of frequency bins.
+ */
+size_t WebRtcNs_num_freq(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_H_
diff --git a/modules/audio_processing/legacy_ns/noise_suppression_x.c b/modules/audio_processing/legacy_ns/noise_suppression_x.c
new file mode 100644
index 0000000..faa866e
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/noise_suppression_x.c
@@ -0,0 +1,60 @@
+/*
+ * 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 <stdlib.h>
+
+#include "common_audio/signal_processing/include/real_fft.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));
+ self->real_fft = NULL;
+ self->initFlag = 0;
+ return (NsxHandle*)self;
+}
+
+void WebRtcNsx_Free(NsxHandle* nsxInst) {
+ WebRtcSpl_FreeRealFFT(((NoiseSuppressionFixedC*)nsxInst)->real_fft);
+ free(nsxInst);
+}
+
+int WebRtcNsx_Init(NsxHandle* nsxInst, uint32_t fs) {
+ return WebRtcNsx_InitCore((NoiseSuppressionFixedC*)nsxInst, fs);
+}
+
+int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode) {
+ return WebRtcNsx_set_policy_core((NoiseSuppressionFixedC*)nsxInst, mode);
+}
+
+void WebRtcNsx_Process(NsxHandle* nsxInst,
+ const int16_t* const* speechFrame,
+ int num_bands,
+ int16_t* const* outFrame) {
+ WebRtcNsx_ProcessCore((NoiseSuppressionFixedC*)nsxInst, speechFrame,
+ num_bands, outFrame);
+}
+
+const uint32_t* WebRtcNsx_noise_estimate(const NsxHandle* nsxInst,
+ int* q_noise) {
+ *q_noise = 11;
+ const NoiseSuppressionFixedC* self = (const NoiseSuppressionFixedC*)nsxInst;
+ if (nsxInst == NULL || self->initFlag == 0) {
+ return NULL;
+ }
+ *q_noise += self->prevQNoise;
+ return self->prevNoiseU32;
+}
+
+size_t WebRtcNsx_num_freq() {
+ return HALF_ANAL_BLOCKL;
+}
diff --git a/modules/audio_processing/legacy_ns/noise_suppression_x.h b/modules/audio_processing/legacy_ns/noise_suppression_x.h
new file mode 100644
index 0000000..572db41
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/noise_suppression_x.h
@@ -0,0 +1,112 @@
+/*
+ * 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_LEGACY_NS_NOISE_SUPPRESSION_X_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_X_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct NsxHandleT NsxHandle;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This function creates an instance of the fixed point Noise Suppression.
+ */
+NsxHandle* WebRtcNsx_Create(void);
+
+/*
+ * This function frees the dynamic memory of a specified Noise Suppression
+ * instance.
+ *
+ * Input:
+ * - nsxInst : Pointer to NS instance that should be freed
+ */
+void WebRtcNsx_Free(NsxHandle* nsxInst);
+
+/*
+ * This function initializes a NS instance
+ *
+ * Input:
+ * - nsxInst : Instance that should be initialized
+ * - fs : sampling frequency
+ *
+ * Output:
+ * - nsxInst : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcNsx_Init(NsxHandle* nsxInst, uint32_t fs);
+
+/*
+ * This changes the aggressiveness of the noise suppression method.
+ *
+ * Input:
+ * - nsxInst : Instance that should be initialized
+ * - mode : 0: Mild, 1: Medium , 2: Aggressive
+ *
+ * Output:
+ * - nsxInst : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcNsx_set_policy(NsxHandle* nsxInst, int mode);
+
+/*
+ * This functions does noise suppression for the inserted speech frame. The
+ * input and output signals should always be 10ms (80 or 160 samples).
+ *
+ * Input
+ * - nsxInst : NSx instance. Needs to be initiated before call.
+ * - speechFrame : Pointer to speech frame buffer for each band
+ * - num_bands : Number of bands
+ *
+ * Output:
+ * - nsxInst : Updated NSx instance
+ * - outFrame : Pointer to output frame for each band
+ */
+void WebRtcNsx_Process(NsxHandle* nsxInst,
+ const int16_t* const* speechFrame,
+ int num_bands,
+ 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().
+ *
+ * Input
+ * - nsxInst : NSx instance. Needs to be initiated before call.
+ * - q_noise : Q value of the noise estimate, which is the number of
+ * bits that it needs to be right-shifted to be
+ * normalized.
+ *
+ * Return value : Pointer to the noise estimate per frequency bin.
+ * Returns NULL if the input is a NULL pointer or an
+ * uninitialized instance.
+ */
+const uint32_t* WebRtcNsx_noise_estimate(const NsxHandle* nsxInst,
+ int* q_noise);
+
+/* Returns the number of frequency bins, which is the length of the noise
+ * estimate for example.
+ *
+ * Return value : Number of frequency bins.
+ */
+size_t WebRtcNsx_num_freq(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MODULES_AUDIO_PROCESSING_LEGACY_NS_NOISE_SUPPRESSION_X_H_
diff --git a/modules/audio_processing/legacy_ns/ns_core.c b/modules/audio_processing/legacy_ns/ns_core.c
new file mode 100644
index 0000000..b5dc829
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/ns_core.c
@@ -0,0 +1,1420 @@
+/*
+ * 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 <math.h>
+#include <string.h>
+#include <stdlib.h>
+
+#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/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) {
+ // Bin size of histogram.
+ self->featureExtractionParams.binSizeLrt = 0.1f;
+ self->featureExtractionParams.binSizeSpecFlat = 0.05f;
+ self->featureExtractionParams.binSizeSpecDiff = 0.1f;
+
+ // Range of histogram over which LRT threshold is computed.
+ self->featureExtractionParams.rangeAvgHistLrt = 1.f;
+
+ // Scale parameters: multiply dominant peaks of the histograms by scale factor
+ // to obtain thresholds for prior model.
+ // For LRT and spectral difference.
+ self->featureExtractionParams.factor1ModelPars = 1.2f;
+ // For spectral_flatness: used when noise is flatter than speech.
+ self->featureExtractionParams.factor2ModelPars = 0.9f;
+
+ // Peak limit for spectral flatness (varies between 0 and 1).
+ self->featureExtractionParams.thresPosSpecFlat = 0.6f;
+
+ // Limit on spacing of two highest peaks in histogram: spacing determined by
+ // bin size.
+ self->featureExtractionParams.limitPeakSpacingSpecFlat =
+ 2 * self->featureExtractionParams.binSizeSpecFlat;
+ self->featureExtractionParams.limitPeakSpacingSpecDiff =
+ 2 * self->featureExtractionParams.binSizeSpecDiff;
+
+ // Limit on relevance of second peak.
+ self->featureExtractionParams.limitPeakWeightsSpecFlat = 0.5f;
+ self->featureExtractionParams.limitPeakWeightsSpecDiff = 0.5f;
+
+ // Fluctuation limit of LRT feature.
+ self->featureExtractionParams.thresFluctLrt = 0.05f;
+
+ // Limit on the max and min values for the feature thresholds.
+ self->featureExtractionParams.maxLrt = 1.f;
+ self->featureExtractionParams.minLrt = 0.2f;
+
+ self->featureExtractionParams.maxSpecFlat = 0.95f;
+ self->featureExtractionParams.minSpecFlat = 0.1f;
+
+ self->featureExtractionParams.maxSpecDiff = 1.f;
+ self->featureExtractionParams.minSpecDiff = 0.16f;
+
+ // Criteria of weight of histogram peak to accept/reject feature.
+ self->featureExtractionParams.thresWeightSpecFlat =
+ (int)(0.3 * (self->modelUpdatePars[1])); // For spectral flatness.
+ self->featureExtractionParams.thresWeightSpecDiff =
+ (int)(0.3 * (self->modelUpdatePars[1])); // For spectral difference.
+}
+
+// Initialize state.
+int WebRtcNs_InitCore(NoiseSuppressionC* self, uint32_t fs) {
+ int i;
+ // Check for valid pointer.
+ if (self == NULL) {
+ return -1;
+ }
+
+ // Initialization of struct.
+ if (fs == 8000 || fs == 16000 || fs == 32000 || fs == 48000) {
+ self->fs = fs;
+ } else {
+ return -1;
+ }
+ self->windShift = 0;
+ // We only support 10ms frames.
+ if (fs == 8000) {
+ self->blockLen = 80;
+ self->anaLen = 128;
+ self->window = kBlocks80w128;
+ } else {
+ self->blockLen = 160;
+ self->anaLen = 256;
+ self->window = kBlocks160w256;
+ }
+ self->magnLen = self->anaLen / 2 + 1; // Number of frequency bins.
+
+ // Initialize FFT work arrays.
+ self->ip[0] = 0; // Setting this triggers initialization.
+ memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+ WebRtc_rdft(self->anaLen, 1, self->dataBuf, self->ip, self->wfft);
+
+ memset(self->analyzeBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+ memset(self->dataBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+ memset(self->syntBuf, 0, sizeof(float) * ANAL_BLOCKL_MAX);
+
+ // For HB processing.
+ memset(self->dataBufHB,
+ 0,
+ sizeof(float) * NUM_HIGH_BANDS_MAX * ANAL_BLOCKL_MAX);
+
+ // For quantile noise estimation.
+ memset(self->quantile, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ for (i = 0; i < SIMULT * HALF_ANAL_BLOCKL; i++) {
+ self->lquantile[i] = 8.f;
+ self->density[i] = 0.3f;
+ }
+
+ for (i = 0; i < SIMULT; i++) {
+ self->counter[i] =
+ (int)floor((float)(END_STARTUP_LONG * (i + 1)) / (float)SIMULT);
+ }
+
+ self->updates = 0;
+
+ // Wiener filter initialization.
+ for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
+ self->smooth[i] = 1.f;
+ }
+
+ // Set the aggressiveness: default.
+ self->aggrMode = 0;
+
+ // Initialize variables for new method.
+ self->priorSpeechProb = 0.5f; // Prior prob for speech/noise.
+ // Previous analyze mag spectrum.
+ memset(self->magnPrevAnalyze, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ // Previous process mag spectrum.
+ memset(self->magnPrevProcess, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ // Current noise-spectrum.
+ memset(self->noise, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ // Previous noise-spectrum.
+ memset(self->noisePrev, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ // Conservative noise spectrum estimate.
+ memset(self->magnAvgPause, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ // For estimation of HB in second pass.
+ memset(self->speechProb, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ // Initial average magnitude spectrum.
+ memset(self->initMagnEst, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+ for (i = 0; i < HALF_ANAL_BLOCKL; i++) {
+ // Smooth LR (same as threshold).
+ self->logLrtTimeAvg[i] = LRT_FEATURE_THR;
+ }
+
+ // Feature quantities.
+ // Spectral flatness (start on threshold).
+ self->featureData[0] = SF_FEATURE_THR;
+ self->featureData[1] = 0.f; // Spectral entropy: not used in this version.
+ self->featureData[2] = 0.f; // Spectral variance: not used in this version.
+ // Average LRT factor (start on threshold).
+ self->featureData[3] = LRT_FEATURE_THR;
+ // Spectral template diff (start on threshold).
+ self->featureData[4] = SF_FEATURE_THR;
+ self->featureData[5] = 0.f; // Normalization for spectral difference.
+ // Window time-average of input magnitude spectrum.
+ self->featureData[6] = 0.f;
+
+ memset(self->parametricNoise, 0, sizeof(float) * HALF_ANAL_BLOCKL);
+
+ // Histogram quantities: used to estimate/update thresholds for features.
+ memset(self->histLrt, 0, sizeof(int) * HIST_PAR_EST);
+ memset(self->histSpecFlat, 0, sizeof(int) * HIST_PAR_EST);
+ memset(self->histSpecDiff, 0, sizeof(int) * HIST_PAR_EST);
+
+
+ self->blockInd = -1; // Frame counter.
+ // Default threshold for LRT feature.
+ self->priorModelPars[0] = LRT_FEATURE_THR;
+ // Threshold for spectral flatness: determined on-line.
+ self->priorModelPars[1] = 0.5f;
+ // sgn_map par for spectral measure: 1 for flatness measure.
+ self->priorModelPars[2] = 1.f;
+ // Threshold for template-difference feature: determined on-line.
+ self->priorModelPars[3] = 0.5f;
+ // Default weighting parameter for LRT feature.
+ self->priorModelPars[4] = 1.f;
+ // Default weighting parameter for spectral flatness feature.
+ self->priorModelPars[5] = 0.f;
+ // Default weighting parameter for spectral difference feature.
+ self->priorModelPars[6] = 0.f;
+
+ // Update flag for parameters:
+ // 0 no update, 1 = update once, 2 = update every window.
+ self->modelUpdatePars[0] = 2;
+ self->modelUpdatePars[1] = 500; // Window for update.
+ // Counter for update of conservative noise spectrum.
+ self->modelUpdatePars[2] = 0;
+ // Counter if the feature thresholds are updated during the sequence.
+ self->modelUpdatePars[3] = self->modelUpdatePars[1];
+
+ self->signalEnergy = 0.0;
+ self->sumMagn = 0.0;
+ self->whiteNoiseLevel = 0.0;
+ self->pinkNoiseNumerator = 0.0;
+ self->pinkNoiseExp = 0.0;
+
+ set_feature_extraction_parameters(self);
+
+ // Default mode.
+ WebRtcNs_set_policy_core(self, 0);
+
+ self->initFlag = 1;
+ return 0;
+}
+
+// Estimate noise.
+static void NoiseEstimation(NoiseSuppressionC* self,
+ float* magn,
+ float* noise) {
+ size_t i, s, offset;
+ float lmagn[HALF_ANAL_BLOCKL], delta;
+
+ if (self->updates < END_STARTUP_LONG) {
+ self->updates++;
+ }
+
+ for (i = 0; i < self->magnLen; i++) {
+ lmagn[i] = (float)log(magn[i]);
+ }
+
+ // Loop over simultaneous estimates.
+ for (s = 0; s < SIMULT; s++) {
+ offset = s * self->magnLen;
+
+ // newquantest(...)
+ for (i = 0; i < self->magnLen; i++) {
+ // Compute delta.
+ if (self->density[offset + i] > 1.0) {
+ delta = FACTOR * 1.f / self->density[offset + i];
+ } else {
+ delta = FACTOR;
+ }
+
+ // Update log quantile estimate.
+ if (lmagn[i] > self->lquantile[offset + i]) {
+ self->lquantile[offset + i] +=
+ QUANTILE * delta / (float)(self->counter[s] + 1);
+ } else {
+ self->lquantile[offset + i] -=
+ (1.f - QUANTILE) * delta / (float)(self->counter[s] + 1);
+ }
+
+ // Update density estimate.
+ if (fabs(lmagn[i] - self->lquantile[offset + i]) < WIDTH) {
+ self->density[offset + i] =
+ ((float)self->counter[s] * self->density[offset + i] +
+ 1.f / (2.f * WIDTH)) /
+ (float)(self->counter[s] + 1);
+ }
+ } // End loop over magnitude spectrum.
+
+ if (self->counter[s] >= END_STARTUP_LONG) {
+ self->counter[s] = 0;
+ if (self->updates >= END_STARTUP_LONG) {
+ for (i = 0; i < self->magnLen; i++) {
+ self->quantile[i] = (float)exp(self->lquantile[offset + i]);
+ }
+ }
+ }
+
+ self->counter[s]++;
+ } // End loop over simultaneous estimates.
+
+ // Sequentially update the noise during startup.
+ if (self->updates < END_STARTUP_LONG) {
+ // Use the last "s" to get noise during startup that differ from zero.
+ for (i = 0; i < self->magnLen; i++) {
+ self->quantile[i] = (float)exp(self->lquantile[offset + i]);
+ }
+ }
+
+ for (i = 0; i < self->magnLen; i++) {
+ noise[i] = self->quantile[i];
+ }
+}
+
+// Extract thresholds for feature parameters.
+// Histograms are computed over some window size (given by
+// self->modelUpdatePars[1]).
+// Thresholds and weights are extracted every window.
+// |flag| = 0 updates histogram only, |flag| = 1 computes the threshold/weights.
+// Threshold and weights are returned in: self->priorModelPars.
+static void FeatureParameterExtraction(NoiseSuppressionC* self, int flag) {
+ int i, useFeatureSpecFlat, useFeatureSpecDiff, numHistLrt;
+ int maxPeak1, maxPeak2;
+ int weightPeak1SpecFlat, weightPeak2SpecFlat, weightPeak1SpecDiff,
+ weightPeak2SpecDiff;
+
+ float binMid, featureSum;
+ float posPeak1SpecFlat, posPeak2SpecFlat, posPeak1SpecDiff, posPeak2SpecDiff;
+ float fluctLrt, avgHistLrt, avgSquareHistLrt, avgHistLrtCompl;
+
+ // 3 features: LRT, flatness, difference.
+ // lrt_feature = self->featureData[3];
+ // flat_feature = self->featureData[0];
+ // diff_feature = self->featureData[4];
+
+ // Update histograms.
+ if (flag == 0) {
+ // LRT
+ if ((self->featureData[3] <
+ HIST_PAR_EST * self->featureExtractionParams.binSizeLrt) &&
+ (self->featureData[3] >= 0.0)) {
+ i = (int)(self->featureData[3] /
+ self->featureExtractionParams.binSizeLrt);
+ self->histLrt[i]++;
+ }
+ // Spectral flatness.
+ if ((self->featureData[0] <
+ HIST_PAR_EST * self->featureExtractionParams.binSizeSpecFlat) &&
+ (self->featureData[0] >= 0.0)) {
+ i = (int)(self->featureData[0] /
+ self->featureExtractionParams.binSizeSpecFlat);
+ self->histSpecFlat[i]++;
+ }
+ // Spectral difference.
+ if ((self->featureData[4] <
+ HIST_PAR_EST * self->featureExtractionParams.binSizeSpecDiff) &&
+ (self->featureData[4] >= 0.0)) {
+ i = (int)(self->featureData[4] /
+ self->featureExtractionParams.binSizeSpecDiff);
+ self->histSpecDiff[i]++;
+ }
+ }
+
+ // Extract parameters for speech/noise probability.
+ if (flag == 1) {
+ // LRT feature: compute the average over
+ // self->featureExtractionParams.rangeAvgHistLrt.
+ avgHistLrt = 0.0;
+ avgHistLrtCompl = 0.0;
+ avgSquareHistLrt = 0.0;
+ numHistLrt = 0;
+ for (i = 0; i < HIST_PAR_EST; i++) {
+ binMid = ((float)i + 0.5f) * self->featureExtractionParams.binSizeLrt;
+ if (binMid <= self->featureExtractionParams.rangeAvgHistLrt) {
+ avgHistLrt += self->histLrt[i] * binMid;
+ numHistLrt += self->histLrt[i];
+ }
+ avgSquareHistLrt += self->histLrt[i] * binMid * binMid;
+ avgHistLrtCompl += self->histLrt[i] * binMid;
+ }
+ if (numHistLrt > 0) {
+ avgHistLrt = avgHistLrt / ((float)numHistLrt);
+ }
+ avgHistLrtCompl = avgHistLrtCompl / ((float)self->modelUpdatePars[1]);
+ avgSquareHistLrt = avgSquareHistLrt / ((float)self->modelUpdatePars[1]);
+ fluctLrt = avgSquareHistLrt - avgHistLrt * avgHistLrtCompl;
+ // Get threshold for LRT feature.
+ if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
+ // Very low fluctuation, so likely noise.
+ self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
+ } else {
+ self->priorModelPars[0] =
+ self->featureExtractionParams.factor1ModelPars * avgHistLrt;
+ // Check if value is within min/max range.
+ if (self->priorModelPars[0] < self->featureExtractionParams.minLrt) {
+ self->priorModelPars[0] = self->featureExtractionParams.minLrt;
+ }
+ if (self->priorModelPars[0] > self->featureExtractionParams.maxLrt) {
+ self->priorModelPars[0] = self->featureExtractionParams.maxLrt;
+ }
+ }
+ // Done with LRT feature.
+
+ // For spectral flatness and spectral difference: compute the main peaks of
+ // histogram.
+ maxPeak1 = 0;
+ maxPeak2 = 0;
+ posPeak1SpecFlat = 0.0;
+ posPeak2SpecFlat = 0.0;
+ weightPeak1SpecFlat = 0;
+ weightPeak2SpecFlat = 0;
+
+ // Peaks for flatness.
+ for (i = 0; i < HIST_PAR_EST; i++) {
+ binMid =
+ (i + 0.5f) * self->featureExtractionParams.binSizeSpecFlat;
+ if (self->histSpecFlat[i] > maxPeak1) {
+ // Found new "first" peak.
+ maxPeak2 = maxPeak1;
+ weightPeak2SpecFlat = weightPeak1SpecFlat;
+ posPeak2SpecFlat = posPeak1SpecFlat;
+
+ maxPeak1 = self->histSpecFlat[i];
+ weightPeak1SpecFlat = self->histSpecFlat[i];
+ posPeak1SpecFlat = binMid;
+ } else if (self->histSpecFlat[i] > maxPeak2) {
+ // Found new "second" peak.
+ maxPeak2 = self->histSpecFlat[i];
+ weightPeak2SpecFlat = self->histSpecFlat[i];
+ posPeak2SpecFlat = binMid;
+ }
+ }
+
+ // Compute two peaks for spectral difference.
+ maxPeak1 = 0;
+ maxPeak2 = 0;
+ posPeak1SpecDiff = 0.0;
+ posPeak2SpecDiff = 0.0;
+ weightPeak1SpecDiff = 0;
+ weightPeak2SpecDiff = 0;
+ // Peaks for spectral difference.
+ for (i = 0; i < HIST_PAR_EST; i++) {
+ binMid =
+ ((float)i + 0.5f) * self->featureExtractionParams.binSizeSpecDiff;
+ if (self->histSpecDiff[i] > maxPeak1) {
+ // Found new "first" peak.
+ maxPeak2 = maxPeak1;
+ weightPeak2SpecDiff = weightPeak1SpecDiff;
+ posPeak2SpecDiff = posPeak1SpecDiff;
+
+ maxPeak1 = self->histSpecDiff[i];
+ weightPeak1SpecDiff = self->histSpecDiff[i];
+ posPeak1SpecDiff = binMid;
+ } else if (self->histSpecDiff[i] > maxPeak2) {
+ // Found new "second" peak.
+ maxPeak2 = self->histSpecDiff[i];
+ weightPeak2SpecDiff = self->histSpecDiff[i];
+ posPeak2SpecDiff = binMid;
+ }
+ }
+
+ // For spectrum flatness feature.
+ useFeatureSpecFlat = 1;
+ // Merge the two peaks if they are close.
+ if ((fabs(posPeak2SpecFlat - posPeak1SpecFlat) <
+ self->featureExtractionParams.limitPeakSpacingSpecFlat) &&
+ (weightPeak2SpecFlat >
+ self->featureExtractionParams.limitPeakWeightsSpecFlat *
+ weightPeak1SpecFlat)) {
+ weightPeak1SpecFlat += weightPeak2SpecFlat;
+ posPeak1SpecFlat = 0.5f * (posPeak1SpecFlat + posPeak2SpecFlat);
+ }
+ // Reject if weight of peaks is not large enough, or peak value too small.
+ if (weightPeak1SpecFlat <
+ self->featureExtractionParams.thresWeightSpecFlat ||
+ posPeak1SpecFlat < self->featureExtractionParams.thresPosSpecFlat) {
+ useFeatureSpecFlat = 0;
+ }
+ // If selected, get the threshold.
+ if (useFeatureSpecFlat == 1) {
+ // Compute the threshold.
+ self->priorModelPars[1] =
+ self->featureExtractionParams.factor2ModelPars * posPeak1SpecFlat;
+ // Check if value is within min/max range.
+ if (self->priorModelPars[1] < self->featureExtractionParams.minSpecFlat) {
+ self->priorModelPars[1] = self->featureExtractionParams.minSpecFlat;
+ }
+ if (self->priorModelPars[1] > self->featureExtractionParams.maxSpecFlat) {
+ self->priorModelPars[1] = self->featureExtractionParams.maxSpecFlat;
+ }
+ }
+ // Done with flatness feature.
+
+ // For template feature.
+ useFeatureSpecDiff = 1;
+ // Merge the two peaks if they are close.
+ if ((fabs(posPeak2SpecDiff - posPeak1SpecDiff) <
+ self->featureExtractionParams.limitPeakSpacingSpecDiff) &&
+ (weightPeak2SpecDiff >
+ self->featureExtractionParams.limitPeakWeightsSpecDiff *
+ weightPeak1SpecDiff)) {
+ weightPeak1SpecDiff += weightPeak2SpecDiff;
+ posPeak1SpecDiff = 0.5f * (posPeak1SpecDiff + posPeak2SpecDiff);
+ }
+ // Get the threshold value.
+ self->priorModelPars[3] =
+ self->featureExtractionParams.factor1ModelPars * posPeak1SpecDiff;
+ // Reject if weight of peaks is not large enough.
+ if (weightPeak1SpecDiff <
+ self->featureExtractionParams.thresWeightSpecDiff) {
+ useFeatureSpecDiff = 0;
+ }
+ // Check if value is within min/max range.
+ if (self->priorModelPars[3] < self->featureExtractionParams.minSpecDiff) {
+ self->priorModelPars[3] = self->featureExtractionParams.minSpecDiff;
+ }
+ if (self->priorModelPars[3] > self->featureExtractionParams.maxSpecDiff) {
+ self->priorModelPars[3] = self->featureExtractionParams.maxSpecDiff;
+ }
+ // Done with spectral difference feature.
+
+ // Don't use template feature if fluctuation of LRT feature is very low:
+ // most likely just noise state.
+ if (fluctLrt < self->featureExtractionParams.thresFluctLrt) {
+ useFeatureSpecDiff = 0;
+ }
+
+ // Select the weights between the features.
+ // self->priorModelPars[4] is weight for LRT: always selected.
+ // self->priorModelPars[5] is weight for spectral flatness.
+ // self->priorModelPars[6] is weight for spectral difference.
+ featureSum = (float)(1 + useFeatureSpecFlat + useFeatureSpecDiff);
+ self->priorModelPars[4] = 1.f / featureSum;
+ self->priorModelPars[5] = ((float)useFeatureSpecFlat) / featureSum;
+ self->priorModelPars[6] = ((float)useFeatureSpecDiff) / featureSum;
+
+ // Set hists to zero for next update.
+ if (self->modelUpdatePars[0] >= 1) {
+ for (i = 0; i < HIST_PAR_EST; i++) {
+ self->histLrt[i] = 0;
+ self->histSpecFlat[i] = 0;
+ self->histSpecDiff[i] = 0;
+ }
+ }
+ } // End of flag == 1.
+}
+
+// Compute spectral flatness on input spectrum.
+// |magnIn| is the magnitude spectrum.
+// Spectral flatness is returned in self->featureData[0].
+static void ComputeSpectralFlatness(NoiseSuppressionC* self,
+ const float* magnIn) {
+ size_t i;
+ size_t shiftLP = 1; // Option to remove first bin(s) from spectral measures.
+ float avgSpectralFlatnessNum, avgSpectralFlatnessDen, spectralTmp;
+
+ // Compute spectral measures.
+ // For flatness.
+ avgSpectralFlatnessNum = 0.0;
+ avgSpectralFlatnessDen = self->sumMagn;
+ for (i = 0; i < shiftLP; i++) {
+ avgSpectralFlatnessDen -= magnIn[i];
+ }
+ // Compute log of ratio of the geometric to arithmetic mean: check for log(0)
+ // case.
+ for (i = shiftLP; i < self->magnLen; i++) {
+ if (magnIn[i] > 0.0) {
+ avgSpectralFlatnessNum += (float)log(magnIn[i]);
+ } else {
+ self->featureData[0] -= SPECT_FL_TAVG * self->featureData[0];
+ return;
+ }
+ }
+ // Normalize.
+ avgSpectralFlatnessDen = avgSpectralFlatnessDen / self->magnLen;
+ avgSpectralFlatnessNum = avgSpectralFlatnessNum / self->magnLen;
+
+ // Ratio and inverse log: check for case of log(0).
+ spectralTmp = (float)exp(avgSpectralFlatnessNum) / avgSpectralFlatnessDen;
+
+ // Time-avg update of spectral flatness feature.
+ self->featureData[0] += SPECT_FL_TAVG * (spectralTmp - self->featureData[0]);
+ // Done with flatness feature.
+}
+
+// Compute prior and post SNR based on quantile noise estimation.
+// Compute DD estimate of prior SNR.
+// Inputs:
+// * |magn| is the signal magnitude spectrum estimate.
+// * |noise| is the magnitude noise spectrum estimate.
+// Outputs:
+// * |snrLocPrior| is the computed prior SNR.
+// * |snrLocPost| is the computed post SNR.
+static void ComputeSnr(const NoiseSuppressionC* self,
+ const float* magn,
+ const float* noise,
+ float* snrLocPrior,
+ float* snrLocPost) {
+ size_t i;
+
+ for (i = 0; i < self->magnLen; i++) {
+ // Previous post SNR.
+ // Previous estimate: based on previous frame with gain filter.
+ float previousEstimateStsa = self->magnPrevAnalyze[i] /
+ (self->noisePrev[i] + 0.0001f) * self->smooth[i];
+ // Post SNR.
+ snrLocPost[i] = 0.f;
+ if (magn[i] > noise[i]) {
+ snrLocPost[i] = magn[i] / (noise[i] + 0.0001f) - 1.f;
+ }
+ // DD estimate is sum of two terms: current estimate and previous estimate.
+ // Directed decision update of snrPrior.
+ snrLocPrior[i] =
+ DD_PR_SNR * previousEstimateStsa + (1.f - DD_PR_SNR) * snrLocPost[i];
+ } // End of loop over frequencies.
+}
+
+// Compute the difference measure between input spectrum and a template/learned
+// noise spectrum.
+// |magnIn| is the input spectrum.
+// The reference/template spectrum is self->magnAvgPause[i].
+// Returns (normalized) spectral difference in self->featureData[4].
+static void ComputeSpectralDifference(NoiseSuppressionC* self,
+ const float* magnIn) {
+ // avgDiffNormMagn = var(magnIn) - cov(magnIn, magnAvgPause)^2 /
+ // var(magnAvgPause)
+ size_t i;
+ float avgPause, avgMagn, covMagnPause, varPause, varMagn, avgDiffNormMagn;
+
+ avgPause = 0.0;
+ avgMagn = self->sumMagn;
+ // Compute average quantities.
+ for (i = 0; i < self->magnLen; i++) {
+ // Conservative smooth noise spectrum from pause frames.
+ avgPause += self->magnAvgPause[i];
+ }
+ avgPause /= self->magnLen;
+ avgMagn /= self->magnLen;
+
+ covMagnPause = 0.0;
+ varPause = 0.0;
+ varMagn = 0.0;
+ // Compute variance and covariance quantities.
+ for (i = 0; i < self->magnLen; i++) {
+ covMagnPause += (magnIn[i] - avgMagn) * (self->magnAvgPause[i] - avgPause);
+ varPause +=
+ (self->magnAvgPause[i] - avgPause) * (self->magnAvgPause[i] - avgPause);
+ varMagn += (magnIn[i] - avgMagn) * (magnIn[i] - avgMagn);
+ }
+ covMagnPause /= self->magnLen;
+ varPause /= self->magnLen;
+ varMagn /= self->magnLen;
+ // Update of average magnitude spectrum.
+ self->featureData[6] += self->signalEnergy;
+
+ avgDiffNormMagn =
+ varMagn - (covMagnPause * covMagnPause) / (varPause + 0.0001f);
+ // Normalize and compute time-avg update of difference feature.
+ avgDiffNormMagn = (float)(avgDiffNormMagn / (self->featureData[5] + 0.0001f));
+ self->featureData[4] +=
+ SPECT_DIFF_TAVG * (avgDiffNormMagn - self->featureData[4]);
+}
+
+// Compute speech/noise probability.
+// Speech/noise probability is returned in |probSpeechFinal|.
+// |magn| is the input magnitude spectrum.
+// |noise| is the noise spectrum.
+// |snrLocPrior| is the prior SNR for each frequency.
+// |snrLocPost| is the post SNR for each frequency.
+static void SpeechNoiseProb(NoiseSuppressionC* self,
+ float* probSpeechFinal,
+ const float* snrLocPrior,
+ const float* snrLocPost) {
+ size_t i;
+ int sgnMap;
+ float invLrt, gainPrior, indPrior;
+ float logLrtTimeAvgKsum, besselTmp;
+ float indicator0, indicator1, indicator2;
+ float tmpFloat1, tmpFloat2;
+ float weightIndPrior0, weightIndPrior1, weightIndPrior2;
+ float threshPrior0, threshPrior1, threshPrior2;
+ float widthPrior, widthPrior0, widthPrior1, widthPrior2;
+
+ widthPrior0 = WIDTH_PR_MAP;
+ // Width for pause region: lower range, so increase width in tanh map.
+ widthPrior1 = 2.f * WIDTH_PR_MAP;
+ widthPrior2 = 2.f * WIDTH_PR_MAP; // For spectral-difference measure.
+
+ // Threshold parameters for features.
+ threshPrior0 = self->priorModelPars[0];
+ threshPrior1 = self->priorModelPars[1];
+ threshPrior2 = self->priorModelPars[3];
+
+ // Sign for flatness feature.
+ sgnMap = (int)(self->priorModelPars[2]);
+
+ // Weight parameters for features.
+ weightIndPrior0 = self->priorModelPars[4];
+ weightIndPrior1 = self->priorModelPars[5];
+ weightIndPrior2 = self->priorModelPars[6];
+
+ // Compute feature based on average LR factor.
+ // This is the average over all frequencies of the smooth log LRT.
+ logLrtTimeAvgKsum = 0.0;
+ for (i = 0; i < self->magnLen; i++) {
+ tmpFloat1 = 1.f + 2.f * snrLocPrior[i];
+ tmpFloat2 = 2.f * snrLocPrior[i] / (tmpFloat1 + 0.0001f);
+ besselTmp = (snrLocPost[i] + 1.f) * tmpFloat2;
+ self->logLrtTimeAvg[i] +=
+ LRT_TAVG * (besselTmp - (float)log(tmpFloat1) - self->logLrtTimeAvg[i]);
+ logLrtTimeAvgKsum += self->logLrtTimeAvg[i];
+ }
+ logLrtTimeAvgKsum = (float)logLrtTimeAvgKsum / (self->magnLen);
+ self->featureData[3] = logLrtTimeAvgKsum;
+ // Done with computation of LR factor.
+
+ // Compute the indicator functions.
+ // Average LRT feature.
+ widthPrior = widthPrior0;
+ // Use larger width in tanh map for pause regions.
+ if (logLrtTimeAvgKsum < threshPrior0) {
+ widthPrior = widthPrior1;
+ }
+ // Compute indicator function: sigmoid map.
+ indicator0 =
+ 0.5f *
+ ((float)tanh(widthPrior * (logLrtTimeAvgKsum - threshPrior0)) + 1.f);
+
+ // Spectral flatness feature.
+ tmpFloat1 = self->featureData[0];
+ widthPrior = widthPrior0;
+ // Use larger width in tanh map for pause regions.
+ if (sgnMap == 1 && (tmpFloat1 > threshPrior1)) {
+ widthPrior = widthPrior1;
+ }
+ if (sgnMap == -1 && (tmpFloat1 < threshPrior1)) {
+ widthPrior = widthPrior1;
+ }
+ // Compute indicator function: sigmoid map.
+ indicator1 =
+ 0.5f *
+ ((float)tanh((float)sgnMap * widthPrior * (threshPrior1 - tmpFloat1)) +
+ 1.f);
+
+ // For template spectrum-difference.
+ tmpFloat1 = self->featureData[4];
+ widthPrior = widthPrior0;
+ // Use larger width in tanh map for pause regions.
+ if (tmpFloat1 < threshPrior2) {
+ widthPrior = widthPrior2;
+ }
+ // Compute indicator function: sigmoid map.
+ indicator2 =
+ 0.5f * ((float)tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.f);
+
+ // Combine the indicator function with the feature weights.
+ indPrior = weightIndPrior0 * indicator0 + weightIndPrior1 * indicator1 +
+ weightIndPrior2 * indicator2;
+ // Done with computing indicator function.
+
+ // Compute the prior probability.
+ self->priorSpeechProb += PRIOR_UPDATE * (indPrior - self->priorSpeechProb);
+ // Make sure probabilities are within range: keep floor to 0.01.
+ if (self->priorSpeechProb > 1.f) {
+ self->priorSpeechProb = 1.f;
+ }
+ if (self->priorSpeechProb < 0.01f) {
+ self->priorSpeechProb = 0.01f;
+ }
+
+ // Final speech probability: combine prior model with LR factor:.
+ gainPrior = (1.f - self->priorSpeechProb) / (self->priorSpeechProb + 0.0001f);
+ for (i = 0; i < self->magnLen; i++) {
+ invLrt = (float)exp(-self->logLrtTimeAvg[i]);
+ invLrt = (float)gainPrior * invLrt;
+ probSpeechFinal[i] = 1.f / (1.f + invLrt);
+ }
+}
+
+// Update the noise features.
+// Inputs:
+// * |magn| is the signal magnitude spectrum estimate.
+// * |updateParsFlag| is an update flag for parameters.
+static void FeatureUpdate(NoiseSuppressionC* self,
+ const float* magn,
+ int updateParsFlag) {
+ // Compute spectral flatness on input spectrum.
+ ComputeSpectralFlatness(self, magn);
+ // Compute difference of input spectrum with learned/estimated noise spectrum.
+ ComputeSpectralDifference(self, magn);
+ // Compute histograms for parameter decisions (thresholds and weights for
+ // features).
+ // Parameters are extracted once every window time.
+ // (=self->modelUpdatePars[1])
+ if (updateParsFlag >= 1) {
+ // Counter update.
+ self->modelUpdatePars[3]--;
+ // Update histogram.
+ if (self->modelUpdatePars[3] > 0) {
+ FeatureParameterExtraction(self, 0);
+ }
+ // Compute model parameters.
+ if (self->modelUpdatePars[3] == 0) {
+ FeatureParameterExtraction(self, 1);
+ self->modelUpdatePars[3] = self->modelUpdatePars[1];
+ // If wish to update only once, set flag to zero.
+ if (updateParsFlag == 1) {
+ self->modelUpdatePars[0] = 0;
+ } else {
+ // Update every window:
+ // Get normalization for spectral difference for next window estimate.
+ self->featureData[6] =
+ self->featureData[6] / ((float)self->modelUpdatePars[1]);
+ self->featureData[5] =
+ 0.5f * (self->featureData[6] + self->featureData[5]);
+ self->featureData[6] = 0.f;
+ }
+ }
+ }
+}
+
+// Update the noise estimate.
+// Inputs:
+// * |magn| is the signal magnitude spectrum estimate.
+// * |snrLocPrior| is the prior SNR.
+// * |snrLocPost| is the post SNR.
+// Output:
+// * |noise| is the updated noise magnitude spectrum estimate.
+static void UpdateNoiseEstimate(NoiseSuppressionC* self,
+ const float* magn,
+ const float* snrLocPrior,
+ const float* snrLocPost,
+ float* noise) {
+ size_t i;
+ float probSpeech, probNonSpeech;
+ // Time-avg parameter for noise update.
+ float gammaNoiseTmp = NOISE_UPDATE;
+ float gammaNoiseOld;
+ float noiseUpdateTmp;
+
+ for (i = 0; i < self->magnLen; i++) {
+ probSpeech = self->speechProb[i];
+ probNonSpeech = 1.f - probSpeech;
+ // Temporary noise update:
+ // Use it for speech frames if update value is less than previous.
+ noiseUpdateTmp = gammaNoiseTmp * self->noisePrev[i] +
+ (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
+ probSpeech * self->noisePrev[i]);
+ // Time-constant based on speech/noise state.
+ gammaNoiseOld = gammaNoiseTmp;
+ gammaNoiseTmp = NOISE_UPDATE;
+ // Increase gamma (i.e., less noise update) for frame likely to be speech.
+ if (probSpeech > PROB_RANGE) {
+ gammaNoiseTmp = SPEECH_UPDATE;
+ }
+ // Conservative noise update.
+ if (probSpeech < PROB_RANGE) {
+ self->magnAvgPause[i] += GAMMA_PAUSE * (magn[i] - self->magnAvgPause[i]);
+ }
+ // Noise update.
+ if (gammaNoiseTmp == gammaNoiseOld) {
+ noise[i] = noiseUpdateTmp;
+ } else {
+ noise[i] = gammaNoiseTmp * self->noisePrev[i] +
+ (1.f - gammaNoiseTmp) * (probNonSpeech * magn[i] +
+ probSpeech * self->noisePrev[i]);
+ // Allow for noise update downwards:
+ // If noise update decreases the noise, it is safe, so allow it to
+ // happen.
+ if (noiseUpdateTmp < noise[i]) {
+ noise[i] = noiseUpdateTmp;
+ }
+ }
+ } // End of freq loop.
+}
+
+// Updates |buffer| with a new |frame|.
+// Inputs:
+// * |frame| is a new speech frame or NULL for setting to zero.
+// * |frame_length| is the length of the new frame.
+// * |buffer_length| is the length of the buffer.
+// Output:
+// * |buffer| is the updated buffer.
+static void UpdateBuffer(const float* frame,
+ size_t frame_length,
+ size_t buffer_length,
+ float* buffer) {
+ RTC_DCHECK_LT(buffer_length, 2 * frame_length);
+
+ memcpy(buffer,
+ buffer + frame_length,
+ sizeof(*buffer) * (buffer_length - frame_length));
+ if (frame) {
+ memcpy(buffer + buffer_length - frame_length,
+ frame,
+ sizeof(*buffer) * frame_length);
+ } else {
+ memset(buffer + buffer_length - frame_length,
+ 0,
+ sizeof(*buffer) * frame_length);
+ }
+}
+
+// Transforms the signal from time to frequency domain.
+// Inputs:
+// * |time_data| is the signal in the time domain.
+// * |time_data_length| is the length of the analysis buffer.
+// * |magnitude_length| is the length of the spectrum magnitude, which equals
+// the length of both |real| and |imag| (time_data_length / 2 + 1).
+// Outputs:
+// * |time_data| is the signal in the frequency domain.
+// * |real| is the real part of the frequency domain.
+// * |imag| is the imaginary part of the frequency domain.
+// * |magn| is the calculated signal magnitude in the frequency domain.
+static void FFT(NoiseSuppressionC* self,
+ float* time_data,
+ size_t time_data_length,
+ size_t magnitude_length,
+ float* real,
+ float* imag,
+ float* magn) {
+ size_t i;
+
+ RTC_DCHECK_EQ(magnitude_length, time_data_length / 2 + 1);
+
+ WebRtc_rdft(time_data_length, 1, time_data, self->ip, self->wfft);
+
+ imag[0] = 0;
+ real[0] = time_data[0];
+ magn[0] = fabsf(real[0]) + 1.f;
+ imag[magnitude_length - 1] = 0;
+ real[magnitude_length - 1] = time_data[1];
+ magn[magnitude_length - 1] = fabsf(real[magnitude_length - 1]) + 1.f;
+ for (i = 1; i < magnitude_length - 1; ++i) {
+ real[i] = time_data[2 * i];
+ imag[i] = time_data[2 * i + 1];
+ // Magnitude spectrum.
+ magn[i] = sqrtf(real[i] * real[i] + imag[i] * imag[i]) + 1.f;
+ }
+}
+
+// Transforms the signal from frequency to time domain.
+// Inputs:
+// * |real| is the real part of the frequency domain.
+// * |imag| is the imaginary part of the frequency domain.
+// * |magnitude_length| is the length of the spectrum magnitude, which equals
+// the length of both |real| and |imag|.
+// * |time_data_length| is the length of the analysis buffer
+// (2 * (magnitude_length - 1)).
+// Output:
+// * |time_data| is the signal in the time domain.
+static void IFFT(NoiseSuppressionC* self,
+ const float* real,
+ const float* imag,
+ size_t magnitude_length,
+ size_t time_data_length,
+ float* time_data) {
+ size_t i;
+
+ RTC_DCHECK_EQ(time_data_length, 2 * (magnitude_length - 1));
+
+ time_data[0] = real[0];
+ time_data[1] = real[magnitude_length - 1];
+ for (i = 1; i < magnitude_length - 1; ++i) {
+ time_data[2 * i] = real[i];
+ time_data[2 * i + 1] = imag[i];
+ }
+ WebRtc_rdft(time_data_length, -1, time_data, self->ip, self->wfft);
+
+ for (i = 0; i < time_data_length; ++i) {
+ time_data[i] *= 2.f / time_data_length; // FFT scaling.
+ }
+}
+
+// Calculates the energy of a buffer.
+// Inputs:
+// * |buffer| is the buffer over which the energy is calculated.
+// * |length| is the length of the buffer.
+// Returns the calculated energy.
+static float Energy(const float* buffer, size_t length) {
+ size_t i;
+ float energy = 0.f;
+
+ for (i = 0; i < length; ++i) {
+ energy += buffer[i] * buffer[i];
+ }
+
+ return energy;
+}
+
+// Windows a buffer.
+// Inputs:
+// * |window| is the window by which to multiply.
+// * |data| is the data without windowing.
+// * |length| is the length of the window and data.
+// Output:
+// * |data_windowed| is the windowed data.
+static void Windowing(const float* window,
+ const float* data,
+ size_t length,
+ float* data_windowed) {
+ size_t i;
+
+ for (i = 0; i < length; ++i) {
+ data_windowed[i] = window[i] * data[i];
+ }
+}
+
+// Estimate prior SNR decision-directed and compute DD based Wiener Filter.
+// Input:
+// * |magn| is the signal magnitude spectrum estimate.
+// Output:
+// * |theFilter| is the frequency response of the computed Wiener filter.
+static void ComputeDdBasedWienerFilter(const NoiseSuppressionC* self,
+ const float* magn,
+ float* theFilter) {
+ size_t i;
+ float snrPrior, previousEstimateStsa, currentEstimateStsa;
+
+ for (i = 0; i < self->magnLen; i++) {
+ // Previous estimate: based on previous frame with gain filter.
+ previousEstimateStsa = self->magnPrevProcess[i] /
+ (self->noisePrev[i] + 0.0001f) * self->smooth[i];
+ // Post and prior SNR.
+ currentEstimateStsa = 0.f;
+ if (magn[i] > self->noise[i]) {
+ currentEstimateStsa = magn[i] / (self->noise[i] + 0.0001f) - 1.f;
+ }
+ // DD estimate is sum of two terms: current estimate and previous estimate.
+ // Directed decision update of |snrPrior|.
+ snrPrior = DD_PR_SNR * previousEstimateStsa +
+ (1.f - DD_PR_SNR) * currentEstimateStsa;
+ // Gain filter.
+ theFilter[i] = snrPrior / (self->overdrive + snrPrior);
+ } // End of loop over frequencies.
+}
+
+// Changes the aggressiveness of the noise suppression method.
+// |mode| = 0 is mild (6dB), |mode| = 1 is medium (10dB) and |mode| = 2 is
+// aggressive (15dB).
+// Returns 0 on success and -1 otherwise.
+int WebRtcNs_set_policy_core(NoiseSuppressionC* self, int mode) {
+ // Allow for modes: 0, 1, 2, 3.
+ if (mode < 0 || mode > 3) {
+ return (-1);
+ }
+
+ self->aggrMode = mode;
+ if (mode == 0) {
+ self->overdrive = 1.f;
+ self->denoiseBound = 0.5f;
+ self->gainmap = 0;
+ } else if (mode == 1) {
+ // self->overdrive = 1.25f;
+ self->overdrive = 1.f;
+ self->denoiseBound = 0.25f;
+ self->gainmap = 1;
+ } else if (mode == 2) {
+ // self->overdrive = 1.25f;
+ self->overdrive = 1.1f;
+ self->denoiseBound = 0.125f;
+ self->gainmap = 1;
+ } else if (mode == 3) {
+ // self->overdrive = 1.3f;
+ self->overdrive = 1.25f;
+ self->denoiseBound = 0.09f;
+ self->gainmap = 1;
+ }
+ return 0;
+}
+
+void WebRtcNs_AnalyzeCore(NoiseSuppressionC* self, const float* speechFrame) {
+ size_t i;
+ const size_t kStartBand = 5; // Skip first frequency bins during estimation.
+ int updateParsFlag;
+ float energy;
+ float signalEnergy = 0.f;
+ float sumMagn = 0.f;
+ float tmpFloat1, tmpFloat2, tmpFloat3;
+ float winData[ANAL_BLOCKL_MAX];
+ float magn[HALF_ANAL_BLOCKL], noise[HALF_ANAL_BLOCKL];
+ float snrLocPost[HALF_ANAL_BLOCKL], snrLocPrior[HALF_ANAL_BLOCKL];
+ float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
+ // Variables during startup.
+ float sum_log_i = 0.0;
+ float sum_log_i_square = 0.0;
+ float sum_log_magn = 0.0;
+ float sum_log_i_log_magn = 0.0;
+ float parametric_exp = 0.0;
+ float parametric_num = 0.0;
+
+ // Check that initiation has been done.
+ RTC_DCHECK_EQ(1, self->initFlag);
+ updateParsFlag = self->modelUpdatePars[0];
+
+ // Update analysis buffer for L band.
+ UpdateBuffer(speechFrame, self->blockLen, self->anaLen, self->analyzeBuf);
+
+ Windowing(self->window, self->analyzeBuf, self->anaLen, winData);
+ energy = Energy(winData, self->anaLen);
+ if (energy == 0.0) {
+ // 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.
+ self->signalEnergy = 0;
+ return;
+ }
+
+ self->blockInd++; // Update the block index only when we process a block.
+
+ FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
+
+ for (i = 0; i < self->magnLen; i++) {
+ signalEnergy += real[i] * real[i] + imag[i] * imag[i];
+ sumMagn += magn[i];
+ if (self->blockInd < END_STARTUP_SHORT) {
+ if (i >= kStartBand) {
+ tmpFloat2 = logf((float)i);
+ sum_log_i += tmpFloat2;
+ sum_log_i_square += tmpFloat2 * tmpFloat2;
+ tmpFloat1 = logf(magn[i]);
+ sum_log_magn += tmpFloat1;
+ sum_log_i_log_magn += tmpFloat2 * tmpFloat1;
+ }
+ }
+ }
+ signalEnergy /= self->magnLen;
+ self->signalEnergy = signalEnergy;
+ self->sumMagn = sumMagn;
+
+ // Quantile noise estimate.
+ NoiseEstimation(self, magn, noise);
+ // Compute simplified noise model during startup.
+ if (self->blockInd < END_STARTUP_SHORT) {
+ // Estimate White noise.
+ self->whiteNoiseLevel += sumMagn / self->magnLen * self->overdrive;
+ // Estimate Pink noise parameters.
+ tmpFloat1 = sum_log_i_square * (self->magnLen - kStartBand);
+ tmpFloat1 -= (sum_log_i * sum_log_i);
+ tmpFloat2 =
+ (sum_log_i_square * sum_log_magn - sum_log_i * sum_log_i_log_magn);
+ tmpFloat3 = tmpFloat2 / tmpFloat1;
+ // Constrain the estimated spectrum to be positive.
+ if (tmpFloat3 < 0.f) {
+ tmpFloat3 = 0.f;
+ }
+ self->pinkNoiseNumerator += tmpFloat3;
+ tmpFloat2 = (sum_log_i * sum_log_magn);
+ tmpFloat2 -= (self->magnLen - kStartBand) * sum_log_i_log_magn;
+ tmpFloat3 = tmpFloat2 / tmpFloat1;
+ // Constrain the pink noise power to be in the interval [0, 1].
+ if (tmpFloat3 < 0.f) {
+ tmpFloat3 = 0.f;
+ }
+ if (tmpFloat3 > 1.f) {
+ tmpFloat3 = 1.f;
+ }
+ self->pinkNoiseExp += tmpFloat3;
+
+ // Calculate frequency independent parts of parametric noise estimate.
+ if (self->pinkNoiseExp > 0.f) {
+ // Use pink noise estimate.
+ parametric_num =
+ expf(self->pinkNoiseNumerator / (float)(self->blockInd + 1));
+ parametric_num *= (float)(self->blockInd + 1);
+ parametric_exp = self->pinkNoiseExp / (float)(self->blockInd + 1);
+ }
+ for (i = 0; i < self->magnLen; i++) {
+ // Estimate the background noise using the white and pink noise
+ // parameters.
+ if (self->pinkNoiseExp == 0.f) {
+ // Use white noise estimate.
+ self->parametricNoise[i] = self->whiteNoiseLevel;
+ } else {
+ // Use pink noise estimate.
+ float use_band = (float)(i < kStartBand ? kStartBand : i);
+ self->parametricNoise[i] =
+ parametric_num / powf(use_band, parametric_exp);
+ }
+ // Weight quantile noise with modeled noise.
+ noise[i] *= (self->blockInd);
+ tmpFloat2 =
+ self->parametricNoise[i] * (END_STARTUP_SHORT - self->blockInd);
+ noise[i] += (tmpFloat2 / (float)(self->blockInd + 1));
+ noise[i] /= END_STARTUP_SHORT;
+ }
+ }
+ // Compute average signal during END_STARTUP_LONG time:
+ // used to normalize spectral difference measure.
+ if (self->blockInd < END_STARTUP_LONG) {
+ self->featureData[5] *= self->blockInd;
+ self->featureData[5] += signalEnergy;
+ self->featureData[5] /= (self->blockInd + 1);
+ }
+
+ // Post and prior SNR needed for SpeechNoiseProb.
+ ComputeSnr(self, magn, noise, snrLocPrior, snrLocPost);
+
+ FeatureUpdate(self, magn, updateParsFlag);
+ SpeechNoiseProb(self, self->speechProb, snrLocPrior, snrLocPost);
+ UpdateNoiseEstimate(self, magn, snrLocPrior, snrLocPost, noise);
+
+ // Keep track of noise spectrum for next frame.
+ memcpy(self->noise, noise, sizeof(*noise) * self->magnLen);
+ memcpy(self->magnPrevAnalyze, magn, sizeof(*magn) * self->magnLen);
+}
+
+void WebRtcNs_ProcessCore(NoiseSuppressionC* self,
+ const float* const* speechFrame,
+ size_t num_bands,
+ float* const* outFrame) {
+ // Main routine for noise reduction.
+ int flagHB = 0;
+ size_t i, j;
+
+ float energy1, energy2, gain, factor, factor1, factor2;
+ float fout[BLOCKL_MAX];
+ float winData[ANAL_BLOCKL_MAX];
+ float magn[HALF_ANAL_BLOCKL];
+ float theFilter[HALF_ANAL_BLOCKL], theFilterTmp[HALF_ANAL_BLOCKL];
+ float real[ANAL_BLOCKL_MAX], imag[HALF_ANAL_BLOCKL];
+
+ // SWB variables.
+ int deltaBweHB = 1;
+ int deltaGainHB = 1;
+ float decayBweHB = 1.0;
+ float gainMapParHB = 1.0;
+ float gainTimeDomainHB = 1.0;
+ float avgProbSpeechHB, avgProbSpeechHBTmp, avgFilterGainHB, gainModHB;
+ float sumMagnAnalyze, sumMagnProcess;
+
+ // Check that initiation has been done.
+ RTC_DCHECK_EQ(1, self->initFlag);
+ RTC_DCHECK_LE(num_bands - 1, NUM_HIGH_BANDS_MAX);
+
+ const float* const* speechFrameHB = NULL;
+ float* const* outFrameHB = NULL;
+ size_t num_high_bands = 0;
+ if (num_bands > 1) {
+ speechFrameHB = &speechFrame[1];
+ outFrameHB = &outFrame[1];
+ num_high_bands = num_bands - 1;
+ flagHB = 1;
+ // Range for averaging low band quantities for H band gain.
+ deltaBweHB = (int)self->magnLen / 4;
+ deltaGainHB = deltaBweHB;
+ }
+
+ // Update analysis buffer for L band.
+ UpdateBuffer(speechFrame[0], self->blockLen, self->anaLen, self->dataBuf);
+
+ if (flagHB == 1) {
+ // Update analysis buffer for H bands.
+ for (i = 0; i < num_high_bands; ++i) {
+ UpdateBuffer(speechFrameHB[i],
+ self->blockLen,
+ self->anaLen,
+ self->dataBufHB[i]);
+ }
+ }
+
+ Windowing(self->window, self->dataBuf, self->anaLen, winData);
+ energy1 = Energy(winData, self->anaLen);
+ if (energy1 == 0.0 || self->signalEnergy == 0) {
+ // Synthesize the special case of zero input.
+ // Read out fully processed segment.
+ for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
+ fout[i - self->windShift] = self->syntBuf[i];
+ }
+ // Update synthesis buffer.
+ UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
+
+ for (i = 0; i < self->blockLen; ++i)
+ outFrame[0][i] =
+ WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fout[i], WEBRTC_SPL_WORD16_MIN);
+
+ // For time-domain gain of HB.
+ if (flagHB == 1) {
+ for (i = 0; i < num_high_bands; ++i) {
+ for (j = 0; j < self->blockLen; ++j) {
+ outFrameHB[i][j] = WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
+ self->dataBufHB[i][j],
+ WEBRTC_SPL_WORD16_MIN);
+ }
+ }
+ }
+
+ return;
+ }
+
+ FFT(self, winData, self->anaLen, self->magnLen, real, imag, magn);
+
+ if (self->blockInd < END_STARTUP_SHORT) {
+ for (i = 0; i < self->magnLen; i++) {
+ self->initMagnEst[i] += magn[i];
+ }
+ }
+
+ ComputeDdBasedWienerFilter(self, magn, theFilter);
+
+ for (i = 0; i < self->magnLen; i++) {
+ // Flooring bottom.
+ if (theFilter[i] < self->denoiseBound) {
+ theFilter[i] = self->denoiseBound;
+ }
+ // Flooring top.
+ if (theFilter[i] > 1.f) {
+ theFilter[i] = 1.f;
+ }
+ if (self->blockInd < END_STARTUP_SHORT) {
+ theFilterTmp[i] =
+ (self->initMagnEst[i] - self->overdrive * self->parametricNoise[i]);
+ theFilterTmp[i] /= (self->initMagnEst[i] + 0.0001f);
+ // Flooring bottom.
+ if (theFilterTmp[i] < self->denoiseBound) {
+ theFilterTmp[i] = self->denoiseBound;
+ }
+ // Flooring top.
+ if (theFilterTmp[i] > 1.f) {
+ theFilterTmp[i] = 1.f;
+ }
+ // Weight the two suppression filters.
+ theFilter[i] *= (self->blockInd);
+ theFilterTmp[i] *= (END_STARTUP_SHORT - self->blockInd);
+ theFilter[i] += theFilterTmp[i];
+ theFilter[i] /= (END_STARTUP_SHORT);
+ }
+
+ self->smooth[i] = theFilter[i];
+ real[i] *= self->smooth[i];
+ imag[i] *= self->smooth[i];
+ }
+ // Keep track of |magn| spectrum for next frame.
+ memcpy(self->magnPrevProcess, magn, sizeof(*magn) * self->magnLen);
+ memcpy(self->noisePrev, self->noise, sizeof(self->noise[0]) * self->magnLen);
+ // Back to time domain.
+ IFFT(self, real, imag, self->magnLen, self->anaLen, winData);
+
+ // Scale factor: only do it after END_STARTUP_LONG time.
+ factor = 1.f;
+ if (self->gainmap == 1 && self->blockInd > END_STARTUP_LONG) {
+ factor1 = 1.f;
+ factor2 = 1.f;
+
+ energy2 = Energy(winData, self->anaLen);
+ gain = (float)sqrt(energy2 / (energy1 + 1.f));
+
+ // Scaling for new version.
+ if (gain > B_LIM) {
+ factor1 = 1.f + 1.3f * (gain - B_LIM);
+ if (gain * factor1 > 1.f) {
+ factor1 = 1.f / gain;
+ }
+ }
+ if (gain < B_LIM) {
+ // Don't reduce scale too much for pause regions:
+ // attenuation here should be controlled by flooring.
+ if (gain <= self->denoiseBound) {
+ gain = self->denoiseBound;
+ }
+ factor2 = 1.f - 0.3f * (B_LIM - gain);
+ }
+ // Combine both scales with speech/noise prob:
+ // note prior (priorSpeechProb) is not frequency dependent.
+ factor = self->priorSpeechProb * factor1 +
+ (1.f - self->priorSpeechProb) * factor2;
+ } // Out of self->gainmap == 1.
+
+ Windowing(self->window, winData, self->anaLen, winData);
+
+ // Synthesis.
+ for (i = 0; i < self->anaLen; i++) {
+ self->syntBuf[i] += factor * winData[i];
+ }
+ // Read out fully processed segment.
+ for (i = self->windShift; i < self->blockLen + self->windShift; i++) {
+ fout[i - self->windShift] = self->syntBuf[i];
+ }
+ // Update synthesis buffer.
+ UpdateBuffer(NULL, self->blockLen, self->anaLen, self->syntBuf);
+
+ for (i = 0; i < self->blockLen; ++i)
+ outFrame[0][i] =
+ WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX, fout[i], WEBRTC_SPL_WORD16_MIN);
+
+ // For time-domain gain of HB.
+ if (flagHB == 1) {
+ // Average speech prob from low band.
+ // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
+ avgProbSpeechHB = 0.0;
+ for (i = self->magnLen - deltaBweHB - 1; i < self->magnLen - 1; i++) {
+ avgProbSpeechHB += self->speechProb[i];
+ }
+ avgProbSpeechHB = avgProbSpeechHB / ((float)deltaBweHB);
+ // If the speech was suppressed by a component between Analyze and
+ // Process, for example the AEC, then it should not be considered speech
+ // for high band suppression purposes.
+ sumMagnAnalyze = 0;
+ sumMagnProcess = 0;
+ for (i = 0; i < self->magnLen; ++i) {
+ sumMagnAnalyze += self->magnPrevAnalyze[i];
+ sumMagnProcess += self->magnPrevProcess[i];
+ }
+ RTC_DCHECK_GT(sumMagnAnalyze, 0);
+ avgProbSpeechHB *= sumMagnProcess / sumMagnAnalyze;
+ // Average filter gain from low band.
+ // Average over second half (i.e., 4->8kHz) of frequencies spectrum.
+ avgFilterGainHB = 0.0;
+ for (i = self->magnLen - deltaGainHB - 1; i < self->magnLen - 1; i++) {
+ avgFilterGainHB += self->smooth[i];
+ }
+ avgFilterGainHB = avgFilterGainHB / ((float)(deltaGainHB));
+ avgProbSpeechHBTmp = 2.f * avgProbSpeechHB - 1.f;
+ // Gain based on speech probability.
+ gainModHB = 0.5f * (1.f + (float)tanh(gainMapParHB * avgProbSpeechHBTmp));
+ // Combine gain with low band gain.
+ gainTimeDomainHB = 0.5f * gainModHB + 0.5f * avgFilterGainHB;
+ if (avgProbSpeechHB >= 0.5f) {
+ gainTimeDomainHB = 0.25f * gainModHB + 0.75f * avgFilterGainHB;
+ }
+ gainTimeDomainHB = gainTimeDomainHB * decayBweHB;
+ // Make sure gain is within flooring range.
+ // Flooring bottom.
+ if (gainTimeDomainHB < self->denoiseBound) {
+ gainTimeDomainHB = self->denoiseBound;
+ }
+ // Flooring top.
+ if (gainTimeDomainHB > 1.f) {
+ gainTimeDomainHB = 1.f;
+ }
+ // Apply gain.
+ for (i = 0; i < num_high_bands; ++i) {
+ for (j = 0; j < self->blockLen; j++) {
+ outFrameHB[i][j] =
+ WEBRTC_SPL_SAT(WEBRTC_SPL_WORD16_MAX,
+ gainTimeDomainHB * self->dataBufHB[i][j],
+ WEBRTC_SPL_WORD16_MIN);
+ }
+ }
+ } // End of H band gain computation.
+}
diff --git a/modules/audio_processing/legacy_ns/ns_core.h b/modules/audio_processing/legacy_ns/ns_core.h
new file mode 100644
index 0000000..7a3b0a4
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/ns_core.h
@@ -0,0 +1,188 @@
+/*
+ * 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_NS_CORE_H_
+#define MODULES_AUDIO_PROCESSING_LEGACY_NS_NS_CORE_H_
+
+#include "modules/audio_processing/legacy_ns/defines.h"
+
+typedef struct NSParaExtract_ {
+ // Bin size of histogram.
+ float binSizeLrt;
+ float binSizeSpecFlat;
+ float binSizeSpecDiff;
+ // Range of histogram over which LRT threshold is computed.
+ float rangeAvgHistLrt;
+ // Scale parameters: multiply dominant peaks of the histograms by scale factor
+ // to obtain thresholds for prior model.
+ float factor1ModelPars; // For LRT and spectral difference.
+ float factor2ModelPars; // For spectral_flatness: used when noise is flatter
+ // than speech.
+ // Peak limit for spectral flatness (varies between 0 and 1).
+ float thresPosSpecFlat;
+ // Limit on spacing of two highest peaks in histogram: spacing determined by
+ // bin size.
+ float limitPeakSpacingSpecFlat;
+ float limitPeakSpacingSpecDiff;
+ // Limit on relevance of second peak.
+ float limitPeakWeightsSpecFlat;
+ float limitPeakWeightsSpecDiff;
+ // Limit on fluctuation of LRT feature.
+ float thresFluctLrt;
+ // Limit on the max and min values for the feature thresholds.
+ float maxLrt;
+ float minLrt;
+ float maxSpecFlat;
+ float minSpecFlat;
+ float maxSpecDiff;
+ float minSpecDiff;
+ // Criteria of weight of histogram peak to accept/reject feature.
+ int thresWeightSpecFlat;
+ int thresWeightSpecDiff;
+} NSParaExtract;
+
+typedef struct NoiseSuppressionC_ {
+ uint32_t fs;
+ size_t blockLen;
+ size_t windShift;
+ size_t anaLen;
+ size_t magnLen;
+ int aggrMode;
+ const float* window;
+ float analyzeBuf[ANAL_BLOCKL_MAX];
+ float dataBuf[ANAL_BLOCKL_MAX];
+ float syntBuf[ANAL_BLOCKL_MAX];
+
+ int initFlag;
+ // Parameters for quantile noise estimation.
+ float density[SIMULT * HALF_ANAL_BLOCKL];
+ float lquantile[SIMULT * HALF_ANAL_BLOCKL];
+ float quantile[HALF_ANAL_BLOCKL];
+ int counter[SIMULT];
+ int updates;
+ // Parameters for Wiener filter.
+ float smooth[HALF_ANAL_BLOCKL];
+ float overdrive;
+ float denoiseBound;
+ int gainmap;
+ // FFT work arrays.
+ size_t ip[IP_LENGTH];
+ float wfft[W_LENGTH];
+
+ // Parameters for new method: some not needed, will reduce/cleanup later.
+ int32_t blockInd; // Frame index counter.
+ int modelUpdatePars[4]; // Parameters for updating or estimating.
+ // Thresholds/weights for prior model.
+ float priorModelPars[7]; // Parameters for prior model.
+ float noise[HALF_ANAL_BLOCKL]; // Noise spectrum from current frame.
+ float noisePrev[HALF_ANAL_BLOCKL]; // Noise spectrum from previous frame.
+ // Magnitude spectrum of previous analyze frame.
+ float magnPrevAnalyze[HALF_ANAL_BLOCKL];
+ // Magnitude spectrum of previous process frame.
+ float magnPrevProcess[HALF_ANAL_BLOCKL];
+ float logLrtTimeAvg[HALF_ANAL_BLOCKL]; // Log LRT factor with time-smoothing.
+ float priorSpeechProb; // Prior speech/noise probability.
+ float featureData[7];
+ // Conservative noise spectrum estimate.
+ float magnAvgPause[HALF_ANAL_BLOCKL];
+ float signalEnergy; // Energy of |magn|.
+ float sumMagn;
+ float whiteNoiseLevel; // Initial noise estimate.
+ float initMagnEst[HALF_ANAL_BLOCKL]; // Initial magnitude spectrum estimate.
+ float pinkNoiseNumerator; // Pink noise parameter: numerator.
+ float pinkNoiseExp; // Pink noise parameter: power of frequencies.
+ float parametricNoise[HALF_ANAL_BLOCKL];
+ // Parameters for feature extraction.
+ NSParaExtract featureExtractionParams;
+ // Histograms for parameter estimation.
+ int histLrt[HIST_PAR_EST];
+ int histSpecFlat[HIST_PAR_EST];
+ int histSpecDiff[HIST_PAR_EST];
+ // Quantities for high band estimate.
+ float speechProb[HALF_ANAL_BLOCKL]; // Final speech/noise prob: prior + LRT.
+ // Buffering data for HB.
+ float dataBufHB[NUM_HIGH_BANDS_MAX][ANAL_BLOCKL_MAX];
+} NoiseSuppressionC;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************
+ * WebRtcNs_InitCore(...)
+ *
+ * This function initializes a noise suppression instance
+ *
+ * Input:
+ * - self : Instance that should be initialized
+ * - fs : Sampling frequency
+ *
+ * Output:
+ * - self : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcNs_InitCore(NoiseSuppressionC* self, uint32_t fs);
+
+/****************************************************************************
+ * WebRtcNs_set_policy_core(...)
+ *
+ * This changes the aggressiveness of the noise suppression method.
+ *
+ * Input:
+ * - self : Instance that should be initialized
+ * - mode : 0: Mild (6dB), 1: Medium (10dB), 2: Aggressive (15dB)
+ *
+ * Output:
+ * - self : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcNs_set_policy_core(NoiseSuppressionC* self, int mode);
+
+/****************************************************************************
+ * WebRtcNs_AnalyzeCore
+ *
+ * Estimate the background noise.
+ *
+ * Input:
+ * - self : Instance that should be initialized
+ * - speechFrame : Input speech frame for lower band
+ *
+ * Output:
+ * - self : Updated instance
+ */
+void WebRtcNs_AnalyzeCore(NoiseSuppressionC* self, const float* speechFrame);
+
+/****************************************************************************
+ * WebRtcNs_ProcessCore
+ *
+ * Do noise suppression.
+ *
+ * Input:
+ * - self : Instance that should be initialized
+ * - inFrame : Input speech frame for each band
+ * - num_bands : Number of bands
+ *
+ * Output:
+ * - self : Updated instance
+ * - outFrame : Output speech frame for each band
+ */
+void WebRtcNs_ProcessCore(NoiseSuppressionC* self,
+ const float* const* inFrame,
+ size_t num_bands,
+ float* const* outFrame);
+
+#ifdef __cplusplus
+}
+#endif
+#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/legacy_ns/nsx_core.h b/modules/audio_processing/legacy_ns/nsx_core.h
new file mode 100644
index 0000000..a3f224a
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/nsx_core.h
@@ -0,0 +1,261 @@
+/*
+ * 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_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/legacy_ns/nsx_defines.h"
+
+typedef struct NoiseSuppressionFixedC_ {
+ uint32_t fs;
+
+ const int16_t* window;
+ int16_t analysisBuffer[ANAL_BLOCKL_MAX];
+ int16_t synthesisBuffer[ANAL_BLOCKL_MAX];
+ uint16_t noiseSupFilter[HALF_ANAL_BLOCKL];
+ uint16_t overdrive; /* Q8 */
+ uint16_t denoiseBound; /* Q14 */
+ const int16_t* factor2Table;
+ int16_t noiseEstLogQuantile[SIMULT * HALF_ANAL_BLOCKL];
+ int16_t noiseEstDensity[SIMULT * HALF_ANAL_BLOCKL];
+ int16_t noiseEstCounter[SIMULT];
+ int16_t noiseEstQuantile[HALF_ANAL_BLOCKL];
+
+ size_t anaLen;
+ size_t anaLen2;
+ size_t magnLen;
+ int aggrMode;
+ int stages;
+ int initFlag;
+ int gainMap;
+
+ int32_t maxLrt;
+ int32_t minLrt;
+ // Log LRT factor with time-smoothing in Q8.
+ int32_t logLrtTimeAvgW32[HALF_ANAL_BLOCKL];
+ int32_t featureLogLrt;
+ int32_t thresholdLogLrt;
+ int16_t weightLogLrt;
+
+ uint32_t featureSpecDiff;
+ uint32_t thresholdSpecDiff;
+ int16_t weightSpecDiff;
+
+ uint32_t featureSpecFlat;
+ uint32_t thresholdSpecFlat;
+ int16_t weightSpecFlat;
+
+ // Conservative estimate of noise spectrum.
+ int32_t avgMagnPause[HALF_ANAL_BLOCKL];
+ uint32_t magnEnergy;
+ uint32_t sumMagn;
+ uint32_t curAvgMagnEnergy;
+ uint32_t timeAvgMagnEnergy;
+ uint32_t timeAvgMagnEnergyTmp;
+
+ uint32_t whiteNoiseLevel; // Initial noise estimate.
+ // Initial magnitude spectrum estimate.
+ uint32_t initMagnEst[HALF_ANAL_BLOCKL];
+ // Pink noise parameters:
+ int32_t pinkNoiseNumerator; // Numerator.
+ int32_t pinkNoiseExp; // Power of freq.
+ int minNorm; // Smallest normalization factor.
+ int zeroInputSignal; // Zero input signal flag.
+
+ // Noise spectrum from previous frame.
+ uint32_t prevNoiseU32[HALF_ANAL_BLOCKL];
+ // Magnitude spectrum from previous frame.
+ uint16_t prevMagnU16[HALF_ANAL_BLOCKL];
+ // Prior speech/noise probability in Q14.
+ int16_t priorNonSpeechProb;
+
+ int blockIndex; // Frame index counter.
+ // Parameter for updating or estimating thresholds/weights for prior model.
+ int modelUpdate;
+ int cntThresUpdate;
+
+ // Histograms for parameter estimation.
+ int16_t histLrt[HIST_PAR_EST];
+ int16_t histSpecFlat[HIST_PAR_EST];
+ int16_t histSpecDiff[HIST_PAR_EST];
+
+ // Quantities for high band estimate.
+ int16_t dataBufHBFX[NUM_HIGH_BANDS_MAX][ANAL_BLOCKL_MAX];
+
+ int qNoise;
+ int prevQNoise;
+ int prevQMagn;
+ size_t blockLen10ms;
+
+ int16_t real[ANAL_BLOCKL_MAX];
+ int16_t imag[ANAL_BLOCKL_MAX];
+ int32_t energyIn;
+ int scaleEnergyIn;
+ int normData;
+
+ struct RealFFT* real_fft;
+} NoiseSuppressionFixedC;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****************************************************************************
+ * WebRtcNsx_InitCore(...)
+ *
+ * This function initializes a noise suppression instance
+ *
+ * Input:
+ * - inst : Instance that should be initialized
+ * - fs : Sampling frequency
+ *
+ * Output:
+ * - inst : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int32_t WebRtcNsx_InitCore(NoiseSuppressionFixedC* inst, uint32_t fs);
+
+/****************************************************************************
+ * WebRtcNsx_set_policy_core(...)
+ *
+ * This changes the aggressiveness of the noise suppression method.
+ *
+ * Input:
+ * - inst : Instance that should be initialized
+ * - mode : 0: Mild (6 dB), 1: Medium (10 dB), 2: Aggressive (15 dB)
+ *
+ * Output:
+ * - inst : Initialized instance
+ *
+ * Return value : 0 - Ok
+ * -1 - Error
+ */
+int WebRtcNsx_set_policy_core(NoiseSuppressionFixedC* inst, int mode);
+
+/****************************************************************************
+ * WebRtcNsx_ProcessCore
+ *
+ * Do noise suppression.
+ *
+ * Input:
+ * - inst : Instance that should be initialized
+ * - inFrame : Input speech frame for each band
+ * - num_bands : Number of bands
+ *
+ * Output:
+ * - inst : Updated instance
+ * - outFrame : Output speech frame for each band
+ */
+void WebRtcNsx_ProcessCore(NoiseSuppressionFixedC* inst,
+ const int16_t* const* inFrame,
+ int num_bands,
+ int16_t* const* outFrame);
+
+/****************************************************************************
+ * Some function pointers, for internal functions shared by ARM NEON and
+ * generic C code.
+ */
+// Noise Estimation.
+typedef void (*NoiseEstimation)(NoiseSuppressionFixedC* inst,
+ uint16_t* magn,
+ uint32_t* noise,
+ int16_t* q_noise);
+extern NoiseEstimation WebRtcNsx_NoiseEstimation;
+
+// Filter the data in the frequency domain, and create spectrum.
+typedef void (*PrepareSpectrum)(NoiseSuppressionFixedC* inst,
+ int16_t* freq_buff);
+extern PrepareSpectrum WebRtcNsx_PrepareSpectrum;
+
+// For the noise supression process, synthesis, read out fully processed
+// segment, and update synthesis buffer.
+typedef void (*SynthesisUpdate)(NoiseSuppressionFixedC* inst,
+ int16_t* out_frame,
+ int16_t gain_factor);
+extern SynthesisUpdate WebRtcNsx_SynthesisUpdate;
+
+// Update analysis buffer for lower band, and window data before FFT.
+typedef void (*AnalysisUpdate)(NoiseSuppressionFixedC* inst,
+ int16_t* out,
+ int16_t* new_speech);
+extern AnalysisUpdate WebRtcNsx_AnalysisUpdate;
+
+// Denormalize the real-valued signal |in|, the output from inverse FFT.
+typedef void (*Denormalize)(NoiseSuppressionFixedC* inst,
+ int16_t* in,
+ int factor);
+extern Denormalize WebRtcNsx_Denormalize;
+
+// Normalize the real-valued signal |in|, the input to forward FFT.
+typedef void (*NormalizeRealBuffer)(NoiseSuppressionFixedC* inst,
+ const int16_t* in,
+ int16_t* out);
+extern NormalizeRealBuffer WebRtcNsx_NormalizeRealBuffer;
+
+// Compute speech/noise probability.
+// Intended to be private.
+void WebRtcNsx_SpeechNoiseProb(NoiseSuppressionFixedC* inst,
+ uint16_t* nonSpeechProbFinal,
+ uint32_t* priorLocSnr,
+ uint32_t* postLocSnr);
+
+#if defined(WEBRTC_HAS_NEON)
+// For the above function pointers, functions for generic platforms are declared
+// and defined as static in file nsx_core.c, while those for ARM Neon platforms
+// are declared below and defined in file nsx_core_neon.c.
+void WebRtcNsx_NoiseEstimationNeon(NoiseSuppressionFixedC* inst,
+ uint16_t* magn,
+ uint32_t* noise,
+ int16_t* q_noise);
+void WebRtcNsx_SynthesisUpdateNeon(NoiseSuppressionFixedC* inst,
+ int16_t* out_frame,
+ int16_t gain_factor);
+void WebRtcNsx_AnalysisUpdateNeon(NoiseSuppressionFixedC* inst,
+ int16_t* out,
+ int16_t* new_speech);
+void WebRtcNsx_PrepareSpectrumNeon(NoiseSuppressionFixedC* inst,
+ int16_t* freq_buff);
+#endif
+
+#if defined(MIPS32_LE)
+// For the above function pointers, functions for generic platforms are declared
+// and defined as static in file nsx_core.c, while those for MIPS platforms
+// are declared below and defined in file nsx_core_mips.c.
+void WebRtcNsx_SynthesisUpdate_mips(NoiseSuppressionFixedC* inst,
+ int16_t* out_frame,
+ int16_t gain_factor);
+void WebRtcNsx_AnalysisUpdate_mips(NoiseSuppressionFixedC* inst,
+ int16_t* out,
+ int16_t* new_speech);
+void WebRtcNsx_PrepareSpectrum_mips(NoiseSuppressionFixedC* inst,
+ int16_t* freq_buff);
+void WebRtcNsx_NormalizeRealBuffer_mips(NoiseSuppressionFixedC* inst,
+ const int16_t* in,
+ int16_t* out);
+#if defined(MIPS_DSP_R1_LE)
+void WebRtcNsx_Denormalize_mips(NoiseSuppressionFixedC* inst,
+ int16_t* in,
+ int factor);
+#endif
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // MODULES_AUDIO_PROCESSING_LEGACY_NS_NSX_CORE_H_
diff --git a/modules/audio_processing/legacy_ns/nsx_core_c.c b/modules/audio_processing/legacy_ns/nsx_core_c.c
new file mode 100644
index 0000000..2b0bb2f
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/nsx_core_c.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2013 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 "rtc_base/checks.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,
+ 7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187
+};
+
+// Compute speech/noise probability
+// speech/noise probability is returned in: probSpeechFinal
+//snrLocPrior is the prior SNR for each frequency (in Q11)
+//snrLocPost is the post SNR for each frequency (in Q11)
+void WebRtcNsx_SpeechNoiseProb(NoiseSuppressionFixedC* inst,
+ uint16_t* nonSpeechProbFinal,
+ uint32_t* priorLocSnr,
+ uint32_t* postLocSnr) {
+ uint32_t zeros, num, den, tmpU32no1, tmpU32no2, tmpU32no3;
+ int32_t invLrtFX, indPriorFX, tmp32, tmp32no1, tmp32no2, besselTmpFX32;
+ int32_t frac32, logTmp;
+ int32_t logLrtTimeAvgKsumFX;
+ int16_t indPriorFX16;
+ int16_t tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac, intPart;
+ size_t i;
+ int normTmp, normTmp2, nShifts;
+
+ // compute feature based on average LR factor
+ // this is the average over all frequencies of the smooth log LRT
+ logLrtTimeAvgKsumFX = 0;
+ for (i = 0; i < inst->magnLen; i++) {
+ besselTmpFX32 = (int32_t)postLocSnr[i]; // Q11
+ normTmp = WebRtcSpl_NormU32(postLocSnr[i]);
+ num = postLocSnr[i] << normTmp; // Q(11+normTmp)
+ if (normTmp > 10) {
+ den = priorLocSnr[i] << (normTmp - 11); // Q(normTmp)
+ } else {
+ den = priorLocSnr[i] >> (11 - normTmp); // Q(normTmp)
+ }
+ if (den > 0) {
+ besselTmpFX32 -= num / den; // Q11
+ } else {
+ besselTmpFX32 = 0;
+ }
+
+ // inst->logLrtTimeAvg[i] += LRT_TAVG * (besselTmp - log(snrLocPrior)
+ // - inst->logLrtTimeAvg[i]);
+ // Here, LRT_TAVG = 0.5
+ zeros = WebRtcSpl_NormU32(priorLocSnr[i]);
+ frac32 = (int32_t)(((priorLocSnr[i] << zeros) & 0x7FFFFFFF) >> 19);
+ tmp32 = (frac32 * frac32 * -43) >> 19;
+ tmp32 += ((int16_t)frac32 * 5412) >> 12;
+ frac32 = tmp32 + 37;
+ // tmp32 = log2(priorLocSnr[i])
+ tmp32 = (int32_t)(((31 - zeros) << 12) + frac32) - (11 << 12); // Q12
+ logTmp = (tmp32 * 178) >> 8; // log2(priorLocSnr[i])*log(2)
+ // tmp32no1 = LRT_TAVG * (log(snrLocPrior) + inst->logLrtTimeAvg[i]) in Q12.
+ tmp32no1 = (logTmp + inst->logLrtTimeAvgW32[i]) / 2;
+ inst->logLrtTimeAvgW32[i] += (besselTmpFX32 - tmp32no1); // Q12
+
+ logLrtTimeAvgKsumFX += inst->logLrtTimeAvgW32[i]; // Q12
+ }
+ inst->featureLogLrt = (logLrtTimeAvgKsumFX * BIN_SIZE_LRT) >>
+ (inst->stages + 11);
+
+ // done with computation of LR factor
+
+ //
+ //compute the indicator functions
+ //
+
+ // average LRT feature
+ // FLOAT code
+ // indicator0 = 0.5 * (tanh(widthPrior *
+ // (logLrtTimeAvgKsum - threshPrior0)) + 1.0);
+ tmpIndFX = 16384; // Q14(1.0)
+ tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12
+ nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5;
+ //use larger width in tanh map for pause regions
+ if (tmp32no1 < 0) {
+ tmpIndFX = 0;
+ tmp32no1 = -tmp32no1;
+ //widthPrior = widthPrior * 2.0;
+ nShifts++;
+ }
+ tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14
+ // compute indicator function: sigmoid map
+ if (tmp32no1 < (16 << 14) && tmp32no1 >= 0) {
+ tableIndex = (int16_t)(tmp32no1 >> 14);
+ tmp16no2 = kIndicatorTable[tableIndex];
+ tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
+ frac = (int16_t)(tmp32no1 & 0x00003fff); // Q14
+ tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
+ if (tmpIndFX == 0) {
+ tmpIndFX = 8192 - tmp16no2; // Q14
+ } else {
+ tmpIndFX = 8192 + tmp16no2; // Q14
+ }
+ }
+ indPriorFX = inst->weightLogLrt * tmpIndFX; // 6*Q14
+
+ //spectral flatness feature
+ if (inst->weightSpecFlat) {
+ tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10
+ tmpIndFX = 16384; // Q14(1.0)
+ //use larger width in tanh map for pause regions
+ tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10
+ nShifts = 4;
+ if (inst->thresholdSpecFlat < tmpU32no1) {
+ tmpIndFX = 0;
+ tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat;
+ //widthPrior = widthPrior * 2.0;
+ nShifts++;
+ }
+ tmpU32no1 = WebRtcSpl_DivU32U16(tmpU32no2 << nShifts, 25); // Q14
+ // compute indicator function: sigmoid map
+ // FLOAT code
+ // indicator1 = 0.5 * (tanh(sgnMap * widthPrior *
+ // (threshPrior1 - tmpFloat1)) + 1.0);
+ if (tmpU32no1 < (16 << 14)) {
+ tableIndex = (int16_t)(tmpU32no1 >> 14);
+ tmp16no2 = kIndicatorTable[tableIndex];
+ tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
+ frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
+ tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
+ if (tmpIndFX) {
+ tmpIndFX = 8192 + tmp16no2; // Q14
+ } else {
+ tmpIndFX = 8192 - tmp16no2; // Q14
+ }
+ }
+ indPriorFX += inst->weightSpecFlat * tmpIndFX; // 6*Q14
+ }
+
+ //for template spectral-difference
+ if (inst->weightSpecDiff) {
+ tmpU32no1 = 0;
+ if (inst->featureSpecDiff) {
+ normTmp = WEBRTC_SPL_MIN(20 - inst->stages,
+ WebRtcSpl_NormU32(inst->featureSpecDiff));
+ RTC_DCHECK_GE(normTmp, 0);
+ tmpU32no1 = inst->featureSpecDiff << normTmp; // Q(normTmp-2*stages)
+ tmpU32no2 = inst->timeAvgMagnEnergy >> (20 - inst->stages - normTmp);
+ if (tmpU32no2 > 0) {
+ // Q(20 - inst->stages)
+ tmpU32no1 /= tmpU32no2;
+ } else {
+ tmpU32no1 = (uint32_t)(0x7fffffff);
+ }
+ }
+ tmpU32no3 = (inst->thresholdSpecDiff << 17) / 25;
+ tmpU32no2 = tmpU32no1 - tmpU32no3;
+ nShifts = 1;
+ tmpIndFX = 16384; // Q14(1.0)
+ //use larger width in tanh map for pause regions
+ if (tmpU32no2 & 0x80000000) {
+ tmpIndFX = 0;
+ tmpU32no2 = tmpU32no3 - tmpU32no1;
+ //widthPrior = widthPrior * 2.0;
+ nShifts--;
+ }
+ tmpU32no1 = tmpU32no2 >> nShifts;
+ // compute indicator function: sigmoid map
+ /* FLOAT code
+ indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0);
+ */
+ if (tmpU32no1 < (16 << 14)) {
+ tableIndex = (int16_t)(tmpU32no1 >> 14);
+ tmp16no2 = kIndicatorTable[tableIndex];
+ tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
+ frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
+ tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
+ tmp16no1, frac, 14);
+ if (tmpIndFX) {
+ tmpIndFX = 8192 + tmp16no2;
+ } else {
+ tmpIndFX = 8192 - tmp16no2;
+ }
+ }
+ indPriorFX += inst->weightSpecDiff * tmpIndFX; // 6*Q14
+ }
+
+ //combine the indicator function with the feature weights
+ // FLOAT code
+ // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 *
+ // indicator1 + weightIndPrior2 * indicator2);
+ indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14
+ // done with computing indicator function
+
+ //compute the prior probability
+ // FLOAT code
+ // inst->priorNonSpeechProb += PRIOR_UPDATE *
+ // (indPriorNonSpeech - inst->priorNonSpeechProb);
+ tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14
+ inst->priorNonSpeechProb += (int16_t)((PRIOR_UPDATE_Q14 * tmp16) >> 14);
+
+ //final speech probability: combine prior model with LR factor:
+
+ memset(nonSpeechProbFinal, 0, sizeof(uint16_t) * inst->magnLen);
+
+ if (inst->priorNonSpeechProb > 0) {
+ for (i = 0; i < inst->magnLen; i++) {
+ // FLOAT code
+ // invLrt = exp(inst->logLrtTimeAvg[i]);
+ // invLrt = inst->priorSpeechProb * invLrt;
+ // nonSpeechProbFinal[i] = (1.0 - inst->priorSpeechProb) /
+ // (1.0 - inst->priorSpeechProb + invLrt);
+ // invLrt = (1.0 - inst->priorNonSpeechProb) * invLrt;
+ // nonSpeechProbFinal[i] = inst->priorNonSpeechProb /
+ // (inst->priorNonSpeechProb + invLrt);
+ if (inst->logLrtTimeAvgW32[i] < 65300) {
+ tmp32no1 = (inst->logLrtTimeAvgW32[i] * 23637) >> 14; // Q12
+ intPart = (int16_t)(tmp32no1 >> 12);
+ if (intPart < -8) {
+ intPart = -8;
+ }
+ frac = (int16_t)(tmp32no1 & 0x00000fff); // Q12
+
+ // Quadratic approximation of 2^frac
+ tmp32no2 = (frac * frac * 44) >> 19; // Q12.
+ tmp32no2 += (frac * 84) >> 7; // Q12
+ invLrtFX = (1 << (8 + intPart)) +
+ WEBRTC_SPL_SHIFT_W32(tmp32no2, intPart - 4); // Q8
+
+ normTmp = WebRtcSpl_NormW32(invLrtFX);
+ normTmp2 = WebRtcSpl_NormW16((16384 - inst->priorNonSpeechProb));
+ if (normTmp + normTmp2 >= 7) {
+ if (normTmp + normTmp2 < 15) {
+ invLrtFX >>= 15 - normTmp2 - normTmp;
+ // Q(normTmp+normTmp2-7)
+ tmp32no1 = invLrtFX * (16384 - inst->priorNonSpeechProb);
+ // Q(normTmp+normTmp2+7)
+ invLrtFX = WEBRTC_SPL_SHIFT_W32(tmp32no1, 7 - normTmp - normTmp2);
+ // Q14
+ } else {
+ tmp32no1 = invLrtFX * (16384 - inst->priorNonSpeechProb);
+ // Q22
+ invLrtFX = tmp32no1 >> 8; // Q14.
+ }
+
+ tmp32no1 = (int32_t)inst->priorNonSpeechProb << 8; // Q22
+
+ nonSpeechProbFinal[i] = tmp32no1 /
+ (inst->priorNonSpeechProb + invLrtFX); // Q8
+ }
+ }
+ }
+ }
+}
diff --git a/modules/audio_processing/legacy_ns/nsx_core_mips.c b/modules/audio_processing/legacy_ns/nsx_core_mips.c
new file mode 100644
index 0000000..af4c287
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/nsx_core_mips.c
@@ -0,0 +1,1001 @@
+/*
+ * Copyright (c) 2013 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 <string.h>
+
+#include "rtc_base/checks.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,
+ 7901, 8014, 8084, 8126, 8152, 8168, 8177, 8183, 8187
+};
+
+// Compute speech/noise probability
+// speech/noise probability is returned in: probSpeechFinal
+//snrLocPrior is the prior SNR for each frequency (in Q11)
+//snrLocPost is the post SNR for each frequency (in Q11)
+void WebRtcNsx_SpeechNoiseProb(NoiseSuppressionFixedC* inst,
+ uint16_t* nonSpeechProbFinal,
+ uint32_t* priorLocSnr,
+ uint32_t* postLocSnr) {
+ uint32_t tmpU32no1, tmpU32no2, tmpU32no3;
+ int32_t indPriorFX, tmp32no1;
+ int32_t logLrtTimeAvgKsumFX;
+ int16_t indPriorFX16;
+ int16_t tmp16, tmp16no1, tmp16no2, tmpIndFX, tableIndex, frac;
+ size_t i;
+ int normTmp, nShifts;
+
+ int32_t r0, r1, r2, r3, r4, r5, r6, r7, r8, r9;
+ int32_t const_max = 0x7fffffff;
+ int32_t const_neg43 = -43;
+ int32_t const_5412 = 5412;
+ int32_t const_11rsh12 = (11 << 12);
+ int32_t const_178 = 178;
+
+
+ // compute feature based on average LR factor
+ // this is the average over all frequencies of the smooth log LRT
+ logLrtTimeAvgKsumFX = 0;
+ for (i = 0; i < inst->magnLen; i++) {
+ r0 = postLocSnr[i]; // Q11
+ r1 = priorLocSnr[i];
+ r2 = inst->logLrtTimeAvgW32[i];
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "clz %[r3], %[r0] \n\t"
+ "clz %[r5], %[r1] \n\t"
+ "slti %[r4], %[r3], 32 \n\t"
+ "slti %[r6], %[r5], 32 \n\t"
+ "movz %[r3], $0, %[r4] \n\t"
+ "movz %[r5], $0, %[r6] \n\t"
+ "slti %[r4], %[r3], 11 \n\t"
+ "addiu %[r6], %[r3], -11 \n\t"
+ "neg %[r7], %[r6] \n\t"
+ "sllv %[r6], %[r1], %[r6] \n\t"
+ "srav %[r7], %[r1], %[r7] \n\t"
+ "movn %[r6], %[r7], %[r4] \n\t"
+ "sllv %[r1], %[r1], %[r5] \n\t"
+ "and %[r1], %[r1], %[const_max] \n\t"
+ "sra %[r1], %[r1], 19 \n\t"
+ "mul %[r7], %[r1], %[r1] \n\t"
+ "sllv %[r3], %[r0], %[r3] \n\t"
+ "divu %[r8], %[r3], %[r6] \n\t"
+ "slti %[r6], %[r6], 1 \n\t"
+ "mul %[r7], %[r7], %[const_neg43] \n\t"
+ "sra %[r7], %[r7], 19 \n\t"
+ "movz %[r3], %[r8], %[r6] \n\t"
+ "subu %[r0], %[r0], %[r3] \n\t"
+ "movn %[r0], $0, %[r6] \n\t"
+ "mul %[r1], %[r1], %[const_5412] \n\t"
+ "sra %[r1], %[r1], 12 \n\t"
+ "addu %[r7], %[r7], %[r1] \n\t"
+ "addiu %[r1], %[r7], 37 \n\t"
+ "addiu %[r5], %[r5], -31 \n\t"
+ "neg %[r5], %[r5] \n\t"
+ "sll %[r5], %[r5], 12 \n\t"
+ "addu %[r5], %[r5], %[r1] \n\t"
+ "subu %[r7], %[r5], %[const_11rsh12] \n\t"
+ "mul %[r7], %[r7], %[const_178] \n\t"
+ "sra %[r7], %[r7], 8 \n\t"
+ "addu %[r7], %[r7], %[r2] \n\t"
+ "sra %[r7], %[r7], 1 \n\t"
+ "subu %[r2], %[r2], %[r7] \n\t"
+ "addu %[r2], %[r2], %[r0] \n\t"
+ ".set pop \n\t"
+ : [r0] "+r" (r0), [r1] "+r" (r1), [r2] "+r" (r2),
+ [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
+ [r6] "=&r" (r6), [r7] "=&r" (r7), [r8] "=&r" (r8)
+ : [const_max] "r" (const_max), [const_neg43] "r" (const_neg43),
+ [const_5412] "r" (const_5412), [const_11rsh12] "r" (const_11rsh12),
+ [const_178] "r" (const_178)
+ : "hi", "lo"
+ );
+ inst->logLrtTimeAvgW32[i] = r2;
+ logLrtTimeAvgKsumFX += r2;
+ }
+
+ inst->featureLogLrt = (logLrtTimeAvgKsumFX * BIN_SIZE_LRT) >>
+ (inst->stages + 11);
+
+ // done with computation of LR factor
+
+ //
+ // compute the indicator functions
+ //
+
+ // average LRT feature
+ // FLOAT code
+ // indicator0 = 0.5 * (tanh(widthPrior *
+ // (logLrtTimeAvgKsum - threshPrior0)) + 1.0);
+ tmpIndFX = 16384; // Q14(1.0)
+ tmp32no1 = logLrtTimeAvgKsumFX - inst->thresholdLogLrt; // Q12
+ nShifts = 7 - inst->stages; // WIDTH_PR_MAP_SHIFT - inst->stages + 5;
+ //use larger width in tanh map for pause regions
+ if (tmp32no1 < 0) {
+ tmpIndFX = 0;
+ tmp32no1 = -tmp32no1;
+ //widthPrior = widthPrior * 2.0;
+ nShifts++;
+ }
+ tmp32no1 = WEBRTC_SPL_SHIFT_W32(tmp32no1, nShifts); // Q14
+ // compute indicator function: sigmoid map
+ if (tmp32no1 < (16 << 14) && tmp32no1 >= 0) {
+ tableIndex = (int16_t)(tmp32no1 >> 14);
+ tmp16no2 = kIndicatorTable[tableIndex];
+ tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
+ frac = (int16_t)(tmp32no1 & 0x00003fff); // Q14
+ tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
+ if (tmpIndFX == 0) {
+ tmpIndFX = 8192 - tmp16no2; // Q14
+ } else {
+ tmpIndFX = 8192 + tmp16no2; // Q14
+ }
+ }
+ indPriorFX = inst->weightLogLrt * tmpIndFX; // 6*Q14
+
+ //spectral flatness feature
+ if (inst->weightSpecFlat) {
+ tmpU32no1 = WEBRTC_SPL_UMUL(inst->featureSpecFlat, 400); // Q10
+ tmpIndFX = 16384; // Q14(1.0)
+ //use larger width in tanh map for pause regions
+ tmpU32no2 = inst->thresholdSpecFlat - tmpU32no1; //Q10
+ nShifts = 4;
+ if (inst->thresholdSpecFlat < tmpU32no1) {
+ tmpIndFX = 0;
+ tmpU32no2 = tmpU32no1 - inst->thresholdSpecFlat;
+ //widthPrior = widthPrior * 2.0;
+ nShifts++;
+ }
+ tmpU32no1 = WebRtcSpl_DivU32U16(tmpU32no2 << nShifts, 25); //Q14
+ // compute indicator function: sigmoid map
+ // FLOAT code
+ // indicator1 = 0.5 * (tanh(sgnMap * widthPrior *
+ // (threshPrior1 - tmpFloat1)) + 1.0);
+ if (tmpU32no1 < (16 << 14)) {
+ tableIndex = (int16_t)(tmpU32no1 >> 14);
+ tmp16no2 = kIndicatorTable[tableIndex];
+ tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
+ frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
+ tmp16no2 += (int16_t)((tmp16no1 * frac) >> 14);
+ if (tmpIndFX) {
+ tmpIndFX = 8192 + tmp16no2; // Q14
+ } else {
+ tmpIndFX = 8192 - tmp16no2; // Q14
+ }
+ }
+ indPriorFX += inst->weightSpecFlat * tmpIndFX; // 6*Q14
+ }
+
+ //for template spectral-difference
+ if (inst->weightSpecDiff) {
+ tmpU32no1 = 0;
+ if (inst->featureSpecDiff) {
+ normTmp = WEBRTC_SPL_MIN(20 - inst->stages,
+ WebRtcSpl_NormU32(inst->featureSpecDiff));
+ RTC_DCHECK_GE(normTmp, 0);
+ tmpU32no1 = inst->featureSpecDiff << normTmp; // Q(normTmp-2*stages)
+ tmpU32no2 = inst->timeAvgMagnEnergy >> (20 - inst->stages - normTmp);
+ if (tmpU32no2 > 0) {
+ // Q(20 - inst->stages)
+ tmpU32no1 /= tmpU32no2;
+ } else {
+ tmpU32no1 = (uint32_t)(0x7fffffff);
+ }
+ }
+ tmpU32no3 = (inst->thresholdSpecDiff << 17) / 25;
+ tmpU32no2 = tmpU32no1 - tmpU32no3;
+ nShifts = 1;
+ tmpIndFX = 16384; // Q14(1.0)
+ //use larger width in tanh map for pause regions
+ if (tmpU32no2 & 0x80000000) {
+ tmpIndFX = 0;
+ tmpU32no2 = tmpU32no3 - tmpU32no1;
+ //widthPrior = widthPrior * 2.0;
+ nShifts--;
+ }
+ tmpU32no1 = tmpU32no2 >> nShifts;
+ // compute indicator function: sigmoid map
+ /* FLOAT code
+ indicator2 = 0.5 * (tanh(widthPrior * (tmpFloat1 - threshPrior2)) + 1.0);
+ */
+ if (tmpU32no1 < (16 << 14)) {
+ tableIndex = (int16_t)(tmpU32no1 >> 14);
+ tmp16no2 = kIndicatorTable[tableIndex];
+ tmp16no1 = kIndicatorTable[tableIndex + 1] - kIndicatorTable[tableIndex];
+ frac = (int16_t)(tmpU32no1 & 0x00003fff); // Q14
+ tmp16no2 += (int16_t)WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(
+ tmp16no1, frac, 14);
+ if (tmpIndFX) {
+ tmpIndFX = 8192 + tmp16no2;
+ } else {
+ tmpIndFX = 8192 - tmp16no2;
+ }
+ }
+ indPriorFX += inst->weightSpecDiff * tmpIndFX; // 6*Q14
+ }
+
+ //combine the indicator function with the feature weights
+ // FLOAT code
+ // indPrior = 1 - (weightIndPrior0 * indicator0 + weightIndPrior1 *
+ // indicator1 + weightIndPrior2 * indicator2);
+ indPriorFX16 = WebRtcSpl_DivW32W16ResW16(98307 - indPriorFX, 6); // Q14
+ // done with computing indicator function
+
+ //compute the prior probability
+ // FLOAT code
+ // inst->priorNonSpeechProb += PRIOR_UPDATE *
+ // (indPriorNonSpeech - inst->priorNonSpeechProb);
+ tmp16 = indPriorFX16 - inst->priorNonSpeechProb; // Q14
+ inst->priorNonSpeechProb += (int16_t)((PRIOR_UPDATE_Q14 * tmp16) >> 14);
+
+ //final speech probability: combine prior model with LR factor:
+
+ memset(nonSpeechProbFinal, 0, sizeof(uint16_t) * inst->magnLen);
+
+ if (inst->priorNonSpeechProb > 0) {
+ r0 = inst->priorNonSpeechProb;
+ r1 = 16384 - r0;
+ int32_t const_23637 = 23637;
+ int32_t const_44 = 44;
+ int32_t const_84 = 84;
+ int32_t const_1 = 1;
+ int32_t const_neg8 = -8;
+ for (i = 0; i < inst->magnLen; i++) {
+ r2 = inst->logLrtTimeAvgW32[i];
+ if (r2 < 65300) {
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "mul %[r2], %[r2], %[const_23637] \n\t"
+ "sll %[r6], %[r1], 16 \n\t"
+ "clz %[r7], %[r6] \n\t"
+ "clo %[r8], %[r6] \n\t"
+ "slt %[r9], %[r6], $0 \n\t"
+ "movn %[r7], %[r8], %[r9] \n\t"
+ "sra %[r2], %[r2], 14 \n\t"
+ "andi %[r3], %[r2], 0xfff \n\t"
+ "mul %[r4], %[r3], %[r3] \n\t"
+ "mul %[r3], %[r3], %[const_84] \n\t"
+ "sra %[r2], %[r2], 12 \n\t"
+ "slt %[r5], %[r2], %[const_neg8] \n\t"
+ "movn %[r2], %[const_neg8], %[r5] \n\t"
+ "mul %[r4], %[r4], %[const_44] \n\t"
+ "sra %[r3], %[r3], 7 \n\t"
+ "addiu %[r7], %[r7], -1 \n\t"
+ "slti %[r9], %[r7], 31 \n\t"
+ "movz %[r7], $0, %[r9] \n\t"
+ "sra %[r4], %[r4], 19 \n\t"
+ "addu %[r4], %[r4], %[r3] \n\t"
+ "addiu %[r3], %[r2], 8 \n\t"
+ "addiu %[r2], %[r2], -4 \n\t"
+ "neg %[r5], %[r2] \n\t"
+ "sllv %[r6], %[r4], %[r2] \n\t"
+ "srav %[r5], %[r4], %[r5] \n\t"
+ "slt %[r2], %[r2], $0 \n\t"
+ "movn %[r6], %[r5], %[r2] \n\t"
+ "sllv %[r3], %[const_1], %[r3] \n\t"
+ "addu %[r2], %[r3], %[r6] \n\t"
+ "clz %[r4], %[r2] \n\t"
+ "clo %[r5], %[r2] \n\t"
+ "slt %[r8], %[r2], $0 \n\t"
+ "movn %[r4], %[r5], %[r8] \n\t"
+ "addiu %[r4], %[r4], -1 \n\t"
+ "slt %[r5], $0, %[r2] \n\t"
+ "or %[r5], %[r5], %[r7] \n\t"
+ "movz %[r4], $0, %[r5] \n\t"
+ "addiu %[r6], %[r7], -7 \n\t"
+ "addu %[r6], %[r6], %[r4] \n\t"
+ "bltz %[r6], 1f \n\t"
+ " nop \n\t"
+ "addiu %[r4], %[r6], -8 \n\t"
+ "neg %[r3], %[r4] \n\t"
+ "srav %[r5], %[r2], %[r3] \n\t"
+ "mul %[r5], %[r5], %[r1] \n\t"
+ "mul %[r2], %[r2], %[r1] \n\t"
+ "slt %[r4], %[r4], $0 \n\t"
+ "srav %[r5], %[r5], %[r6] \n\t"
+ "sra %[r2], %[r2], 8 \n\t"
+ "movn %[r2], %[r5], %[r4] \n\t"
+ "sll %[r3], %[r0], 8 \n\t"
+ "addu %[r2], %[r0], %[r2] \n\t"
+ "divu %[r3], %[r3], %[r2] \n\t"
+ "1: \n\t"
+ ".set pop \n\t"
+ : [r2] "+r" (r2), [r3] "=&r" (r3), [r4] "=&r" (r4),
+ [r5] "=&r" (r5), [r6] "=&r" (r6), [r7] "=&r" (r7),
+ [r8] "=&r" (r8), [r9] "=&r" (r9)
+ : [r0] "r" (r0), [r1] "r" (r1), [const_23637] "r" (const_23637),
+ [const_neg8] "r" (const_neg8), [const_84] "r" (const_84),
+ [const_1] "r" (const_1), [const_44] "r" (const_44)
+ : "hi", "lo"
+ );
+ nonSpeechProbFinal[i] = r3;
+ }
+ }
+ }
+}
+
+// Update analysis buffer for lower band, and window data before FFT.
+void WebRtcNsx_AnalysisUpdate_mips(NoiseSuppressionFixedC* inst,
+ int16_t* out,
+ int16_t* new_speech) {
+ int iters, after;
+ int anaLen = (int)inst->anaLen;
+ int *window = (int*)inst->window;
+ int *anaBuf = (int*)inst->analysisBuffer;
+ int *outBuf = (int*)out;
+ int r0, r1, r2, r3, r4, r5, r6, r7;
+#if defined(MIPS_DSP_R1_LE)
+ int r8;
+#endif
+
+ // 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.
+#if defined(MIPS_DSP_R1_LE)
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "sra %[iters], %[anaLen], 3 \n\t"
+ "1: \n\t"
+ "blez %[iters], 2f \n\t"
+ " nop \n\t"
+ "lw %[r0], 0(%[window]) \n\t"
+ "lw %[r1], 0(%[anaBuf]) \n\t"
+ "lw %[r2], 4(%[window]) \n\t"
+ "lw %[r3], 4(%[anaBuf]) \n\t"
+ "lw %[r4], 8(%[window]) \n\t"
+ "lw %[r5], 8(%[anaBuf]) \n\t"
+ "lw %[r6], 12(%[window]) \n\t"
+ "lw %[r7], 12(%[anaBuf]) \n\t"
+ "muleq_s.w.phl %[r8], %[r0], %[r1] \n\t"
+ "muleq_s.w.phr %[r0], %[r0], %[r1] \n\t"
+ "muleq_s.w.phl %[r1], %[r2], %[r3] \n\t"
+ "muleq_s.w.phr %[r2], %[r2], %[r3] \n\t"
+ "muleq_s.w.phl %[r3], %[r4], %[r5] \n\t"
+ "muleq_s.w.phr %[r4], %[r4], %[r5] \n\t"
+ "muleq_s.w.phl %[r5], %[r6], %[r7] \n\t"
+ "muleq_s.w.phr %[r6], %[r6], %[r7] \n\t"
+#if defined(MIPS_DSP_R2_LE)
+ "precr_sra_r.ph.w %[r8], %[r0], 15 \n\t"
+ "precr_sra_r.ph.w %[r1], %[r2], 15 \n\t"
+ "precr_sra_r.ph.w %[r3], %[r4], 15 \n\t"
+ "precr_sra_r.ph.w %[r5], %[r6], 15 \n\t"
+ "sw %[r8], 0(%[outBuf]) \n\t"
+ "sw %[r1], 4(%[outBuf]) \n\t"
+ "sw %[r3], 8(%[outBuf]) \n\t"
+ "sw %[r5], 12(%[outBuf]) \n\t"
+#else
+ "shra_r.w %[r8], %[r8], 15 \n\t"
+ "shra_r.w %[r0], %[r0], 15 \n\t"
+ "shra_r.w %[r1], %[r1], 15 \n\t"
+ "shra_r.w %[r2], %[r2], 15 \n\t"
+ "shra_r.w %[r3], %[r3], 15 \n\t"
+ "shra_r.w %[r4], %[r4], 15 \n\t"
+ "shra_r.w %[r5], %[r5], 15 \n\t"
+ "shra_r.w %[r6], %[r6], 15 \n\t"
+ "sll %[r0], %[r0], 16 \n\t"
+ "sll %[r2], %[r2], 16 \n\t"
+ "sll %[r4], %[r4], 16 \n\t"
+ "sll %[r6], %[r6], 16 \n\t"
+ "packrl.ph %[r0], %[r8], %[r0] \n\t"
+ "packrl.ph %[r2], %[r1], %[r2] \n\t"
+ "packrl.ph %[r4], %[r3], %[r4] \n\t"
+ "packrl.ph %[r6], %[r5], %[r6] \n\t"
+ "sw %[r0], 0(%[outBuf]) \n\t"
+ "sw %[r2], 4(%[outBuf]) \n\t"
+ "sw %[r4], 8(%[outBuf]) \n\t"
+ "sw %[r6], 12(%[outBuf]) \n\t"
+#endif
+ "addiu %[window], %[window], 16 \n\t"
+ "addiu %[anaBuf], %[anaBuf], 16 \n\t"
+ "addiu %[outBuf], %[outBuf], 16 \n\t"
+ "b 1b \n\t"
+ " addiu %[iters], %[iters], -1 \n\t"
+ "2: \n\t"
+ "andi %[after], %[anaLen], 7 \n\t"
+ "3: \n\t"
+ "blez %[after], 4f \n\t"
+ " nop \n\t"
+ "lh %[r0], 0(%[window]) \n\t"
+ "lh %[r1], 0(%[anaBuf]) \n\t"
+ "mul %[r0], %[r0], %[r1] \n\t"
+ "addiu %[window], %[window], 2 \n\t"
+ "addiu %[anaBuf], %[anaBuf], 2 \n\t"
+ "addiu %[outBuf], %[outBuf], 2 \n\t"
+ "shra_r.w %[r0], %[r0], 14 \n\t"
+ "sh %[r0], -2(%[outBuf]) \n\t"
+ "b 3b \n\t"
+ " addiu %[after], %[after], -1 \n\t"
+ "4: \n\t"
+ ".set pop \n\t"
+ : [r0] "=&r" (r0), [r1] "=&r" (r1), [r2] "=&r" (r2),
+ [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
+ [r6] "=&r" (r6), [r7] "=&r" (r7), [r8] "=&r" (r8),
+ [iters] "=&r" (iters), [after] "=&r" (after),
+ [window] "+r" (window),[anaBuf] "+r" (anaBuf),
+ [outBuf] "+r" (outBuf)
+ : [anaLen] "r" (anaLen)
+ : "memory", "hi", "lo"
+ );
+#else
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "sra %[iters], %[anaLen], 2 \n\t"
+ "1: \n\t"
+ "blez %[iters], 2f \n\t"
+ " nop \n\t"
+ "lh %[r0], 0(%[window]) \n\t"
+ "lh %[r1], 0(%[anaBuf]) \n\t"
+ "lh %[r2], 2(%[window]) \n\t"
+ "lh %[r3], 2(%[anaBuf]) \n\t"
+ "lh %[r4], 4(%[window]) \n\t"
+ "lh %[r5], 4(%[anaBuf]) \n\t"
+ "lh %[r6], 6(%[window]) \n\t"
+ "lh %[r7], 6(%[anaBuf]) \n\t"
+ "mul %[r0], %[r0], %[r1] \n\t"
+ "mul %[r2], %[r2], %[r3] \n\t"
+ "mul %[r4], %[r4], %[r5] \n\t"
+ "mul %[r6], %[r6], %[r7] \n\t"
+ "addiu %[window], %[window], 8 \n\t"
+ "addiu %[anaBuf], %[anaBuf], 8 \n\t"
+ "addiu %[r0], %[r0], 0x2000 \n\t"
+ "addiu %[r2], %[r2], 0x2000 \n\t"
+ "addiu %[r4], %[r4], 0x2000 \n\t"
+ "addiu %[r6], %[r6], 0x2000 \n\t"
+ "sra %[r0], %[r0], 14 \n\t"
+ "sra %[r2], %[r2], 14 \n\t"
+ "sra %[r4], %[r4], 14 \n\t"
+ "sra %[r6], %[r6], 14 \n\t"
+ "sh %[r0], 0(%[outBuf]) \n\t"
+ "sh %[r2], 2(%[outBuf]) \n\t"
+ "sh %[r4], 4(%[outBuf]) \n\t"
+ "sh %[r6], 6(%[outBuf]) \n\t"
+ "addiu %[outBuf], %[outBuf], 8 \n\t"
+ "b 1b \n\t"
+ " addiu %[iters], %[iters], -1 \n\t"
+ "2: \n\t"
+ "andi %[after], %[anaLen], 3 \n\t"
+ "3: \n\t"
+ "blez %[after], 4f \n\t"
+ " nop \n\t"
+ "lh %[r0], 0(%[window]) \n\t"
+ "lh %[r1], 0(%[anaBuf]) \n\t"
+ "mul %[r0], %[r0], %[r1] \n\t"
+ "addiu %[window], %[window], 2 \n\t"
+ "addiu %[anaBuf], %[anaBuf], 2 \n\t"
+ "addiu %[outBuf], %[outBuf], 2 \n\t"
+ "addiu %[r0], %[r0], 0x2000 \n\t"
+ "sra %[r0], %[r0], 14 \n\t"
+ "sh %[r0], -2(%[outBuf]) \n\t"
+ "b 3b \n\t"
+ " addiu %[after], %[after], -1 \n\t"
+ "4: \n\t"
+ ".set pop \n\t"
+ : [r0] "=&r" (r0), [r1] "=&r" (r1), [r2] "=&r" (r2),
+ [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
+ [r6] "=&r" (r6), [r7] "=&r" (r7), [iters] "=&r" (iters),
+ [after] "=&r" (after), [window] "+r" (window),
+ [anaBuf] "+r" (anaBuf), [outBuf] "+r" (outBuf)
+ : [anaLen] "r" (anaLen)
+ : "memory", "hi", "lo"
+ );
+#endif
+}
+
+// For the noise supression process, synthesis, read out fully processed
+// segment, and update synthesis buffer.
+void WebRtcNsx_SynthesisUpdate_mips(NoiseSuppressionFixedC* inst,
+ int16_t* out_frame,
+ int16_t gain_factor) {
+ int iters = (int)inst->blockLen10ms >> 2;
+ int after = inst->blockLen10ms & 3;
+ int r0, r1, r2, r3, r4, r5, r6, r7;
+ int16_t *window = (int16_t*)inst->window;
+ int16_t *real = inst->real;
+ int16_t *synthBuf = inst->synthesisBuffer;
+ int16_t *out = out_frame;
+ int sat_pos = 0x7fff;
+ int sat_neg = 0xffff8000;
+ int block10 = (int)inst->blockLen10ms;
+ int anaLen = (int)inst->anaLen;
+
+ __asm __volatile(
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "1: \n\t"
+ "blez %[iters], 2f \n\t"
+ " nop \n\t"
+ "lh %[r0], 0(%[window]) \n\t"
+ "lh %[r1], 0(%[real]) \n\t"
+ "lh %[r2], 2(%[window]) \n\t"
+ "lh %[r3], 2(%[real]) \n\t"
+ "lh %[r4], 4(%[window]) \n\t"
+ "lh %[r5], 4(%[real]) \n\t"
+ "lh %[r6], 6(%[window]) \n\t"
+ "lh %[r7], 6(%[real]) \n\t"
+ "mul %[r0], %[r0], %[r1] \n\t"
+ "mul %[r2], %[r2], %[r3] \n\t"
+ "mul %[r4], %[r4], %[r5] \n\t"
+ "mul %[r6], %[r6], %[r7] \n\t"
+ "addiu %[r0], %[r0], 0x2000 \n\t"
+ "addiu %[r2], %[r2], 0x2000 \n\t"
+ "addiu %[r4], %[r4], 0x2000 \n\t"
+ "addiu %[r6], %[r6], 0x2000 \n\t"
+ "sra %[r0], %[r0], 14 \n\t"
+ "sra %[r2], %[r2], 14 \n\t"
+ "sra %[r4], %[r4], 14 \n\t"
+ "sra %[r6], %[r6], 14 \n\t"
+ "mul %[r0], %[r0], %[gain_factor] \n\t"
+ "mul %[r2], %[r2], %[gain_factor] \n\t"
+ "mul %[r4], %[r4], %[gain_factor] \n\t"
+ "mul %[r6], %[r6], %[gain_factor] \n\t"
+ "addiu %[r0], %[r0], 0x1000 \n\t"
+ "addiu %[r2], %[r2], 0x1000 \n\t"
+ "addiu %[r4], %[r4], 0x1000 \n\t"
+ "addiu %[r6], %[r6], 0x1000 \n\t"
+ "sra %[r0], %[r0], 13 \n\t"
+ "sra %[r2], %[r2], 13 \n\t"
+ "sra %[r4], %[r4], 13 \n\t"
+ "sra %[r6], %[r6], 13 \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "slt %[r3], %[r2], %[sat_pos] \n\t"
+ "slt %[r5], %[r4], %[sat_pos] \n\t"
+ "slt %[r7], %[r6], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "movz %[r2], %[sat_pos], %[r3] \n\t"
+ "movz %[r4], %[sat_pos], %[r5] \n\t"
+ "movz %[r6], %[sat_pos], %[r7] \n\t"
+ "lh %[r1], 0(%[synthBuf]) \n\t"
+ "lh %[r3], 2(%[synthBuf]) \n\t"
+ "lh %[r5], 4(%[synthBuf]) \n\t"
+ "lh %[r7], 6(%[synthBuf]) \n\t"
+ "addu %[r0], %[r0], %[r1] \n\t"
+ "addu %[r2], %[r2], %[r3] \n\t"
+ "addu %[r4], %[r4], %[r5] \n\t"
+ "addu %[r6], %[r6], %[r7] \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "slt %[r3], %[r2], %[sat_pos] \n\t"
+ "slt %[r5], %[r4], %[sat_pos] \n\t"
+ "slt %[r7], %[r6], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "movz %[r2], %[sat_pos], %[r3] \n\t"
+ "movz %[r4], %[sat_pos], %[r5] \n\t"
+ "movz %[r6], %[sat_pos], %[r7] \n\t"
+ "slt %[r1], %[r0], %[sat_neg] \n\t"
+ "slt %[r3], %[r2], %[sat_neg] \n\t"
+ "slt %[r5], %[r4], %[sat_neg] \n\t"
+ "slt %[r7], %[r6], %[sat_neg] \n\t"
+ "movn %[r0], %[sat_neg], %[r1] \n\t"
+ "movn %[r2], %[sat_neg], %[r3] \n\t"
+ "movn %[r4], %[sat_neg], %[r5] \n\t"
+ "movn %[r6], %[sat_neg], %[r7] \n\t"
+ "sh %[r0], 0(%[synthBuf]) \n\t"
+ "sh %[r2], 2(%[synthBuf]) \n\t"
+ "sh %[r4], 4(%[synthBuf]) \n\t"
+ "sh %[r6], 6(%[synthBuf]) \n\t"
+ "sh %[r0], 0(%[out]) \n\t"
+ "sh %[r2], 2(%[out]) \n\t"
+ "sh %[r4], 4(%[out]) \n\t"
+ "sh %[r6], 6(%[out]) \n\t"
+ "addiu %[window], %[window], 8 \n\t"
+ "addiu %[real], %[real], 8 \n\t"
+ "addiu %[synthBuf],%[synthBuf], 8 \n\t"
+ "addiu %[out], %[out], 8 \n\t"
+ "b 1b \n\t"
+ " addiu %[iters], %[iters], -1 \n\t"
+ "2: \n\t"
+ "blez %[after], 3f \n\t"
+ " subu %[block10], %[anaLen], %[block10] \n\t"
+ "lh %[r0], 0(%[window]) \n\t"
+ "lh %[r1], 0(%[real]) \n\t"
+ "mul %[r0], %[r0], %[r1] \n\t"
+ "addiu %[window], %[window], 2 \n\t"
+ "addiu %[real], %[real], 2 \n\t"
+ "addiu %[r0], %[r0], 0x2000 \n\t"
+ "sra %[r0], %[r0], 14 \n\t"
+ "mul %[r0], %[r0], %[gain_factor] \n\t"
+ "addiu %[r0], %[r0], 0x1000 \n\t"
+ "sra %[r0], %[r0], 13 \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "lh %[r1], 0(%[synthBuf]) \n\t"
+ "addu %[r0], %[r0], %[r1] \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "slt %[r1], %[r0], %[sat_neg] \n\t"
+ "movn %[r0], %[sat_neg], %[r1] \n\t"
+ "sh %[r0], 0(%[synthBuf]) \n\t"
+ "sh %[r0], 0(%[out]) \n\t"
+ "addiu %[synthBuf],%[synthBuf], 2 \n\t"
+ "addiu %[out], %[out], 2 \n\t"
+ "b 2b \n\t"
+ " addiu %[after], %[after], -1 \n\t"
+ "3: \n\t"
+ "sra %[iters], %[block10], 2 \n\t"
+ "4: \n\t"
+ "blez %[iters], 5f \n\t"
+ " andi %[after], %[block10], 3 \n\t"
+ "lh %[r0], 0(%[window]) \n\t"
+ "lh %[r1], 0(%[real]) \n\t"
+ "lh %[r2], 2(%[window]) \n\t"
+ "lh %[r3], 2(%[real]) \n\t"
+ "lh %[r4], 4(%[window]) \n\t"
+ "lh %[r5], 4(%[real]) \n\t"
+ "lh %[r6], 6(%[window]) \n\t"
+ "lh %[r7], 6(%[real]) \n\t"
+ "mul %[r0], %[r0], %[r1] \n\t"
+ "mul %[r2], %[r2], %[r3] \n\t"
+ "mul %[r4], %[r4], %[r5] \n\t"
+ "mul %[r6], %[r6], %[r7] \n\t"
+ "addiu %[r0], %[r0], 0x2000 \n\t"
+ "addiu %[r2], %[r2], 0x2000 \n\t"
+ "addiu %[r4], %[r4], 0x2000 \n\t"
+ "addiu %[r6], %[r6], 0x2000 \n\t"
+ "sra %[r0], %[r0], 14 \n\t"
+ "sra %[r2], %[r2], 14 \n\t"
+ "sra %[r4], %[r4], 14 \n\t"
+ "sra %[r6], %[r6], 14 \n\t"
+ "mul %[r0], %[r0], %[gain_factor] \n\t"
+ "mul %[r2], %[r2], %[gain_factor] \n\t"
+ "mul %[r4], %[r4], %[gain_factor] \n\t"
+ "mul %[r6], %[r6], %[gain_factor] \n\t"
+ "addiu %[r0], %[r0], 0x1000 \n\t"
+ "addiu %[r2], %[r2], 0x1000 \n\t"
+ "addiu %[r4], %[r4], 0x1000 \n\t"
+ "addiu %[r6], %[r6], 0x1000 \n\t"
+ "sra %[r0], %[r0], 13 \n\t"
+ "sra %[r2], %[r2], 13 \n\t"
+ "sra %[r4], %[r4], 13 \n\t"
+ "sra %[r6], %[r6], 13 \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "slt %[r3], %[r2], %[sat_pos] \n\t"
+ "slt %[r5], %[r4], %[sat_pos] \n\t"
+ "slt %[r7], %[r6], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "movz %[r2], %[sat_pos], %[r3] \n\t"
+ "movz %[r4], %[sat_pos], %[r5] \n\t"
+ "movz %[r6], %[sat_pos], %[r7] \n\t"
+ "lh %[r1], 0(%[synthBuf]) \n\t"
+ "lh %[r3], 2(%[synthBuf]) \n\t"
+ "lh %[r5], 4(%[synthBuf]) \n\t"
+ "lh %[r7], 6(%[synthBuf]) \n\t"
+ "addu %[r0], %[r0], %[r1] \n\t"
+ "addu %[r2], %[r2], %[r3] \n\t"
+ "addu %[r4], %[r4], %[r5] \n\t"
+ "addu %[r6], %[r6], %[r7] \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "slt %[r3], %[r2], %[sat_pos] \n\t"
+ "slt %[r5], %[r4], %[sat_pos] \n\t"
+ "slt %[r7], %[r6], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "movz %[r2], %[sat_pos], %[r3] \n\t"
+ "movz %[r4], %[sat_pos], %[r5] \n\t"
+ "movz %[r6], %[sat_pos], %[r7] \n\t"
+ "slt %[r1], %[r0], %[sat_neg] \n\t"
+ "slt %[r3], %[r2], %[sat_neg] \n\t"
+ "slt %[r5], %[r4], %[sat_neg] \n\t"
+ "slt %[r7], %[r6], %[sat_neg] \n\t"
+ "movn %[r0], %[sat_neg], %[r1] \n\t"
+ "movn %[r2], %[sat_neg], %[r3] \n\t"
+ "movn %[r4], %[sat_neg], %[r5] \n\t"
+ "movn %[r6], %[sat_neg], %[r7] \n\t"
+ "sh %[r0], 0(%[synthBuf]) \n\t"
+ "sh %[r2], 2(%[synthBuf]) \n\t"
+ "sh %[r4], 4(%[synthBuf]) \n\t"
+ "sh %[r6], 6(%[synthBuf]) \n\t"
+ "addiu %[window], %[window], 8 \n\t"
+ "addiu %[real], %[real], 8 \n\t"
+ "addiu %[synthBuf],%[synthBuf], 8 \n\t"
+ "b 4b \n\t"
+ " addiu %[iters], %[iters], -1 \n\t"
+ "5: \n\t"
+ "blez %[after], 6f \n\t"
+ " nop \n\t"
+ "lh %[r0], 0(%[window]) \n\t"
+ "lh %[r1], 0(%[real]) \n\t"
+ "mul %[r0], %[r0], %[r1] \n\t"
+ "addiu %[window], %[window], 2 \n\t"
+ "addiu %[real], %[real], 2 \n\t"
+ "addiu %[r0], %[r0], 0x2000 \n\t"
+ "sra %[r0], %[r0], 14 \n\t"
+ "mul %[r0], %[r0], %[gain_factor] \n\t"
+ "addiu %[r0], %[r0], 0x1000 \n\t"
+ "sra %[r0], %[r0], 13 \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "lh %[r1], 0(%[synthBuf]) \n\t"
+ "addu %[r0], %[r0], %[r1] \n\t"
+ "slt %[r1], %[r0], %[sat_pos] \n\t"
+ "movz %[r0], %[sat_pos], %[r1] \n\t"
+ "slt %[r1], %[r0], %[sat_neg] \n\t"
+ "movn %[r0], %[sat_neg], %[r1] \n\t"
+ "sh %[r0], 0(%[synthBuf]) \n\t"
+ "addiu %[synthBuf],%[synthBuf], 2 \n\t"
+ "b 2b \n\t"
+ " addiu %[after], %[after], -1 \n\t"
+ "6: \n\t"
+ ".set pop \n\t"
+ : [r0] "=&r" (r0), [r1] "=&r" (r1), [r2] "=&r" (r2),
+ [r3] "=&r" (r3), [r4] "=&r" (r4), [r5] "=&r" (r5),
+ [r6] "=&r" (r6), [r7] "=&r" (r7), [iters] "+r" (iters),
+ [after] "+r" (after), [block10] "+r" (block10),
+ [window] "+r" (window), [real] "+r" (real),
+ [synthBuf] "+r" (synthBuf), [out] "+r" (out)
+ : [gain_factor] "r" (gain_factor), [sat_pos] "r" (sat_pos),
+ [sat_neg] "r" (sat_neg), [anaLen] "r" (anaLen)
+ : "memory", "hi", "lo"
+ );
+
+ // 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);
+}
+
+// Filter the data in the frequency domain, and create spectrum.
+void WebRtcNsx_PrepareSpectrum_mips(NoiseSuppressionFixedC* inst,
+ int16_t* freq_buf) {
+ uint16_t *noiseSupFilter = inst->noiseSupFilter;
+ int16_t *real = inst->real;
+ int16_t *imag = inst->imag;
+ int32_t loop_count = 2;
+ int16_t tmp_1, tmp_2, tmp_3, tmp_4, tmp_5, tmp_6;
+ int16_t tmp16 = (int16_t)(inst->anaLen << 1) - 4;
+ int16_t* freq_buf_f = freq_buf;
+ int16_t* freq_buf_s = &freq_buf[tmp16];
+
+ __asm __volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ //first sample
+ "lh %[tmp_1], 0(%[noiseSupFilter]) \n\t"
+ "lh %[tmp_2], 0(%[real]) \n\t"
+ "lh %[tmp_3], 0(%[imag]) \n\t"
+ "mul %[tmp_2], %[tmp_2], %[tmp_1] \n\t"
+ "mul %[tmp_3], %[tmp_3], %[tmp_1] \n\t"
+ "sra %[tmp_2], %[tmp_2], 14 \n\t"
+ "sra %[tmp_3], %[tmp_3], 14 \n\t"
+ "sh %[tmp_2], 0(%[real]) \n\t"
+ "sh %[tmp_3], 0(%[imag]) \n\t"
+ "negu %[tmp_3], %[tmp_3] \n\t"
+ "sh %[tmp_2], 0(%[freq_buf_f]) \n\t"
+ "sh %[tmp_3], 2(%[freq_buf_f]) \n\t"
+ "addiu %[real], %[real], 2 \n\t"
+ "addiu %[imag], %[imag], 2 \n\t"
+ "addiu %[noiseSupFilter], %[noiseSupFilter], 2 \n\t"
+ "addiu %[freq_buf_f], %[freq_buf_f], 4 \n\t"
+ "1: \n\t"
+ "lh %[tmp_1], 0(%[noiseSupFilter]) \n\t"
+ "lh %[tmp_2], 0(%[real]) \n\t"
+ "lh %[tmp_3], 0(%[imag]) \n\t"
+ "lh %[tmp_4], 2(%[noiseSupFilter]) \n\t"
+ "lh %[tmp_5], 2(%[real]) \n\t"
+ "lh %[tmp_6], 2(%[imag]) \n\t"
+ "mul %[tmp_2], %[tmp_2], %[tmp_1] \n\t"
+ "mul %[tmp_3], %[tmp_3], %[tmp_1] \n\t"
+ "mul %[tmp_5], %[tmp_5], %[tmp_4] \n\t"
+ "mul %[tmp_6], %[tmp_6], %[tmp_4] \n\t"
+ "addiu %[loop_count], %[loop_count], 2 \n\t"
+ "sra %[tmp_2], %[tmp_2], 14 \n\t"
+ "sra %[tmp_3], %[tmp_3], 14 \n\t"
+ "sra %[tmp_5], %[tmp_5], 14 \n\t"
+ "sra %[tmp_6], %[tmp_6], 14 \n\t"
+ "addiu %[noiseSupFilter], %[noiseSupFilter], 4 \n\t"
+ "sh %[tmp_2], 0(%[real]) \n\t"
+ "sh %[tmp_2], 4(%[freq_buf_s]) \n\t"
+ "sh %[tmp_3], 0(%[imag]) \n\t"
+ "sh %[tmp_3], 6(%[freq_buf_s]) \n\t"
+ "negu %[tmp_3], %[tmp_3] \n\t"
+ "sh %[tmp_5], 2(%[real]) \n\t"
+ "sh %[tmp_5], 0(%[freq_buf_s]) \n\t"
+ "sh %[tmp_6], 2(%[imag]) \n\t"
+ "sh %[tmp_6], 2(%[freq_buf_s]) \n\t"
+ "negu %[tmp_6], %[tmp_6] \n\t"
+ "addiu %[freq_buf_s], %[freq_buf_s], -8 \n\t"
+ "addiu %[real], %[real], 4 \n\t"
+ "addiu %[imag], %[imag], 4 \n\t"
+ "sh %[tmp_2], 0(%[freq_buf_f]) \n\t"
+ "sh %[tmp_3], 2(%[freq_buf_f]) \n\t"
+ "sh %[tmp_5], 4(%[freq_buf_f]) \n\t"
+ "sh %[tmp_6], 6(%[freq_buf_f]) \n\t"
+ "blt %[loop_count], %[loop_size], 1b \n\t"
+ " addiu %[freq_buf_f], %[freq_buf_f], 8 \n\t"
+ //last two samples:
+ "lh %[tmp_1], 0(%[noiseSupFilter]) \n\t"
+ "lh %[tmp_2], 0(%[real]) \n\t"
+ "lh %[tmp_3], 0(%[imag]) \n\t"
+ "lh %[tmp_4], 2(%[noiseSupFilter]) \n\t"
+ "lh %[tmp_5], 2(%[real]) \n\t"
+ "lh %[tmp_6], 2(%[imag]) \n\t"
+ "mul %[tmp_2], %[tmp_2], %[tmp_1] \n\t"
+ "mul %[tmp_3], %[tmp_3], %[tmp_1] \n\t"
+ "mul %[tmp_5], %[tmp_5], %[tmp_4] \n\t"
+ "mul %[tmp_6], %[tmp_6], %[tmp_4] \n\t"
+ "sra %[tmp_2], %[tmp_2], 14 \n\t"
+ "sra %[tmp_3], %[tmp_3], 14 \n\t"
+ "sra %[tmp_5], %[tmp_5], 14 \n\t"
+ "sra %[tmp_6], %[tmp_6], 14 \n\t"
+ "sh %[tmp_2], 0(%[real]) \n\t"
+ "sh %[tmp_2], 4(%[freq_buf_s]) \n\t"
+ "sh %[tmp_3], 0(%[imag]) \n\t"
+ "sh %[tmp_3], 6(%[freq_buf_s]) \n\t"
+ "negu %[tmp_3], %[tmp_3] \n\t"
+ "sh %[tmp_2], 0(%[freq_buf_f]) \n\t"
+ "sh %[tmp_3], 2(%[freq_buf_f]) \n\t"
+ "sh %[tmp_5], 4(%[freq_buf_f]) \n\t"
+ "sh %[tmp_6], 6(%[freq_buf_f]) \n\t"
+ "sh %[tmp_5], 2(%[real]) \n\t"
+ "sh %[tmp_6], 2(%[imag]) \n\t"
+ ".set pop \n\t"
+ : [real] "+r" (real), [imag] "+r" (imag),
+ [freq_buf_f] "+r" (freq_buf_f), [freq_buf_s] "+r" (freq_buf_s),
+ [loop_count] "+r" (loop_count), [noiseSupFilter] "+r" (noiseSupFilter),
+ [tmp_1] "=&r" (tmp_1), [tmp_2] "=&r" (tmp_2), [tmp_3] "=&r" (tmp_3),
+ [tmp_4] "=&r" (tmp_4), [tmp_5] "=&r" (tmp_5), [tmp_6] "=&r" (tmp_6)
+ : [loop_size] "r" (inst->anaLen2)
+ : "memory", "hi", "lo"
+ );
+}
+
+#if defined(MIPS_DSP_R1_LE)
+// Denormalize the real-valued signal |in|, the output from inverse FFT.
+void WebRtcNsx_Denormalize_mips(NoiseSuppressionFixedC* inst,
+ int16_t* in,
+ int factor) {
+ int32_t r0, r1, r2, r3, t0;
+ int len = (int)inst->anaLen;
+ int16_t *out = &inst->real[0];
+ int shift = factor - inst->normData;
+
+ __asm __volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beqz %[len], 8f \n\t"
+ " nop \n\t"
+ "bltz %[shift], 4f \n\t"
+ " sra %[t0], %[len], 2 \n\t"
+ "beqz %[t0], 2f \n\t"
+ " andi %[len], %[len], 3 \n\t"
+ "1: \n\t"
+ "lh %[r0], 0(%[in]) \n\t"
+ "lh %[r1], 2(%[in]) \n\t"
+ "lh %[r2], 4(%[in]) \n\t"
+ "lh %[r3], 6(%[in]) \n\t"
+ "shllv_s.ph %[r0], %[r0], %[shift] \n\t"
+ "shllv_s.ph %[r1], %[r1], %[shift] \n\t"
+ "shllv_s.ph %[r2], %[r2], %[shift] \n\t"
+ "shllv_s.ph %[r3], %[r3], %[shift] \n\t"
+ "addiu %[in], %[in], 8 \n\t"
+ "addiu %[t0], %[t0], -1 \n\t"
+ "sh %[r0], 0(%[out]) \n\t"
+ "sh %[r1], 2(%[out]) \n\t"
+ "sh %[r2], 4(%[out]) \n\t"
+ "sh %[r3], 6(%[out]) \n\t"
+ "bgtz %[t0], 1b \n\t"
+ " addiu %[out], %[out], 8 \n\t"
+ "2: \n\t"
+ "beqz %[len], 8f \n\t"
+ " nop \n\t"
+ "3: \n\t"
+ "lh %[r0], 0(%[in]) \n\t"
+ "addiu %[in], %[in], 2 \n\t"
+ "addiu %[len], %[len], -1 \n\t"
+ "shllv_s.ph %[r0], %[r0], %[shift] \n\t"
+ "addiu %[out], %[out], 2 \n\t"
+ "bgtz %[len], 3b \n\t"
+ " sh %[r0], -2(%[out]) \n\t"
+ "b 8f \n\t"
+ "4: \n\t"
+ "negu %[shift], %[shift] \n\t"
+ "beqz %[t0], 6f \n\t"
+ " andi %[len], %[len], 3 \n\t"
+ "5: \n\t"
+ "lh %[r0], 0(%[in]) \n\t"
+ "lh %[r1], 2(%[in]) \n\t"
+ "lh %[r2], 4(%[in]) \n\t"
+ "lh %[r3], 6(%[in]) \n\t"
+ "srav %[r0], %[r0], %[shift] \n\t"
+ "srav %[r1], %[r1], %[shift] \n\t"
+ "srav %[r2], %[r2], %[shift] \n\t"
+ "srav %[r3], %[r3], %[shift] \n\t"
+ "addiu %[in], %[in], 8 \n\t"
+ "addiu %[t0], %[t0], -1 \n\t"
+ "sh %[r0], 0(%[out]) \n\t"
+ "sh %[r1], 2(%[out]) \n\t"
+ "sh %[r2], 4(%[out]) \n\t"
+ "sh %[r3], 6(%[out]) \n\t"
+ "bgtz %[t0], 5b \n\t"
+ " addiu %[out], %[out], 8 \n\t"
+ "6: \n\t"
+ "beqz %[len], 8f \n\t"
+ " nop \n\t"
+ "7: \n\t"
+ "lh %[r0], 0(%[in]) \n\t"
+ "addiu %[in], %[in], 2 \n\t"
+ "addiu %[len], %[len], -1 \n\t"
+ "srav %[r0], %[r0], %[shift] \n\t"
+ "addiu %[out], %[out], 2 \n\t"
+ "bgtz %[len], 7b \n\t"
+ " sh %[r0], -2(%[out]) \n\t"
+ "8: \n\t"
+ ".set pop \n\t"
+ : [t0] "=&r" (t0), [r0] "=&r" (r0), [r1] "=&r" (r1),
+ [r2] "=&r" (r2), [r3] "=&r" (r3)
+ : [len] "r" (len), [shift] "r" (shift), [in] "r" (in),
+ [out] "r" (out)
+ : "memory"
+ );
+}
+#endif
+
+// Normalize the real-valued signal |in|, the input to forward FFT.
+void WebRtcNsx_NormalizeRealBuffer_mips(NoiseSuppressionFixedC* inst,
+ const int16_t* in,
+ int16_t* out) {
+ int32_t r0, r1, r2, r3, t0;
+ int len = (int)inst->anaLen;
+ int shift = inst->normData;
+
+ __asm __volatile (
+ ".set push \n\t"
+ ".set noreorder \n\t"
+ "beqz %[len], 4f \n\t"
+ " sra %[t0], %[len], 2 \n\t"
+ "beqz %[t0], 2f \n\t"
+ " andi %[len], %[len], 3 \n\t"
+ "1: \n\t"
+ "lh %[r0], 0(%[in]) \n\t"
+ "lh %[r1], 2(%[in]) \n\t"
+ "lh %[r2], 4(%[in]) \n\t"
+ "lh %[r3], 6(%[in]) \n\t"
+ "sllv %[r0], %[r0], %[shift] \n\t"
+ "sllv %[r1], %[r1], %[shift] \n\t"
+ "sllv %[r2], %[r2], %[shift] \n\t"
+ "sllv %[r3], %[r3], %[shift] \n\t"
+ "addiu %[in], %[in], 8 \n\t"
+ "addiu %[t0], %[t0], -1 \n\t"
+ "sh %[r0], 0(%[out]) \n\t"
+ "sh %[r1], 2(%[out]) \n\t"
+ "sh %[r2], 4(%[out]) \n\t"
+ "sh %[r3], 6(%[out]) \n\t"
+ "bgtz %[t0], 1b \n\t"
+ " addiu %[out], %[out], 8 \n\t"
+ "2: \n\t"
+ "beqz %[len], 4f \n\t"
+ " nop \n\t"
+ "3: \n\t"
+ "lh %[r0], 0(%[in]) \n\t"
+ "addiu %[in], %[in], 2 \n\t"
+ "addiu %[len], %[len], -1 \n\t"
+ "sllv %[r0], %[r0], %[shift] \n\t"
+ "addiu %[out], %[out], 2 \n\t"
+ "bgtz %[len], 3b \n\t"
+ " sh %[r0], -2(%[out]) \n\t"
+ "4: \n\t"
+ ".set pop \n\t"
+ : [t0] "=&r" (t0), [r0] "=&r" (r0), [r1] "=&r" (r1),
+ [r2] "=&r" (r2), [r3] "=&r" (r3)
+ : [len] "r" (len), [shift] "r" (shift), [in] "r" (in),
+ [out] "r" (out)
+ : "memory"
+ );
+}
diff --git a/modules/audio_processing/legacy_ns/nsx_core_neon.c b/modules/audio_processing/legacy_ns/nsx_core_neon.c
new file mode 100644
index 0000000..244111c
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/nsx_core_neon.c
@@ -0,0 +1,606 @@
+/*
+ * 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/nsx_core.h"
+
+#include <arm_neon.h>
+
+#include "rtc_base/checks.h"
+
+// Constants to compensate for shifting signal log(2^shifts).
+const int16_t WebRtcNsx_kLogTable[9] = {
+ 0, 177, 355, 532, 710, 887, 1065, 1242, 1420
+};
+
+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
+};
+
+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
+};
+
+// Update the noise estimation information.
+static void UpdateNoiseEstimateNeon(NoiseSuppressionFixedC* inst, int offset) {
+ const int16_t kExp2Const = 11819; // Q13
+ int16_t* ptr_noiseEstLogQuantile = NULL;
+ int16_t* ptr_noiseEstQuantile = NULL;
+ int16x4_t kExp2Const16x4 = vdup_n_s16(kExp2Const);
+ int32x4_t twentyOne32x4 = vdupq_n_s32(21);
+ int32x4_t constA32x4 = vdupq_n_s32(0x1fffff);
+ int32x4_t constB32x4 = vdupq_n_s32(0x200000);
+
+ int16_t 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);
+
+ int32x4_t qNoise32x4 = vdupq_n_s32(inst->qNoise);
+
+ for (ptr_noiseEstLogQuantile = &inst->noiseEstLogQuantile[offset],
+ ptr_noiseEstQuantile = &inst->noiseEstQuantile[0];
+ ptr_noiseEstQuantile < &inst->noiseEstQuantile[inst->magnLen - 3];
+ ptr_noiseEstQuantile += 4, ptr_noiseEstLogQuantile += 4) {
+
+ // tmp32no2 = kExp2Const * inst->noiseEstLogQuantile[offset + i];
+ int16x4_t v16x4 = vld1_s16(ptr_noiseEstLogQuantile);
+ int32x4_t v32x4B = vmull_s16(v16x4, kExp2Const16x4);
+
+ // tmp32no1 = (0x00200000 | (tmp32no2 & 0x001FFFFF)); // 2^21 + frac
+ int32x4_t v32x4A = vandq_s32(v32x4B, constA32x4);
+ v32x4A = vorrq_s32(v32x4A, constB32x4);
+
+ // tmp16 = (int16_t)(tmp32no2 >> 21);
+ v32x4B = vshrq_n_s32(v32x4B, 21);
+
+ // tmp16 -= 21;// shift 21 to get result in Q0
+ v32x4B = vsubq_s32(v32x4B, twentyOne32x4);
+
+ // tmp16 += (int16_t) inst->qNoise;
+ // shift to get result in Q(qNoise)
+ v32x4B = vaddq_s32(v32x4B, qNoise32x4);
+
+ // if (tmp16 < 0) {
+ // tmp32no1 >>= -tmp16;
+ // } else {
+ // tmp32no1 <<= tmp16;
+ // }
+ v32x4B = vshlq_s32(v32x4A, v32x4B);
+
+ // tmp16 = WebRtcSpl_SatW32ToW16(tmp32no1);
+ v16x4 = vqmovn_s32(v32x4B);
+
+ //inst->noiseEstQuantile[i] = tmp16;
+ vst1_s16(ptr_noiseEstQuantile, v16x4);
+ }
+
+ // Last iteration:
+
+ // inst->quantile[i]=exp(inst->lquantile[offset+i]);
+ // in Q21
+ int32_t tmp32no2 = kExp2Const * *ptr_noiseEstLogQuantile;
+ int32_t 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;
+ }
+ *ptr_noiseEstQuantile = WebRtcSpl_SatW32ToW16(tmp32no1);
+}
+
+// Noise Estimation
+void WebRtcNsx_NoiseEstimationNeon(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;
+ 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];
+ }
+
+ int16x8_t logval_16x8 = vdupq_n_s16(logval);
+
+ // 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);
+ RTC_DCHECK_LT(frac, 256);
+ // log2(magn(i))
+ 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;
+ }
+ }
+
+ int16x4_t Q3_16x4 = vdup_n_s16(3);
+ int16x8_t WIDTHQ8_16x8 = vdupq_n_s16(WIDTH_Q8);
+ int16x8_t WIDTHFACTOR_16x8 = vdupq_n_s16(width_factor);
+
+ int16_t factor = FACTOR_Q7;
+ if (inst->blockIndex < END_STARTUP_LONG)
+ factor = FACTOR_Q7_STARTUP;
+
+ // 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(...)
+ int16_t deltaBuff[8];
+ int16x4_t tmp16x4_0;
+ int16x4_t tmp16x4_1;
+ int16x4_t countDiv_16x4 = vdup_n_s16(countDiv);
+ int16x8_t countProd_16x8 = vdupq_n_s16(countProd);
+ int16x8_t tmp16x8_0 = vdupq_n_s16(countDiv);
+ int16x8_t prod16x8 = vqrdmulhq_s16(WIDTHFACTOR_16x8, tmp16x8_0);
+ int16x8_t tmp16x8_1;
+ int16x8_t tmp16x8_2;
+ int16x8_t tmp16x8_3;
+ uint16x8_t tmp16x8_4;
+ int32x4_t tmp32x4;
+
+ for (i = 0; i + 7 < inst->magnLen; i += 8) {
+ // Compute delta.
+ // Smaller step size during startup. This prevents from using
+ // unrealistic values causing overflow.
+ tmp16x8_0 = vdupq_n_s16(factor);
+ vst1q_s16(deltaBuff, tmp16x8_0);
+
+ int j;
+ for (j = 0; j < 8; j++) {
+ if (inst->noiseEstDensity[offset + i + j] > 512) {
+ // Get values for deltaBuff by shifting intead of dividing.
+ int factor = WebRtcSpl_NormW16(inst->noiseEstDensity[offset + i + j]);
+ deltaBuff[j] = (int16_t)(FACTOR_Q16 >> (14 - factor));
+ }
+ }
+
+ // Update log quantile estimate
+
+ // tmp16 = (int16_t)((delta * countDiv) >> 14);
+ tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[0]), countDiv_16x4);
+ tmp16x4_1 = vshrn_n_s32(tmp32x4, 14);
+ tmp32x4 = vmull_s16(vld1_s16(&deltaBuff[4]), countDiv_16x4);
+ tmp16x4_0 = vshrn_n_s32(tmp32x4, 14);
+ tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // Keep for several lines.
+
+ // prepare for the "if" branch
+ // tmp16 += 2;
+ // tmp16_1 = (Word16)(tmp16>>2);
+ tmp16x8_1 = vrshrq_n_s16(tmp16x8_0, 2);
+
+ // inst->noiseEstLogQuantile[offset+i] + tmp16_1;
+ tmp16x8_2 = vld1q_s16(&inst->noiseEstLogQuantile[offset + i]); // Keep
+ tmp16x8_1 = vaddq_s16(tmp16x8_2, tmp16x8_1); // Keep for several lines
+
+ // Prepare for the "else" branch
+ // tmp16 += 1;
+ // tmp16_1 = (Word16)(tmp16>>1);
+ tmp16x8_0 = vrshrq_n_s16(tmp16x8_0, 1);
+
+ // tmp16_2 = (int16_t)((tmp16_1 * 3) >> 1);
+ tmp32x4 = vmull_s16(vget_low_s16(tmp16x8_0), Q3_16x4);
+ tmp16x4_1 = vshrn_n_s32(tmp32x4, 1);
+
+ // tmp16_2 = (int16_t)((tmp16_1 * 3) >> 1);
+ tmp32x4 = vmull_s16(vget_high_s16(tmp16x8_0), Q3_16x4);
+ tmp16x4_0 = vshrn_n_s32(tmp32x4, 1);
+
+ // inst->noiseEstLogQuantile[offset + i] - tmp16_2;
+ tmp16x8_0 = vcombine_s16(tmp16x4_1, tmp16x4_0); // keep
+ tmp16x8_0 = vsubq_s16(tmp16x8_2, tmp16x8_0);
+
+ // logval is the smallest fixed point representation we can have. Values
+ // below that will correspond to values in the interval [0, 1], which
+ // can't possibly occur.
+ tmp16x8_0 = vmaxq_s16(tmp16x8_0, logval_16x8);
+
+ // Do the if-else branches:
+ tmp16x8_3 = vld1q_s16(&lmagn[i]); // keep for several lines
+ tmp16x8_4 = vcgtq_s16(tmp16x8_3, tmp16x8_2);
+ tmp16x8_2 = vbslq_s16(tmp16x8_4, tmp16x8_1, tmp16x8_0);
+ vst1q_s16(&inst->noiseEstLogQuantile[offset + i], tmp16x8_2);
+
+ // Update density estimate
+ // tmp16_1 + tmp16_2
+ tmp16x8_1 = vld1q_s16(&inst->noiseEstDensity[offset + i]);
+ tmp16x8_0 = vqrdmulhq_s16(tmp16x8_1, countProd_16x8);
+ tmp16x8_0 = vaddq_s16(tmp16x8_0, prod16x8);
+
+ // lmagn[i] - inst->noiseEstLogQuantile[offset + i]
+ tmp16x8_3 = vsubq_s16(tmp16x8_3, tmp16x8_2);
+ tmp16x8_3 = vabsq_s16(tmp16x8_3);
+ tmp16x8_4 = vcgtq_s16(WIDTHQ8_16x8, tmp16x8_3);
+ tmp16x8_1 = vbslq_s16(tmp16x8_4, tmp16x8_0, tmp16x8_1);
+ vst1q_s16(&inst->noiseEstDensity[offset + i], tmp16x8_1);
+ } // End loop over magnitude spectrum
+
+ // Last iteration over magnitude spectrum:
+ // compute delta
+ if (inst->noiseEstDensity[offset + i] > 512) {
+ // Get values for deltaBuff 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) {
+ // logval is the smallest fixed point representation we can have.
+ // Values below that will correspond to values in the interval
+ // [0, 1], which can't possibly occur.
+ 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;
+ }
+
+
+ if (counter >= END_STARTUP_LONG) {
+ inst->noiseEstCounter[s] = 0;
+ if (inst->blockIndex >= END_STARTUP_LONG) {
+ UpdateNoiseEstimateNeon(inst, offset);
+ }
+ }
+ inst->noiseEstCounter[s]++;
+
+ } // end loop over simultaneous estimates
+
+ // Sequentially update the noise during startup
+ if (inst->blockIndex < END_STARTUP_LONG) {
+ UpdateNoiseEstimateNeon(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.
+void WebRtcNsx_PrepareSpectrumNeon(NoiseSuppressionFixedC* inst,
+ int16_t* freq_buf) {
+ RTC_DCHECK_EQ(1, inst->magnLen % 8);
+ RTC_DCHECK_EQ(0, inst->anaLen2 % 16);
+
+ // (1) Filtering.
+
+ // Fixed point C code for the next block is as follows:
+ // 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)
+ // }
+
+ int16_t* preal = &inst->real[0];
+ int16_t* pimag = &inst->imag[0];
+ int16_t* pns_filter = (int16_t*)&inst->noiseSupFilter[0];
+ int16_t* pimag_end = pimag + inst->magnLen - 4;
+
+ while (pimag < pimag_end) {
+ int16x8_t real = vld1q_s16(preal);
+ int16x8_t imag = vld1q_s16(pimag);
+ int16x8_t ns_filter = vld1q_s16(pns_filter);
+
+ int32x4_t tmp_r_0 = vmull_s16(vget_low_s16(real), vget_low_s16(ns_filter));
+ int32x4_t tmp_i_0 = vmull_s16(vget_low_s16(imag), vget_low_s16(ns_filter));
+ int32x4_t tmp_r_1 = vmull_s16(vget_high_s16(real),
+ vget_high_s16(ns_filter));
+ int32x4_t tmp_i_1 = vmull_s16(vget_high_s16(imag),
+ vget_high_s16(ns_filter));
+
+ int16x4_t result_r_0 = vshrn_n_s32(tmp_r_0, 14);
+ int16x4_t result_i_0 = vshrn_n_s32(tmp_i_0, 14);
+ int16x4_t result_r_1 = vshrn_n_s32(tmp_r_1, 14);
+ int16x4_t result_i_1 = vshrn_n_s32(tmp_i_1, 14);
+
+ vst1q_s16(preal, vcombine_s16(result_r_0, result_r_1));
+ vst1q_s16(pimag, vcombine_s16(result_i_0, result_i_1));
+ preal += 8;
+ pimag += 8;
+ pns_filter += 8;
+ }
+
+ // Filter the last element
+ *preal = (int16_t)((*preal * *pns_filter) >> 14);
+ *pimag = (int16_t)((*pimag * *pns_filter) >> 14);
+
+ // (2) Create spectrum.
+
+ // Fixed point C code for the rest of the function is as follows:
+ // 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];
+
+ preal = &inst->real[0];
+ pimag = &inst->imag[0];
+ pimag_end = pimag + inst->anaLen2;
+ int16_t * freq_buf_start = freq_buf;
+ while (pimag < pimag_end) {
+ // loop unroll
+ int16x8x2_t real_imag_0;
+ int16x8x2_t real_imag_1;
+ real_imag_0.val[1] = vld1q_s16(pimag);
+ real_imag_0.val[0] = vld1q_s16(preal);
+ preal += 8;
+ pimag += 8;
+ real_imag_1.val[1] = vld1q_s16(pimag);
+ real_imag_1.val[0] = vld1q_s16(preal);
+ preal += 8;
+ pimag += 8;
+
+ real_imag_0.val[1] = vnegq_s16(real_imag_0.val[1]);
+ real_imag_1.val[1] = vnegq_s16(real_imag_1.val[1]);
+ vst2q_s16(freq_buf_start, real_imag_0);
+ freq_buf_start += 16;
+ vst2q_s16(freq_buf_start, real_imag_1);
+ freq_buf_start += 16;
+ }
+ freq_buf[inst->anaLen] = inst->real[inst->anaLen2];
+ freq_buf[inst->anaLen + 1] = -inst->imag[inst->anaLen2];
+}
+
+// For the noise supress process, synthesis, read out fully processed segment,
+// and update synthesis buffer.
+void WebRtcNsx_SynthesisUpdateNeon(NoiseSuppressionFixedC* inst,
+ int16_t* out_frame,
+ int16_t gain_factor) {
+ RTC_DCHECK_EQ(0, inst->anaLen % 16);
+ RTC_DCHECK_EQ(0, inst->blockLen10ms % 16);
+
+ int16_t* preal_start = inst->real;
+ const int16_t* pwindow = inst->window;
+ int16_t* preal_end = preal_start + inst->anaLen;
+ int16_t* psynthesis_buffer = inst->synthesisBuffer;
+
+ while (preal_start < preal_end) {
+ // Loop unroll.
+ int16x8_t window_0 = vld1q_s16(pwindow);
+ int16x8_t real_0 = vld1q_s16(preal_start);
+ int16x8_t synthesis_buffer_0 = vld1q_s16(psynthesis_buffer);
+
+ int16x8_t window_1 = vld1q_s16(pwindow + 8);
+ int16x8_t real_1 = vld1q_s16(preal_start + 8);
+ int16x8_t synthesis_buffer_1 = vld1q_s16(psynthesis_buffer + 8);
+
+ int32x4_t tmp32a_0_low = vmull_s16(vget_low_s16(real_0),
+ vget_low_s16(window_0));
+ int32x4_t tmp32a_0_high = vmull_s16(vget_high_s16(real_0),
+ vget_high_s16(window_0));
+
+ int32x4_t tmp32a_1_low = vmull_s16(vget_low_s16(real_1),
+ vget_low_s16(window_1));
+ int32x4_t tmp32a_1_high = vmull_s16(vget_high_s16(real_1),
+ vget_high_s16(window_1));
+
+ int16x4_t tmp16a_0_low = vqrshrn_n_s32(tmp32a_0_low, 14);
+ int16x4_t tmp16a_0_high = vqrshrn_n_s32(tmp32a_0_high, 14);
+
+ int16x4_t tmp16a_1_low = vqrshrn_n_s32(tmp32a_1_low, 14);
+ int16x4_t tmp16a_1_high = vqrshrn_n_s32(tmp32a_1_high, 14);
+
+ int32x4_t tmp32b_0_low = vmull_n_s16(tmp16a_0_low, gain_factor);
+ int32x4_t tmp32b_0_high = vmull_n_s16(tmp16a_0_high, gain_factor);
+
+ int32x4_t tmp32b_1_low = vmull_n_s16(tmp16a_1_low, gain_factor);
+ int32x4_t tmp32b_1_high = vmull_n_s16(tmp16a_1_high, gain_factor);
+
+ int16x4_t tmp16b_0_low = vqrshrn_n_s32(tmp32b_0_low, 13);
+ int16x4_t tmp16b_0_high = vqrshrn_n_s32(tmp32b_0_high, 13);
+
+ int16x4_t tmp16b_1_low = vqrshrn_n_s32(tmp32b_1_low, 13);
+ int16x4_t tmp16b_1_high = vqrshrn_n_s32(tmp32b_1_high, 13);
+
+ synthesis_buffer_0 = vqaddq_s16(vcombine_s16(tmp16b_0_low, tmp16b_0_high),
+ synthesis_buffer_0);
+ synthesis_buffer_1 = vqaddq_s16(vcombine_s16(tmp16b_1_low, tmp16b_1_high),
+ synthesis_buffer_1);
+ vst1q_s16(psynthesis_buffer, synthesis_buffer_0);
+ vst1q_s16(psynthesis_buffer + 8, synthesis_buffer_1);
+
+ pwindow += 16;
+ preal_start += 16;
+ psynthesis_buffer += 16;
+ }
+
+ // Read out fully processed segment.
+ int16_t * p_start = inst->synthesisBuffer;
+ int16_t * p_end = inst->synthesisBuffer + inst->blockLen10ms;
+ int16_t * p_frame = out_frame;
+ while (p_start < p_end) {
+ int16x8_t frame_0 = vld1q_s16(p_start);
+ vst1q_s16(p_frame, frame_0);
+ p_start += 8;
+ p_frame += 8;
+ }
+
+ // Update synthesis buffer.
+ int16_t* p_start_src = inst->synthesisBuffer + inst->blockLen10ms;
+ int16_t* p_end_src = inst->synthesisBuffer + inst->anaLen;
+ int16_t* p_start_dst = inst->synthesisBuffer;
+ while (p_start_src < p_end_src) {
+ int16x8_t frame = vld1q_s16(p_start_src);
+ vst1q_s16(p_start_dst, frame);
+ p_start_src += 8;
+ p_start_dst += 8;
+ }
+
+ p_start = inst->synthesisBuffer + inst->anaLen - inst->blockLen10ms;
+ p_end = p_start + inst->blockLen10ms;
+ int16x8_t zero = vdupq_n_s16(0);
+ for (;p_start < p_end; p_start += 8) {
+ vst1q_s16(p_start, zero);
+ }
+}
+
+// Update analysis buffer for lower band, and window data before FFT.
+void WebRtcNsx_AnalysisUpdateNeon(NoiseSuppressionFixedC* inst,
+ int16_t* out,
+ int16_t* new_speech) {
+ RTC_DCHECK_EQ(0, inst->blockLen10ms % 16);
+ RTC_DCHECK_EQ(0, inst->anaLen % 16);
+
+ // For lower band update analysis buffer.
+ // memcpy(inst->analysisBuffer, inst->analysisBuffer + inst->blockLen10ms,
+ // (inst->anaLen - inst->blockLen10ms) * sizeof(*inst->analysisBuffer));
+ int16_t* p_start_src = inst->analysisBuffer + inst->blockLen10ms;
+ int16_t* p_end_src = inst->analysisBuffer + inst->anaLen;
+ int16_t* p_start_dst = inst->analysisBuffer;
+ while (p_start_src < p_end_src) {
+ int16x8_t frame = vld1q_s16(p_start_src);
+ vst1q_s16(p_start_dst, frame);
+
+ p_start_src += 8;
+ p_start_dst += 8;
+ }
+
+ // memcpy(inst->analysisBuffer + inst->anaLen - inst->blockLen10ms,
+ // new_speech, inst->blockLen10ms * sizeof(*inst->analysisBuffer));
+ p_start_src = new_speech;
+ p_end_src = new_speech + inst->blockLen10ms;
+ p_start_dst = inst->analysisBuffer + inst->anaLen - inst->blockLen10ms;
+ while (p_start_src < p_end_src) {
+ int16x8_t frame = vld1q_s16(p_start_src);
+ vst1q_s16(p_start_dst, frame);
+
+ p_start_src += 8;
+ p_start_dst += 8;
+ }
+
+ // Window data before FFT.
+ int16_t* p_start_window = (int16_t*) inst->window;
+ int16_t* p_start_buffer = inst->analysisBuffer;
+ int16_t* p_end_buffer = inst->analysisBuffer + inst->anaLen;
+ int16_t* p_start_out = out;
+
+ // Load the first element to reduce pipeline bubble.
+ int16x8_t window = vld1q_s16(p_start_window);
+ int16x8_t buffer = vld1q_s16(p_start_buffer);
+ p_start_window += 8;
+ p_start_buffer += 8;
+
+ while (p_start_buffer < p_end_buffer) {
+ // Unroll loop.
+ int32x4_t tmp32_low = vmull_s16(vget_low_s16(window), vget_low_s16(buffer));
+ int32x4_t tmp32_high = vmull_s16(vget_high_s16(window),
+ vget_high_s16(buffer));
+ window = vld1q_s16(p_start_window);
+ buffer = vld1q_s16(p_start_buffer);
+
+ int16x4_t result_low = vrshrn_n_s32(tmp32_low, 14);
+ int16x4_t result_high = vrshrn_n_s32(tmp32_high, 14);
+ vst1q_s16(p_start_out, vcombine_s16(result_low, result_high));
+
+ p_start_buffer += 8;
+ p_start_window += 8;
+ p_start_out += 8;
+ }
+ int32x4_t tmp32_low = vmull_s16(vget_low_s16(window), vget_low_s16(buffer));
+ int32x4_t tmp32_high = vmull_s16(vget_high_s16(window),
+ vget_high_s16(buffer));
+
+ int16x4_t result_low = vrshrn_n_s32(tmp32_low, 14);
+ int16x4_t result_high = vrshrn_n_s32(tmp32_high, 14);
+ vst1q_s16(p_start_out, vcombine_s16(result_low, result_high));
+}
diff --git a/modules/audio_processing/legacy_ns/nsx_defines.h b/modules/audio_processing/legacy_ns/nsx_defines.h
new file mode 100644
index 0000000..18db311
--- /dev/null
+++ b/modules/audio_processing/legacy_ns/nsx_defines.h
@@ -0,0 +1,74 @@
+/*
+ * 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_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 */
+#define NUM_HIGH_BANDS_MAX 2 /* Max number of high bands */
+#define SIMULT 3
+#define END_STARTUP_LONG 200
+#define END_STARTUP_SHORT 50
+#define FACTOR_Q16 2621440 /* 40 in Q16 */
+#define FACTOR_Q7 5120 /* 40 in Q7 */
+#define FACTOR_Q7_STARTUP 1024 /* 8 in Q7 */
+#define WIDTH_Q8 3 /* 0.01 in Q8 (or 25 ) */
+
+/* PARAMETERS FOR NEW METHOD */
+#define DD_PR_SNR_Q11 2007 /* ~= Q11(0.98) DD update of prior SNR */
+#define ONE_MINUS_DD_PR_SNR_Q11 41 /* DD update of prior SNR */
+#define SPECT_FLAT_TAVG_Q14 \
+ 4915 /* (0.30) tavg parameter for spectral flatness measure */
+#define SPECT_DIFF_TAVG_Q8 \
+ 77 /* (0.30) tavg parameter for spectral flatness measure */
+#define PRIOR_UPDATE_Q14 1638 /* Q14(0.1) Update parameter of prior model */
+#define NOISE_UPDATE_Q8 26 /* 26 ~= Q8(0.1) Update parameter for noise */
+
+/* Probability threshold for noise state in speech/noise likelihood. */
+#define ONE_MINUS_PROB_RANGE_Q8 205 /* 205 ~= Q8(0.8) */
+#define HIST_PAR_EST 1000 /* Histogram size for estimation of parameters */
+
+/* FEATURE EXTRACTION CONFIG */
+/* Bin size of histogram */
+#define BIN_SIZE_LRT 10
+/* Scale parameters: multiply dominant peaks of the histograms by scale factor
+ * to obtain. */
+/* Thresholds for prior model */
+#define FACTOR_1_LRT_DIFF \
+ 6 /* For LRT and spectral difference (5 times bigger) */
+/* For spectral_flatness: used when noise is flatter than speech (10 times
+ * bigger). */
+#define FACTOR_2_FLAT_Q10 922
+/* Peak limit for spectral flatness (varies between 0 and 1) */
+#define THRES_PEAK_FLAT 24 /* * 2 * BIN_SIZE_FLAT_FX */
+/* Limit on spacing of two highest peaks in histogram: spacing determined by bin
+ * size. */
+#define LIM_PEAK_SPACE_FLAT_DIFF 4 /* * 2 * BIN_SIZE_DIFF_FX */
+/* Limit on relevance of second peak */
+#define LIM_PEAK_WEIGHT_FLAT_DIFF 2
+#define THRES_FLUCT_LRT \
+ 10240 /* = 20 * inst->modelUpdate; fluctuation limit of LRT feat. */
+/* Limit on the max and min values for the feature thresholds */
+#define MAX_FLAT_Q10 38912 /* * 2 * BIN_SIZE_FLAT_FX */
+#define MIN_FLAT_Q10 4096 /* * 2 * BIN_SIZE_FLAT_FX */
+#define MAX_DIFF 100 /* * 2 * BIN_SIZE_DIFF_FX */
+#define MIN_DIFF 16 /* * 2 * BIN_SIZE_DIFF_FX */
+/* Criteria of weight of histogram peak to accept/reject feature */
+#define THRES_WEIGHT_FLAT_DIFF \
+ 154 /*(int)(0.3*(inst->modelUpdate)) for flatness and difference */
+
+#define STAT_UPDATES 9 /* Update every 512 = 1 << 9 block */
+#define ONE_MINUS_GAMMA_PAUSE_Q8 \
+ 13 /* ~= Q8(0.05) Update for conservative noise estimate */
+#define GAMMA_NOISE_TRANS_AND_SPEECH_Q8 \
+ 3 /* ~= Q8(0.01) Update for transition and noise region */
+
+#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_