summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/audio_processing/transient
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/libwebrtc/modules/audio_processing/transient
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/libwebrtc/modules/audio_processing/transient')
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/BUILD.gn133
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/click_annotate.cc107
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/common.h27
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h44
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator.h68
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator_unittest.cc111
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/file_utils.cc257
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/file_utils.h117
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/file_utils_unittest.cc501
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/moving_moments.cc50
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/moving_moments.h53
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/moving_moments_unittest.cc207
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/test/plotDetection.m22
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/test/readDetection.m26
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/test/readPCM.m26
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_detector.cc176
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_detector.h89
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_detector_unittest.cc95
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_suppression_test.cc238
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor.h75
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_api_gn/moz.build201
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.cc455
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.h115
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl_gn/moz.build236
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_unittest.cc175
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.cc56
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.h43
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_gn/moz.build221
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc108
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/windows_private.h557
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/wpd_node.cc72
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/wpd_node.h45
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/wpd_node_unittest.cc64
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.cc118
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.h92
-rw-r--r--third_party/libwebrtc/modules/audio_processing/transient/wpd_tree_unittest.cc177
36 files changed, 5157 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/BUILD.gn b/third_party/libwebrtc/modules/audio_processing/transient/BUILD.gn
new file mode 100644
index 0000000000..41aeab0abe
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/BUILD.gn
@@ -0,0 +1,133 @@
+# Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
+#
+# Use of this source code is governed by a BSD-style license
+# that can be found in the LICENSE file in the root of the source
+# tree. An additional intellectual property rights grant can be found
+# in the file PATENTS. All contributing project authors may
+# be found in the AUTHORS file in the root of the source tree.
+
+import("../../../webrtc.gni")
+
+rtc_source_set("transient_suppressor_api") {
+ sources = [ "transient_suppressor.h" ]
+}
+
+rtc_library("transient_suppressor_impl") {
+ visibility = [
+ ":click_annotate",
+ ":transient_suppression_test",
+ ":transient_suppression_unittests",
+ "..:optionally_built_submodule_creators",
+ ]
+ sources = [
+ "common.h",
+ "daubechies_8_wavelet_coeffs.h",
+ "dyadic_decimator.h",
+ "moving_moments.cc",
+ "moving_moments.h",
+ "transient_detector.cc",
+ "transient_detector.h",
+ "transient_suppressor_impl.cc",
+ "transient_suppressor_impl.h",
+ "windows_private.h",
+ "wpd_node.cc",
+ "wpd_node.h",
+ "wpd_tree.cc",
+ "wpd_tree.h",
+ ]
+ deps = [
+ ":transient_suppressor_api",
+ ":voice_probability_delay_unit",
+ "../../../common_audio:common_audio",
+ "../../../common_audio:common_audio_c",
+ "../../../common_audio:fir_filter",
+ "../../../common_audio:fir_filter_factory",
+ "../../../common_audio/third_party/ooura:fft_size_256",
+ "../../../rtc_base:checks",
+ "../../../rtc_base:gtest_prod",
+ "../../../rtc_base:logging",
+ ]
+}
+
+rtc_library("voice_probability_delay_unit") {
+ sources = [
+ "voice_probability_delay_unit.cc",
+ "voice_probability_delay_unit.h",
+ ]
+ deps = [ "../../../rtc_base:checks" ]
+}
+
+if (rtc_include_tests) {
+ if (!build_with_chromium) {
+ rtc_executable("click_annotate") {
+ testonly = true
+ sources = [
+ "click_annotate.cc",
+ "file_utils.cc",
+ "file_utils.h",
+ ]
+ deps = [
+ ":transient_suppressor_impl",
+ "..:audio_processing",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../system_wrappers",
+ ]
+ }
+
+ rtc_executable("transient_suppression_test") {
+ testonly = true
+ sources = [
+ "file_utils.cc",
+ "file_utils.h",
+ "transient_suppression_test.cc",
+ "voice_probability_delay_unit_unittest.cc",
+ ]
+ deps = [
+ ":transient_suppressor_api",
+ ":transient_suppressor_impl",
+ ":voice_probability_delay_unit",
+ "..:audio_processing",
+ "../../../common_audio",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../system_wrappers",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "../agc:level_estimation",
+ "//testing/gtest",
+ "//third_party/abseil-cpp/absl/flags:flag",
+ "//third_party/abseil-cpp/absl/flags:parse",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ }
+ }
+
+ rtc_library("transient_suppression_unittests") {
+ testonly = true
+ sources = [
+ "dyadic_decimator_unittest.cc",
+ "file_utils.cc",
+ "file_utils.h",
+ "file_utils_unittest.cc",
+ "moving_moments_unittest.cc",
+ "transient_detector_unittest.cc",
+ "transient_suppressor_unittest.cc",
+ "voice_probability_delay_unit_unittest.cc",
+ "wpd_node_unittest.cc",
+ "wpd_tree_unittest.cc",
+ ]
+ deps = [
+ ":transient_suppressor_api",
+ ":transient_suppressor_impl",
+ ":voice_probability_delay_unit",
+ "../../../rtc_base:stringutils",
+ "../../../rtc_base/system:file_wrapper",
+ "../../../test:fileutils",
+ "../../../test:test_support",
+ "//testing/gtest",
+ ]
+ absl_deps = [
+ "//third_party/abseil-cpp/absl/strings",
+ "//third_party/abseil-cpp/absl/types:optional",
+ ]
+ }
+}
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/click_annotate.cc b/third_party/libwebrtc/modules/audio_processing/transient/click_annotate.cc
new file mode 100644
index 0000000000..f3f040f9aa
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/click_annotate.cc
@@ -0,0 +1,107 @@
+/*
+ * 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 <cfloat>
+#include <cstdio>
+#include <cstdlib>
+#include <memory>
+#include <vector>
+
+#include "modules/audio_processing/transient/file_utils.h"
+#include "modules/audio_processing/transient/transient_detector.h"
+#include "rtc_base/system/file_wrapper.h"
+
+using webrtc::FileWrapper;
+using webrtc::TransientDetector;
+
+// Application to generate a RTP timing file.
+// Opens the PCM file and divides the signal in frames.
+// Creates a send times array, one for each step.
+// Each block that contains a transient, has an infinite send time.
+// The resultant array is written to a DAT file
+// Returns -1 on error or `lost_packets` otherwise.
+int main(int argc, char* argv[]) {
+ if (argc != 5) {
+ printf("\n%s - Application to generate a RTP timing file.\n\n", argv[0]);
+ printf("%s PCMfile DATfile chunkSize sampleRate\n\n", argv[0]);
+ printf("Opens the PCMfile with sampleRate in Hertz.\n");
+ printf("Creates a send times array, one for each chunkSize ");
+ printf("milliseconds step.\n");
+ printf("Each block that contains a transient, has an infinite send time. ");
+ printf("The resultant array is written to a DATfile.\n\n");
+ return 0;
+ }
+
+ FileWrapper pcm_file = FileWrapper::OpenReadOnly(argv[1]);
+ if (!pcm_file.is_open()) {
+ printf("\nThe %s could not be opened.\n\n", argv[1]);
+ return -1;
+ }
+
+ FileWrapper dat_file = FileWrapper::OpenWriteOnly(argv[2]);
+ if (!dat_file.is_open()) {
+ printf("\nThe %s could not be opened.\n\n", argv[2]);
+ return -1;
+ }
+
+ int chunk_size_ms = atoi(argv[3]);
+ if (chunk_size_ms <= 0) {
+ printf("\nThe chunkSize must be a positive integer\n\n");
+ return -1;
+ }
+
+ int sample_rate_hz = atoi(argv[4]);
+ if (sample_rate_hz <= 0) {
+ printf("\nThe sampleRate must be a positive integer\n\n");
+ return -1;
+ }
+
+ TransientDetector detector(sample_rate_hz);
+ int lost_packets = 0;
+ size_t audio_buffer_length = chunk_size_ms * sample_rate_hz / 1000;
+ std::unique_ptr<float[]> audio_buffer(new float[audio_buffer_length]);
+ std::vector<float> send_times;
+
+ // Read first buffer from the PCM test file.
+ size_t file_samples_read = ReadInt16FromFileToFloatBuffer(
+ &pcm_file, audio_buffer_length, audio_buffer.get());
+ for (int time = 0; file_samples_read > 0; time += chunk_size_ms) {
+ // Pad the rest of the buffer with zeros.
+ for (size_t i = file_samples_read; i < audio_buffer_length; ++i) {
+ audio_buffer[i] = 0.0;
+ }
+ float value =
+ detector.Detect(audio_buffer.get(), audio_buffer_length, NULL, 0);
+ if (value < 0.5f) {
+ value = time;
+ } else {
+ value = FLT_MAX;
+ ++lost_packets;
+ }
+ send_times.push_back(value);
+
+ // Read next buffer from the PCM test file.
+ file_samples_read = ReadInt16FromFileToFloatBuffer(
+ &pcm_file, audio_buffer_length, audio_buffer.get());
+ }
+
+ size_t floats_written =
+ WriteFloatBufferToFile(&dat_file, send_times.size(), &send_times[0]);
+
+ if (floats_written == 0) {
+ printf("\nThe send times could not be written to DAT file\n\n");
+ return -1;
+ }
+
+ pcm_file.Close();
+ dat_file.Close();
+
+ return lost_packets;
+}
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/common.h b/third_party/libwebrtc/modules/audio_processing/transient/common.h
new file mode 100644
index 0000000000..63c9a7b315
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/common.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2014 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_TRANSIENT_COMMON_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
+namespace webrtc {
+namespace ts {
+
+static const float kPi = 3.14159265358979323846f;
+static const int kChunkSizeMs = 10;
+enum {
+ kSampleRate8kHz = 8000,
+ kSampleRate16kHz = 16000,
+ kSampleRate32kHz = 32000,
+ kSampleRate48kHz = 48000
+};
+
+} // namespace ts
+} // namespace webrtc
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_COMMON_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h b/third_party/libwebrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
new file mode 100644
index 0000000000..92233bfd74
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+// This header file defines the coefficients of the FIR based approximation of
+// the Meyer Wavelet
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
+
+// Decomposition coefficients Daubechies 8.
+
+namespace webrtc {
+
+const int kDaubechies8CoefficientsLength = 16;
+
+const float kDaubechies8HighPassCoefficients[kDaubechies8CoefficientsLength] = {
+ -5.44158422430816093862e-02f, 3.12871590914465924627e-01f,
+ -6.75630736298012846142e-01f, 5.85354683654869090148e-01f,
+ 1.58291052560238926228e-02f, -2.84015542962428091389e-01f,
+ -4.72484573997972536787e-04f, 1.28747426620186011803e-01f,
+ 1.73693010020221083600e-02f, -4.40882539310647192377e-02f,
+ -1.39810279170155156436e-02f, 8.74609404701565465445e-03f,
+ 4.87035299301066034600e-03f, -3.91740372995977108837e-04f,
+ -6.75449405998556772109e-04f, -1.17476784002281916305e-04f};
+
+const float kDaubechies8LowPassCoefficients[kDaubechies8CoefficientsLength] = {
+ -1.17476784002281916305e-04f, 6.75449405998556772109e-04f,
+ -3.91740372995977108837e-04f, -4.87035299301066034600e-03f,
+ 8.74609404701565465445e-03f, 1.39810279170155156436e-02f,
+ -4.40882539310647192377e-02f, -1.73693010020221083600e-02f,
+ 1.28747426620186011803e-01f, 4.72484573997972536787e-04f,
+ -2.84015542962428091389e-01f, -1.58291052560238926228e-02f,
+ 5.85354683654869090148e-01f, 6.75630736298012846142e-01f,
+ 3.12871590914465924627e-01f, 5.44158422430816093862e-02f};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_DAUBECHIES_8_WAVELET_COEFFS_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator.h b/third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator.h
new file mode 100644
index 0000000000..52467e8c25
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
+
+#include <cstdlib>
+
+// Provides a set of static methods to perform dyadic decimations.
+
+namespace webrtc {
+
+// Returns the proper length of the output buffer that you should use for the
+// given `in_length` and decimation `odd_sequence`.
+// Return -1 on error.
+inline size_t GetOutLengthToDyadicDecimate(size_t in_length,
+ bool odd_sequence) {
+ size_t out_length = in_length / 2;
+
+ if (in_length % 2 == 1 && !odd_sequence) {
+ ++out_length;
+ }
+
+ return out_length;
+}
+
+// Performs a dyadic decimation: removes every odd/even member of a sequence
+// halving its overall length.
+// Arguments:
+// in: array of `in_length`.
+// odd_sequence: If false, the odd members will be removed (1, 3, 5, ...);
+// if true, the even members will be removed (0, 2, 4, ...).
+// out: array of `out_length`. `out_length` must be large enough to
+// hold the decimated output. The necessary length can be provided by
+// GetOutLengthToDyadicDecimate().
+// Must be previously allocated.
+// Returns the number of output samples, -1 on error.
+template <typename T>
+static size_t DyadicDecimate(const T* in,
+ size_t in_length,
+ bool odd_sequence,
+ T* out,
+ size_t out_length) {
+ size_t half_length = GetOutLengthToDyadicDecimate(in_length, odd_sequence);
+
+ if (!in || !out || in_length <= 0 || out_length < half_length) {
+ return 0;
+ }
+
+ size_t output_samples = 0;
+ size_t index_adjustment = odd_sequence ? 1 : 0;
+ for (output_samples = 0; output_samples < half_length; ++output_samples) {
+ out[output_samples] = in[output_samples * 2 + index_adjustment];
+ }
+
+ return output_samples;
+}
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_DYADIC_DECIMATOR_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator_unittest.cc
new file mode 100644
index 0000000000..e4776d694f
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/dyadic_decimator_unittest.cc
@@ -0,0 +1,111 @@
+/*
+ * 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 "modules/audio_processing/transient/dyadic_decimator.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+static const size_t kEvenBufferLength = 6;
+static const size_t kOddBufferLength = 5;
+static const size_t kOutBufferLength = 3;
+
+int16_t const test_buffer_even_len[] = {0, 1, 2, 3, 4, 5};
+int16_t const test_buffer_odd_len[] = {0, 1, 2, 3, 4};
+int16_t test_buffer_out[kOutBufferLength];
+
+TEST(DyadicDecimatorTest, GetOutLengthToDyadicDecimate) {
+ EXPECT_EQ(3u, GetOutLengthToDyadicDecimate(6, false));
+ EXPECT_EQ(3u, GetOutLengthToDyadicDecimate(6, true));
+ EXPECT_EQ(3u, GetOutLengthToDyadicDecimate(5, false));
+ EXPECT_EQ(2u, GetOutLengthToDyadicDecimate(5, true));
+}
+
+TEST(DyadicDecimatorTest, DyadicDecimateErrorValues) {
+ size_t out_samples = 0;
+
+ out_samples = DyadicDecimate(static_cast<int16_t*>(NULL), kEvenBufferLength,
+ false, // Even sequence.
+ test_buffer_out, kOutBufferLength);
+ EXPECT_EQ(0u, out_samples);
+
+ out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
+ false, // Even sequence.
+ static_cast<int16_t*>(NULL), kOutBufferLength);
+ EXPECT_EQ(0u, out_samples);
+
+ // Less than required `out_length`.
+ out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
+ false, // Even sequence.
+ test_buffer_out, 2);
+ EXPECT_EQ(0u, out_samples);
+}
+
+TEST(DyadicDecimatorTest, DyadicDecimateEvenLengthEvenSequence) {
+ size_t expected_out_samples =
+ GetOutLengthToDyadicDecimate(kEvenBufferLength, false);
+
+ size_t out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
+ false, // Even sequence.
+ test_buffer_out, kOutBufferLength);
+
+ EXPECT_EQ(expected_out_samples, out_samples);
+
+ EXPECT_EQ(0, test_buffer_out[0]);
+ EXPECT_EQ(2, test_buffer_out[1]);
+ EXPECT_EQ(4, test_buffer_out[2]);
+}
+
+TEST(DyadicDecimatorTest, DyadicDecimateEvenLengthOddSequence) {
+ size_t expected_out_samples =
+ GetOutLengthToDyadicDecimate(kEvenBufferLength, true);
+
+ size_t out_samples = DyadicDecimate(test_buffer_even_len, kEvenBufferLength,
+ true, // Odd sequence.
+ test_buffer_out, kOutBufferLength);
+
+ EXPECT_EQ(expected_out_samples, out_samples);
+
+ EXPECT_EQ(1, test_buffer_out[0]);
+ EXPECT_EQ(3, test_buffer_out[1]);
+ EXPECT_EQ(5, test_buffer_out[2]);
+}
+
+TEST(DyadicDecimatorTest, DyadicDecimateOddLengthEvenSequence) {
+ size_t expected_out_samples =
+ GetOutLengthToDyadicDecimate(kOddBufferLength, false);
+
+ size_t out_samples = DyadicDecimate(test_buffer_odd_len, kOddBufferLength,
+ false, // Even sequence.
+ test_buffer_out, kOutBufferLength);
+
+ EXPECT_EQ(expected_out_samples, out_samples);
+
+ EXPECT_EQ(0, test_buffer_out[0]);
+ EXPECT_EQ(2, test_buffer_out[1]);
+ EXPECT_EQ(4, test_buffer_out[2]);
+}
+
+TEST(DyadicDecimatorTest, DyadicDecimateOddLengthOddSequence) {
+ size_t expected_out_samples =
+ GetOutLengthToDyadicDecimate(kOddBufferLength, true);
+
+ size_t out_samples = DyadicDecimate(test_buffer_odd_len, kOddBufferLength,
+ true, // Odd sequence.
+ test_buffer_out, kOutBufferLength);
+
+ EXPECT_EQ(expected_out_samples, out_samples);
+
+ EXPECT_EQ(1, test_buffer_out[0]);
+ EXPECT_EQ(3, test_buffer_out[1]);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/file_utils.cc b/third_party/libwebrtc/modules/audio_processing/transient/file_utils.cc
new file mode 100644
index 0000000000..58f99325d1
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/file_utils.cc
@@ -0,0 +1,257 @@
+/*
+ * 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 "modules/audio_processing/transient/file_utils.h"
+
+#include <memory>
+
+#include "rtc_base/system/file_wrapper.h"
+
+namespace webrtc {
+
+int ConvertByteArrayToFloat(const uint8_t bytes[4], float* out) {
+ if (!bytes || !out) {
+ return -1;
+ }
+
+ uint32_t binary_value = 0;
+ for (int i = 3; i >= 0; --i) {
+ binary_value <<= 8;
+ binary_value += bytes[i];
+ }
+
+ *out = bit_cast<float>(binary_value);
+
+ return 0;
+}
+
+int ConvertByteArrayToDouble(const uint8_t bytes[8], double* out) {
+ if (!bytes || !out) {
+ return -1;
+ }
+
+ uint64_t binary_value = 0;
+ for (int i = 7; i >= 0; --i) {
+ binary_value <<= 8;
+ binary_value += bytes[i];
+ }
+
+ *out = bit_cast<double>(binary_value);
+
+ return 0;
+}
+
+int ConvertFloatToByteArray(float value, uint8_t out_bytes[4]) {
+ if (!out_bytes) {
+ return -1;
+ }
+
+ uint32_t binary_value = bit_cast<uint32_t>(value);
+ for (size_t i = 0; i < 4; ++i) {
+ out_bytes[i] = binary_value;
+ binary_value >>= 8;
+ }
+
+ return 0;
+}
+
+int ConvertDoubleToByteArray(double value, uint8_t out_bytes[8]) {
+ if (!out_bytes) {
+ return -1;
+ }
+
+ uint64_t binary_value = bit_cast<uint64_t>(value);
+ for (size_t i = 0; i < 8; ++i) {
+ out_bytes[i] = binary_value;
+ binary_value >>= 8;
+ }
+
+ return 0;
+}
+
+size_t ReadInt16BufferFromFile(FileWrapper* file,
+ size_t length,
+ int16_t* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[2]);
+
+ size_t int16s_read = 0;
+
+ while (int16s_read < length) {
+ size_t bytes_read = file->Read(byte_array.get(), 2);
+ if (bytes_read < 2) {
+ break;
+ }
+ int16_t value = byte_array[1];
+ value <<= 8;
+ value += byte_array[0];
+ buffer[int16s_read] = value;
+ ++int16s_read;
+ }
+
+ return int16s_read;
+}
+
+size_t ReadInt16FromFileToFloatBuffer(FileWrapper* file,
+ size_t length,
+ float* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<int16_t[]> buffer16(new int16_t[length]);
+
+ size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get());
+
+ for (size_t i = 0; i < int16s_read; ++i) {
+ buffer[i] = buffer16[i];
+ }
+
+ return int16s_read;
+}
+
+size_t ReadInt16FromFileToDoubleBuffer(FileWrapper* file,
+ size_t length,
+ double* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<int16_t[]> buffer16(new int16_t[length]);
+
+ size_t int16s_read = ReadInt16BufferFromFile(file, length, buffer16.get());
+
+ for (size_t i = 0; i < int16s_read; ++i) {
+ buffer[i] = buffer16[i];
+ }
+
+ return int16s_read;
+}
+
+size_t ReadFloatBufferFromFile(FileWrapper* file,
+ size_t length,
+ float* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[4]);
+
+ size_t floats_read = 0;
+
+ while (floats_read < length) {
+ size_t bytes_read = file->Read(byte_array.get(), 4);
+ if (bytes_read < 4) {
+ break;
+ }
+ ConvertByteArrayToFloat(byte_array.get(), &buffer[floats_read]);
+ ++floats_read;
+ }
+
+ return floats_read;
+}
+
+size_t ReadDoubleBufferFromFile(FileWrapper* file,
+ size_t length,
+ double* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[8]);
+
+ size_t doubles_read = 0;
+
+ while (doubles_read < length) {
+ size_t bytes_read = file->Read(byte_array.get(), 8);
+ if (bytes_read < 8) {
+ break;
+ }
+ ConvertByteArrayToDouble(byte_array.get(), &buffer[doubles_read]);
+ ++doubles_read;
+ }
+
+ return doubles_read;
+}
+
+size_t WriteInt16BufferToFile(FileWrapper* file,
+ size_t length,
+ const int16_t* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[2]);
+
+ size_t int16s_written = 0;
+
+ for (int16s_written = 0; int16s_written < length; ++int16s_written) {
+ // Get byte representation.
+ byte_array[0] = buffer[int16s_written] & 0xFF;
+ byte_array[1] = (buffer[int16s_written] >> 8) & 0xFF;
+
+ file->Write(byte_array.get(), 2);
+ }
+
+ file->Flush();
+
+ return int16s_written;
+}
+
+size_t WriteFloatBufferToFile(FileWrapper* file,
+ size_t length,
+ const float* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[4]);
+
+ size_t floats_written = 0;
+
+ for (floats_written = 0; floats_written < length; ++floats_written) {
+ // Get byte representation.
+ ConvertFloatToByteArray(buffer[floats_written], byte_array.get());
+
+ file->Write(byte_array.get(), 4);
+ }
+
+ file->Flush();
+
+ return floats_written;
+}
+
+size_t WriteDoubleBufferToFile(FileWrapper* file,
+ size_t length,
+ const double* buffer) {
+ if (!file || !file->is_open() || !buffer || length <= 0) {
+ return 0;
+ }
+
+ std::unique_ptr<uint8_t[]> byte_array(new uint8_t[8]);
+
+ size_t doubles_written = 0;
+
+ for (doubles_written = 0; doubles_written < length; ++doubles_written) {
+ // Get byte representation.
+ ConvertDoubleToByteArray(buffer[doubles_written], byte_array.get());
+
+ file->Write(byte_array.get(), 8);
+ }
+
+ file->Flush();
+
+ return doubles_written;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/file_utils.h b/third_party/libwebrtc/modules/audio_processing/transient/file_utils.h
new file mode 100644
index 0000000000..b748337773
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/file_utils.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
+
+#include <string.h>
+
+#include "rtc_base/system/file_wrapper.h"
+
+namespace webrtc {
+
+// This is a copy of the cast included in the Chromium codebase here:
+// http://cs.chromium.org/src/third_party/cld/base/casts.h
+template <class Dest, class Source>
+inline Dest bit_cast(const Source& source) {
+ // A compile error here means your Dest and Source have different sizes.
+ static_assert(sizeof(Dest) == sizeof(Source),
+ "Dest and Source have different sizes");
+
+ Dest dest;
+ memcpy(&dest, &source, sizeof(dest));
+ return dest;
+}
+
+// Converts the byte array with binary float representation to float.
+// Bytes must be in little-endian order.
+// Returns 0 if correct, -1 on error.
+int ConvertByteArrayToFloat(const uint8_t bytes[4], float* out);
+
+// Converts the byte array with binary double representation to double.
+// Bytes must be in little-endian order.
+// Returns 0 if correct, -1 on error.
+int ConvertByteArrayToDouble(const uint8_t bytes[8], double* out);
+
+// Converts a float to a byte array with binary float representation.
+// Bytes will be in little-endian order.
+// Returns 0 if correct, -1 on error.
+int ConvertFloatToByteArray(float value, uint8_t out_bytes[4]);
+
+// Converts a double to a byte array with binary double representation.
+// Bytes will be in little-endian order.
+// Returns 0 if correct, -1 on error.
+int ConvertDoubleToByteArray(double value, uint8_t out_bytes[8]);
+
+// Reads `length` 16-bit integers from `file` to `buffer`.
+// `file` must be previously opened.
+// Returns the number of 16-bit integers read or -1 on error.
+size_t ReadInt16BufferFromFile(FileWrapper* file,
+ size_t length,
+ int16_t* buffer);
+
+// Reads `length` 16-bit integers from `file` and stores those values
+// (converting them) in `buffer`.
+// `file` must be previously opened.
+// Returns the number of 16-bit integers read or -1 on error.
+size_t ReadInt16FromFileToFloatBuffer(FileWrapper* file,
+ size_t length,
+ float* buffer);
+
+// Reads `length` 16-bit integers from `file` and stores those values
+// (converting them) in `buffer`.
+// `file` must be previously opened.
+// Returns the number of 16-bit integers read or -1 on error.
+size_t ReadInt16FromFileToDoubleBuffer(FileWrapper* file,
+ size_t length,
+ double* buffer);
+
+// Reads `length` floats in binary representation (4 bytes) from `file` to
+// `buffer`.
+// `file` must be previously opened.
+// Returns the number of floats read or -1 on error.
+size_t ReadFloatBufferFromFile(FileWrapper* file, size_t length, float* buffer);
+
+// Reads `length` doubles in binary representation (8 bytes) from `file` to
+// `buffer`.
+// `file` must be previously opened.
+// Returns the number of doubles read or -1 on error.
+size_t ReadDoubleBufferFromFile(FileWrapper* file,
+ size_t length,
+ double* buffer);
+
+// Writes `length` 16-bit integers from `buffer` in binary representation (2
+// bytes) to `file`. It flushes `file`, so after this call there are no
+// writings pending.
+// `file` must be previously opened.
+// Returns the number of doubles written or -1 on error.
+size_t WriteInt16BufferToFile(FileWrapper* file,
+ size_t length,
+ const int16_t* buffer);
+
+// Writes `length` floats from `buffer` in binary representation (4 bytes) to
+// `file`. It flushes `file`, so after this call there are no writtings pending.
+// `file` must be previously opened.
+// Returns the number of doubles written or -1 on error.
+size_t WriteFloatBufferToFile(FileWrapper* file,
+ size_t length,
+ const float* buffer);
+
+// Writes `length` doubles from `buffer` in binary representation (8 bytes) to
+// `file`. It flushes `file`, so after this call there are no writings pending.
+// `file` must be previously opened.
+// Returns the number of doubles written or -1 on error.
+size_t WriteDoubleBufferToFile(FileWrapper* file,
+ size_t length,
+ const double* buffer);
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_FILE_UTILS_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/file_utils_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/file_utils_unittest.cc
new file mode 100644
index 0000000000..a9dddb1eda
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/file_utils_unittest.cc
@@ -0,0 +1,501 @@
+/*
+ * 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 "modules/audio_processing/transient/file_utils.h"
+
+#include <string.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/system/file_wrapper.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+static const uint8_t kPiBytesf[4] = {0xDB, 0x0F, 0x49, 0x40};
+static const uint8_t kEBytesf[4] = {0x54, 0xF8, 0x2D, 0x40};
+static const uint8_t kAvogadroBytesf[4] = {0x2F, 0x0C, 0xFF, 0x66};
+
+static const uint8_t kPiBytes[8] = {0x18, 0x2D, 0x44, 0x54,
+ 0xFB, 0x21, 0x09, 0x40};
+static const uint8_t kEBytes[8] = {0x69, 0x57, 0x14, 0x8B,
+ 0x0A, 0xBF, 0x05, 0x40};
+static const uint8_t kAvogadroBytes[8] = {0xF4, 0xBC, 0xA8, 0xDF,
+ 0x85, 0xE1, 0xDF, 0x44};
+
+static const double kPi = 3.14159265358979323846;
+static const double kE = 2.71828182845904523536;
+static const double kAvogadro = 602214100000000000000000.0;
+
+class TransientFileUtilsTest : public ::testing::Test {
+ protected:
+ TransientFileUtilsTest()
+ : kTestFileName(
+ test::ResourcePath("audio_processing/transient/double-utils",
+ "dat")),
+ kTestFileNamef(
+ test::ResourcePath("audio_processing/transient/float-utils",
+ "dat")) {}
+
+ ~TransientFileUtilsTest() override { CleanupTempFiles(); }
+
+ std::string CreateTempFilename(absl::string_view dir,
+ absl::string_view prefix) {
+ std::string filename = test::TempFilename(dir, prefix);
+ temp_filenames_.push_back(filename);
+ return filename;
+ }
+
+ void CleanupTempFiles() {
+ for (const std::string& filename : temp_filenames_) {
+ remove(filename.c_str());
+ }
+ temp_filenames_.clear();
+ }
+
+ // This file (used in some tests) contains binary data. The data correspond to
+ // the double representation of the constants: Pi, E, and the Avogadro's
+ // Number;
+ // appended in that order.
+ const std::string kTestFileName;
+
+ // This file (used in some tests) contains binary data. The data correspond to
+ // the float representation of the constants: Pi, E, and the Avogadro's
+ // Number;
+ // appended in that order.
+ const std::string kTestFileNamef;
+
+ // List of temporary filenames created by CreateTempFilename.
+ std::vector<std::string> temp_filenames_;
+};
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ConvertByteArrayToFloat DISABLED_ConvertByteArrayToFloat
+#else
+#define MAYBE_ConvertByteArrayToFloat ConvertByteArrayToFloat
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ConvertByteArrayToFloat) {
+ float value = 0.0;
+
+ EXPECT_EQ(0, ConvertByteArrayToFloat(kPiBytesf, &value));
+ EXPECT_FLOAT_EQ(kPi, value);
+
+ EXPECT_EQ(0, ConvertByteArrayToFloat(kEBytesf, &value));
+ EXPECT_FLOAT_EQ(kE, value);
+
+ EXPECT_EQ(0, ConvertByteArrayToFloat(kAvogadroBytesf, &value));
+ EXPECT_FLOAT_EQ(kAvogadro, value);
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ConvertByteArrayToDouble DISABLED_ConvertByteArrayToDouble
+#else
+#define MAYBE_ConvertByteArrayToDouble ConvertByteArrayToDouble
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ConvertByteArrayToDouble) {
+ double value = 0.0;
+
+ EXPECT_EQ(0, ConvertByteArrayToDouble(kPiBytes, &value));
+ EXPECT_DOUBLE_EQ(kPi, value);
+
+ EXPECT_EQ(0, ConvertByteArrayToDouble(kEBytes, &value));
+ EXPECT_DOUBLE_EQ(kE, value);
+
+ EXPECT_EQ(0, ConvertByteArrayToDouble(kAvogadroBytes, &value));
+ EXPECT_DOUBLE_EQ(kAvogadro, value);
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ConvertFloatToByteArray DISABLED_ConvertFloatToByteArray
+#else
+#define MAYBE_ConvertFloatToByteArray ConvertFloatToByteArray
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ConvertFloatToByteArray) {
+ std::unique_ptr<uint8_t[]> bytes(new uint8_t[4]);
+
+ EXPECT_EQ(0, ConvertFloatToByteArray(kPi, bytes.get()));
+ EXPECT_EQ(0, memcmp(bytes.get(), kPiBytesf, 4));
+
+ EXPECT_EQ(0, ConvertFloatToByteArray(kE, bytes.get()));
+ EXPECT_EQ(0, memcmp(bytes.get(), kEBytesf, 4));
+
+ EXPECT_EQ(0, ConvertFloatToByteArray(kAvogadro, bytes.get()));
+ EXPECT_EQ(0, memcmp(bytes.get(), kAvogadroBytesf, 4));
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ConvertDoubleToByteArray DISABLED_ConvertDoubleToByteArray
+#else
+#define MAYBE_ConvertDoubleToByteArray ConvertDoubleToByteArray
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ConvertDoubleToByteArray) {
+ std::unique_ptr<uint8_t[]> bytes(new uint8_t[8]);
+
+ EXPECT_EQ(0, ConvertDoubleToByteArray(kPi, bytes.get()));
+ EXPECT_EQ(0, memcmp(bytes.get(), kPiBytes, 8));
+
+ EXPECT_EQ(0, ConvertDoubleToByteArray(kE, bytes.get()));
+ EXPECT_EQ(0, memcmp(bytes.get(), kEBytes, 8));
+
+ EXPECT_EQ(0, ConvertDoubleToByteArray(kAvogadro, bytes.get()));
+ EXPECT_EQ(0, memcmp(bytes.get(), kAvogadroBytes, 8));
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ReadInt16BufferFromFile DISABLED_ReadInt16BufferFromFile
+#else
+#define MAYBE_ReadInt16BufferFromFile ReadInt16BufferFromFile
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16BufferFromFile) {
+ std::string test_filename = kTestFileName;
+
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
+
+ const size_t kBufferLength = 12;
+ std::unique_ptr<int16_t[]> buffer(new int16_t[kBufferLength]);
+
+ EXPECT_EQ(kBufferLength,
+ ReadInt16BufferFromFile(&file, kBufferLength, buffer.get()));
+ EXPECT_EQ(22377, buffer[4]);
+ EXPECT_EQ(16389, buffer[7]);
+ EXPECT_EQ(17631, buffer[kBufferLength - 1]);
+
+ file.Rewind();
+
+ // The next test is for checking the case where there are not as much data as
+ // needed in the file, but reads to the end, and it returns the number of
+ // int16s read.
+ const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
+ buffer.reset(new int16_t[kBufferLenghtLargerThanFile]);
+ EXPECT_EQ(kBufferLength,
+ ReadInt16BufferFromFile(&file, kBufferLenghtLargerThanFile,
+ buffer.get()));
+ EXPECT_EQ(11544, buffer[0]);
+ EXPECT_EQ(22377, buffer[4]);
+ EXPECT_EQ(16389, buffer[7]);
+ EXPECT_EQ(17631, buffer[kBufferLength - 1]);
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ReadInt16FromFileToFloatBuffer \
+ DISABLED_ReadInt16FromFileToFloatBuffer
+#else
+#define MAYBE_ReadInt16FromFileToFloatBuffer ReadInt16FromFileToFloatBuffer
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToFloatBuffer) {
+ std::string test_filename = kTestFileName;
+
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
+
+ const size_t kBufferLength = 12;
+ std::unique_ptr<float[]> buffer(new float[kBufferLength]);
+
+ EXPECT_EQ(kBufferLength,
+ ReadInt16FromFileToFloatBuffer(&file, kBufferLength, buffer.get()));
+
+ EXPECT_DOUBLE_EQ(11544, buffer[0]);
+ EXPECT_DOUBLE_EQ(22377, buffer[4]);
+ EXPECT_DOUBLE_EQ(16389, buffer[7]);
+ EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]);
+
+ file.Rewind();
+
+ // The next test is for checking the case where there are not as much data as
+ // needed in the file, but reads to the end, and it returns the number of
+ // int16s read.
+ const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
+ buffer.reset(new float[kBufferLenghtLargerThanFile]);
+ EXPECT_EQ(kBufferLength,
+ ReadInt16FromFileToFloatBuffer(&file, kBufferLenghtLargerThanFile,
+ buffer.get()));
+ EXPECT_DOUBLE_EQ(11544, buffer[0]);
+ EXPECT_DOUBLE_EQ(22377, buffer[4]);
+ EXPECT_DOUBLE_EQ(16389, buffer[7]);
+ EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]);
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ReadInt16FromFileToDoubleBuffer \
+ DISABLED_ReadInt16FromFileToDoubleBuffer
+#else
+#define MAYBE_ReadInt16FromFileToDoubleBuffer ReadInt16FromFileToDoubleBuffer
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ReadInt16FromFileToDoubleBuffer) {
+ std::string test_filename = kTestFileName;
+
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
+
+ const size_t kBufferLength = 12;
+ std::unique_ptr<double[]> buffer(new double[kBufferLength]);
+
+ EXPECT_EQ(kBufferLength, ReadInt16FromFileToDoubleBuffer(&file, kBufferLength,
+ buffer.get()));
+ EXPECT_DOUBLE_EQ(11544, buffer[0]);
+ EXPECT_DOUBLE_EQ(22377, buffer[4]);
+ EXPECT_DOUBLE_EQ(16389, buffer[7]);
+ EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]);
+
+ file.Rewind();
+
+ // The next test is for checking the case where there are not as much data as
+ // needed in the file, but reads to the end, and it returns the number of
+ // int16s read.
+ const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
+ buffer.reset(new double[kBufferLenghtLargerThanFile]);
+ EXPECT_EQ(kBufferLength,
+ ReadInt16FromFileToDoubleBuffer(&file, kBufferLenghtLargerThanFile,
+ buffer.get()));
+ EXPECT_DOUBLE_EQ(11544, buffer[0]);
+ EXPECT_DOUBLE_EQ(22377, buffer[4]);
+ EXPECT_DOUBLE_EQ(16389, buffer[7]);
+ EXPECT_DOUBLE_EQ(17631, buffer[kBufferLength - 1]);
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ReadFloatBufferFromFile DISABLED_ReadFloatBufferFromFile
+#else
+#define MAYBE_ReadFloatBufferFromFile ReadFloatBufferFromFile
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ReadFloatBufferFromFile) {
+ std::string test_filename = kTestFileNamef;
+
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileNamef.c_str();
+
+ const size_t kBufferLength = 3;
+ std::unique_ptr<float[]> buffer(new float[kBufferLength]);
+
+ EXPECT_EQ(kBufferLength,
+ ReadFloatBufferFromFile(&file, kBufferLength, buffer.get()));
+ EXPECT_FLOAT_EQ(kPi, buffer[0]);
+ EXPECT_FLOAT_EQ(kE, buffer[1]);
+ EXPECT_FLOAT_EQ(kAvogadro, buffer[2]);
+
+ file.Rewind();
+
+ // The next test is for checking the case where there are not as much data as
+ // needed in the file, but reads to the end, and it returns the number of
+ // doubles read.
+ const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
+ buffer.reset(new float[kBufferLenghtLargerThanFile]);
+ EXPECT_EQ(kBufferLength,
+ ReadFloatBufferFromFile(&file, kBufferLenghtLargerThanFile,
+ buffer.get()));
+ EXPECT_FLOAT_EQ(kPi, buffer[0]);
+ EXPECT_FLOAT_EQ(kE, buffer[1]);
+ EXPECT_FLOAT_EQ(kAvogadro, buffer[2]);
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ReadDoubleBufferFromFile DISABLED_ReadDoubleBufferFromFile
+#else
+#define MAYBE_ReadDoubleBufferFromFile ReadDoubleBufferFromFile
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ReadDoubleBufferFromFile) {
+ std::string test_filename = kTestFileName;
+
+ FileWrapper file = FileWrapper::OpenReadOnly(test_filename);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
+
+ const size_t kBufferLength = 3;
+ std::unique_ptr<double[]> buffer(new double[kBufferLength]);
+
+ EXPECT_EQ(kBufferLength,
+ ReadDoubleBufferFromFile(&file, kBufferLength, buffer.get()));
+ EXPECT_DOUBLE_EQ(kPi, buffer[0]);
+ EXPECT_DOUBLE_EQ(kE, buffer[1]);
+ EXPECT_DOUBLE_EQ(kAvogadro, buffer[2]);
+
+ file.Rewind();
+
+ // The next test is for checking the case where there are not as much data as
+ // needed in the file, but reads to the end, and it returns the number of
+ // doubles read.
+ const size_t kBufferLenghtLargerThanFile = kBufferLength * 2;
+ buffer.reset(new double[kBufferLenghtLargerThanFile]);
+ EXPECT_EQ(kBufferLength,
+ ReadDoubleBufferFromFile(&file, kBufferLenghtLargerThanFile,
+ buffer.get()));
+ EXPECT_DOUBLE_EQ(kPi, buffer[0]);
+ EXPECT_DOUBLE_EQ(kE, buffer[1]);
+ EXPECT_DOUBLE_EQ(kAvogadro, buffer[2]);
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_WriteInt16BufferToFile DISABLED_WriteInt16BufferToFile
+#else
+#define MAYBE_WriteInt16BufferToFile WriteInt16BufferToFile
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_WriteInt16BufferToFile) {
+ std::string kOutFileName =
+ CreateTempFilename(test::OutputPath(), "utils_test");
+
+ FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
+
+ const size_t kBufferLength = 3;
+ std::unique_ptr<int16_t[]> written_buffer(new int16_t[kBufferLength]);
+ std::unique_ptr<int16_t[]> read_buffer(new int16_t[kBufferLength]);
+
+ written_buffer[0] = 1;
+ written_buffer[1] = 2;
+ written_buffer[2] = 3;
+
+ EXPECT_EQ(kBufferLength,
+ WriteInt16BufferToFile(&file, kBufferLength, written_buffer.get()));
+
+ file.Close();
+
+ file = FileWrapper::OpenReadOnly(kOutFileName);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
+
+ EXPECT_EQ(kBufferLength,
+ ReadInt16BufferFromFile(&file, kBufferLength, read_buffer.get()));
+ EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
+ kBufferLength * sizeof(written_buffer[0])));
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_WriteFloatBufferToFile DISABLED_WriteFloatBufferToFile
+#else
+#define MAYBE_WriteFloatBufferToFile WriteFloatBufferToFile
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_WriteFloatBufferToFile) {
+ std::string kOutFileName =
+ CreateTempFilename(test::OutputPath(), "utils_test");
+
+ FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
+
+ const size_t kBufferLength = 3;
+ std::unique_ptr<float[]> written_buffer(new float[kBufferLength]);
+ std::unique_ptr<float[]> read_buffer(new float[kBufferLength]);
+
+ written_buffer[0] = static_cast<float>(kPi);
+ written_buffer[1] = static_cast<float>(kE);
+ written_buffer[2] = static_cast<float>(kAvogadro);
+
+ EXPECT_EQ(kBufferLength,
+ WriteFloatBufferToFile(&file, kBufferLength, written_buffer.get()));
+
+ file.Close();
+
+ file = FileWrapper::OpenReadOnly(kOutFileName);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
+
+ EXPECT_EQ(kBufferLength,
+ ReadFloatBufferFromFile(&file, kBufferLength, read_buffer.get()));
+ EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
+ kBufferLength * sizeof(written_buffer[0])));
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_WriteDoubleBufferToFile DISABLED_WriteDoubleBufferToFile
+#else
+#define MAYBE_WriteDoubleBufferToFile WriteDoubleBufferToFile
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_WriteDoubleBufferToFile) {
+ std::string kOutFileName =
+ CreateTempFilename(test::OutputPath(), "utils_test");
+
+ FileWrapper file = FileWrapper::OpenWriteOnly(kOutFileName);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
+
+ const size_t kBufferLength = 3;
+ std::unique_ptr<double[]> written_buffer(new double[kBufferLength]);
+ std::unique_ptr<double[]> read_buffer(new double[kBufferLength]);
+
+ written_buffer[0] = kPi;
+ written_buffer[1] = kE;
+ written_buffer[2] = kAvogadro;
+
+ EXPECT_EQ(kBufferLength, WriteDoubleBufferToFile(&file, kBufferLength,
+ written_buffer.get()));
+
+ file.Close();
+
+ file = FileWrapper::OpenReadOnly(kOutFileName);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kOutFileName.c_str();
+
+ EXPECT_EQ(kBufferLength,
+ ReadDoubleBufferFromFile(&file, kBufferLength, read_buffer.get()));
+ EXPECT_EQ(0, memcmp(written_buffer.get(), read_buffer.get(),
+ kBufferLength * sizeof(written_buffer[0])));
+}
+
+#if defined(WEBRTC_IOS)
+#define MAYBE_ExpectedErrorReturnValues DISABLED_ExpectedErrorReturnValues
+#else
+#define MAYBE_ExpectedErrorReturnValues ExpectedErrorReturnValues
+#endif
+TEST_F(TransientFileUtilsTest, MAYBE_ExpectedErrorReturnValues) {
+ std::string test_filename = kTestFileName;
+
+ double value;
+ std::unique_ptr<int16_t[]> int16_buffer(new int16_t[1]);
+ std::unique_ptr<double[]> double_buffer(new double[1]);
+ FileWrapper file;
+
+ EXPECT_EQ(-1, ConvertByteArrayToDouble(NULL, &value));
+ EXPECT_EQ(-1, ConvertByteArrayToDouble(kPiBytes, NULL));
+
+ EXPECT_EQ(-1, ConvertDoubleToByteArray(kPi, NULL));
+
+ // Tests with file not opened.
+ EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 1, int16_buffer.get()));
+ EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 1, double_buffer.get()));
+ EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 1, double_buffer.get()));
+ EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 1, int16_buffer.get()));
+ EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 1, double_buffer.get()));
+
+ file = FileWrapper::OpenReadOnly(test_filename);
+ ASSERT_TRUE(file.is_open()) << "File could not be opened:\n"
+ << kTestFileName.c_str();
+
+ EXPECT_EQ(0u, ReadInt16BufferFromFile(NULL, 1, int16_buffer.get()));
+ EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 1, NULL));
+ EXPECT_EQ(0u, ReadInt16BufferFromFile(&file, 0, int16_buffer.get()));
+
+ EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(NULL, 1, double_buffer.get()));
+ EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 1, NULL));
+ EXPECT_EQ(0u, ReadInt16FromFileToDoubleBuffer(&file, 0, double_buffer.get()));
+
+ EXPECT_EQ(0u, ReadDoubleBufferFromFile(NULL, 1, double_buffer.get()));
+ EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 1, NULL));
+ EXPECT_EQ(0u, ReadDoubleBufferFromFile(&file, 0, double_buffer.get()));
+
+ EXPECT_EQ(0u, WriteInt16BufferToFile(NULL, 1, int16_buffer.get()));
+ EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 1, NULL));
+ EXPECT_EQ(0u, WriteInt16BufferToFile(&file, 0, int16_buffer.get()));
+
+ EXPECT_EQ(0u, WriteDoubleBufferToFile(NULL, 1, double_buffer.get()));
+ EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 1, NULL));
+ EXPECT_EQ(0u, WriteDoubleBufferToFile(&file, 0, double_buffer.get()));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/moving_moments.cc b/third_party/libwebrtc/modules/audio_processing/transient/moving_moments.cc
new file mode 100644
index 0000000000..83810bfe3c
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/moving_moments.cc
@@ -0,0 +1,50 @@
+/*
+ * 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 "modules/audio_processing/transient/moving_moments.h"
+
+#include <algorithm>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+MovingMoments::MovingMoments(size_t length)
+ : length_(length), queue_(), sum_(0.0), sum_of_squares_(0.0) {
+ RTC_DCHECK_GT(length, 0);
+ for (size_t i = 0; i < length; ++i) {
+ queue_.push(0.0);
+ }
+}
+
+MovingMoments::~MovingMoments() {}
+
+void MovingMoments::CalculateMoments(const float* in,
+ size_t in_length,
+ float* first,
+ float* second) {
+ RTC_DCHECK(in);
+ RTC_DCHECK_GT(in_length, 0);
+ RTC_DCHECK(first);
+ RTC_DCHECK(second);
+
+ for (size_t i = 0; i < in_length; ++i) {
+ const float old_value = queue_.front();
+ queue_.pop();
+ queue_.push(in[i]);
+
+ sum_ += in[i] - old_value;
+ sum_of_squares_ += in[i] * in[i] - old_value * old_value;
+ first[i] = sum_ / length_;
+ second[i] = std::max(0.f, sum_of_squares_ / length_);
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/moving_moments.h b/third_party/libwebrtc/modules/audio_processing/transient/moving_moments.h
new file mode 100644
index 0000000000..70451dcb71
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/moving_moments.h
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
+
+#include <stddef.h>
+
+#include <queue>
+
+namespace webrtc {
+
+// Calculates the first and second moments for each value of a buffer taking
+// into account a given number of previous values.
+// It preserves its state, so it can be multiple-called.
+// TODO(chadan): Implement a function that takes a buffer of first moments and a
+// buffer of second moments; and calculates the variances. When needed.
+// TODO(chadan): Add functionality to update with a buffer but only output are
+// the last values of the moments. When needed.
+class MovingMoments {
+ public:
+ // Creates a Moving Moments object, that uses the last `length` values
+ // (including the new value introduced in every new calculation).
+ explicit MovingMoments(size_t length);
+ ~MovingMoments();
+
+ // Calculates the new values using `in`. Results will be in the out buffers.
+ // `first` and `second` must be allocated with at least `in_length`.
+ void CalculateMoments(const float* in,
+ size_t in_length,
+ float* first,
+ float* second);
+
+ private:
+ size_t length_;
+ // A queue holding the `length_` latest input values.
+ std::queue<float> queue_;
+ // Sum of the values of the queue.
+ float sum_;
+ // Sum of the squares of the values of the queue.
+ float sum_of_squares_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_MOVING_MOMENTS_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/moving_moments_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/moving_moments_unittest.cc
new file mode 100644
index 0000000000..b0e613e7ab
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/moving_moments_unittest.cc
@@ -0,0 +1,207 @@
+/*
+ * 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 "modules/audio_processing/transient/moving_moments.h"
+
+#include <memory>
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+static const float kTolerance = 0.0001f;
+
+class MovingMomentsTest : public ::testing::Test {
+ protected:
+ static const size_t kMovingMomentsBufferLength = 5;
+ static const size_t kMaxOutputLength = 20; // Valid for this tests only.
+
+ virtual void SetUp();
+ // Calls CalculateMoments and verifies that it produces the expected
+ // outputs.
+ void CalculateMomentsAndVerify(const float* input,
+ size_t input_length,
+ const float* expected_mean,
+ const float* expected_mean_squares);
+
+ std::unique_ptr<MovingMoments> moving_moments_;
+ float output_mean_[kMaxOutputLength];
+ float output_mean_squares_[kMaxOutputLength];
+};
+
+const size_t MovingMomentsTest::kMaxOutputLength;
+
+void MovingMomentsTest::SetUp() {
+ moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
+}
+
+void MovingMomentsTest::CalculateMomentsAndVerify(
+ const float* input,
+ size_t input_length,
+ const float* expected_mean,
+ const float* expected_mean_squares) {
+ ASSERT_LE(input_length, kMaxOutputLength);
+
+ moving_moments_->CalculateMoments(input, input_length, output_mean_,
+ output_mean_squares_);
+
+ for (size_t i = 1; i < input_length; ++i) {
+ EXPECT_NEAR(expected_mean[i], output_mean_[i], kTolerance);
+ EXPECT_NEAR(expected_mean_squares[i], output_mean_squares_[i], kTolerance);
+ }
+}
+
+TEST_F(MovingMomentsTest, CorrectMomentsOfAnAllZerosBuffer) {
+ const float kInput[] = {0.f, 0.f, 0.f, 0.f, 0.f};
+ const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
+
+ const float expected_mean[kInputLength] = {0.f, 0.f, 0.f, 0.f, 0.f};
+ const float expected_mean_squares[kInputLength] = {0.f, 0.f, 0.f, 0.f, 0.f};
+
+ CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
+ expected_mean_squares);
+}
+
+TEST_F(MovingMomentsTest, CorrectMomentsOfAConstantBuffer) {
+ const float kInput[] = {5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f, 5.f};
+ const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
+
+ const float expected_mean[kInputLength] = {1.f, 2.f, 3.f, 4.f, 5.f,
+ 5.f, 5.f, 5.f, 5.f, 5.f};
+ const float expected_mean_squares[kInputLength] = {
+ 5.f, 10.f, 15.f, 20.f, 25.f, 25.f, 25.f, 25.f, 25.f, 25.f};
+
+ CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
+ expected_mean_squares);
+}
+
+TEST_F(MovingMomentsTest, CorrectMomentsOfAnIncreasingBuffer) {
+ const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f};
+ const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
+
+ const float expected_mean[kInputLength] = {0.2f, 0.6f, 1.2f, 2.f, 3.f,
+ 4.f, 5.f, 6.f, 7.f};
+ const float expected_mean_squares[kInputLength] = {
+ 0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
+
+ CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
+ expected_mean_squares);
+}
+
+TEST_F(MovingMomentsTest, CorrectMomentsOfADecreasingBuffer) {
+ const float kInput[] = {-1.f, -2.f, -3.f, -4.f, -5.f, -6.f, -7.f, -8.f, -9.f};
+ const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
+
+ const float expected_mean[kInputLength] = {-0.2f, -0.6f, -1.2f, -2.f, -3.f,
+ -4.f, -5.f, -6.f, -7.f};
+ const float expected_mean_squares[kInputLength] = {
+ 0.2f, 1.f, 2.8f, 6.f, 11.f, 18.f, 27.f, 38.f, 51.f};
+
+ CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
+ expected_mean_squares);
+}
+
+TEST_F(MovingMomentsTest, CorrectMomentsOfAZeroMeanSequence) {
+ const size_t kMovingMomentsBufferLength = 4;
+ moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
+ const float kInput[] = {1.f, -1.f, 1.f, -1.f, 1.f,
+ -1.f, 1.f, -1.f, 1.f, -1.f};
+ const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
+
+ const float expected_mean[kInputLength] = {0.25f, 0.f, 0.25f, 0.f, 0.f,
+ 0.f, 0.f, 0.f, 0.f, 0.f};
+ const float expected_mean_squares[kInputLength] = {
+ 0.25f, 0.5f, 0.75f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
+
+ CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
+ expected_mean_squares);
+}
+
+TEST_F(MovingMomentsTest, CorrectMomentsOfAnArbitraryBuffer) {
+ const float kInput[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f,
+ 0.13f, 0.17f, 0.19f, 0.23f};
+ const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
+
+ const float expected_mean[kInputLength] = {
+ 0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
+ const float expected_mean_squares[kInputLength] = {0.008f, 0.026f, 0.076f,
+ 0.174f, 0.1764f, 0.1718f,
+ 0.1596f, 0.1168f, 0.0294f};
+
+ CalculateMomentsAndVerify(kInput, kInputLength, expected_mean,
+ expected_mean_squares);
+}
+
+TEST_F(MovingMomentsTest, MutipleCalculateMomentsCalls) {
+ const float kInputFirstCall[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f,
+ 0.13f, 0.17f, 0.19f, 0.23f};
+ const size_t kInputFirstCallLength =
+ sizeof(kInputFirstCall) / sizeof(kInputFirstCall[0]);
+ const float kInputSecondCall[] = {0.29f, 0.31f};
+ const size_t kInputSecondCallLength =
+ sizeof(kInputSecondCall) / sizeof(kInputSecondCall[0]);
+ const float kInputThirdCall[] = {0.37f, 0.41f, 0.43f, 0.47f};
+ const size_t kInputThirdCallLength =
+ sizeof(kInputThirdCall) / sizeof(kInputThirdCall[0]);
+
+ const float expected_mean_first_call[kInputFirstCallLength] = {
+ 0.04f, 0.1f, 0.2f, 0.34f, 0.362f, 0.348f, 0.322f, 0.26f, 0.166f};
+ const float expected_mean_squares_first_call[kInputFirstCallLength] = {
+ 0.008f, 0.026f, 0.076f, 0.174f, 0.1764f,
+ 0.1718f, 0.1596f, 0.1168f, 0.0294f};
+
+ const float expected_mean_second_call[kInputSecondCallLength] = {0.202f,
+ 0.238f};
+ const float expected_mean_squares_second_call[kInputSecondCallLength] = {
+ 0.0438f, 0.0596f};
+
+ const float expected_mean_third_call[kInputThirdCallLength] = {
+ 0.278f, 0.322f, 0.362f, 0.398f};
+ const float expected_mean_squares_third_call[kInputThirdCallLength] = {
+ 0.0812f, 0.1076f, 0.134f, 0.1614f};
+
+ CalculateMomentsAndVerify(kInputFirstCall, kInputFirstCallLength,
+ expected_mean_first_call,
+ expected_mean_squares_first_call);
+
+ CalculateMomentsAndVerify(kInputSecondCall, kInputSecondCallLength,
+ expected_mean_second_call,
+ expected_mean_squares_second_call);
+
+ CalculateMomentsAndVerify(kInputThirdCall, kInputThirdCallLength,
+ expected_mean_third_call,
+ expected_mean_squares_third_call);
+}
+
+TEST_F(MovingMomentsTest, VerifySampleBasedVsBlockBasedCalculation) {
+ const float kInput[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f,
+ 0.13f, 0.17f, 0.19f, 0.23f};
+ const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]);
+
+ float output_mean_block_based[kInputLength];
+ float output_mean_squares_block_based[kInputLength];
+
+ float output_mean_sample_based;
+ float output_mean_squares_sample_based;
+
+ moving_moments_->CalculateMoments(kInput, kInputLength,
+ output_mean_block_based,
+ output_mean_squares_block_based);
+ moving_moments_.reset(new MovingMoments(kMovingMomentsBufferLength));
+ for (size_t i = 0; i < kInputLength; ++i) {
+ moving_moments_->CalculateMoments(&kInput[i], 1, &output_mean_sample_based,
+ &output_mean_squares_sample_based);
+ EXPECT_FLOAT_EQ(output_mean_block_based[i], output_mean_sample_based);
+ EXPECT_FLOAT_EQ(output_mean_squares_block_based[i],
+ output_mean_squares_sample_based);
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/test/plotDetection.m b/third_party/libwebrtc/modules/audio_processing/transient/test/plotDetection.m
new file mode 100644
index 0000000000..8e12ab920b
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/test/plotDetection.m
@@ -0,0 +1,22 @@
+%
+% Copyright (c) 2014 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.
+%
+
+function [] = plotDetection(PCMfile, DATfile, fs, chunkSize)
+%[] = plotDetection(PCMfile, DATfile, fs, chunkSize)
+%
+%Plots the signal alongside the detection values.
+%
+%PCMfile: The file of the input signal in PCM format.
+%DATfile: The file containing the detection values in binary float format.
+%fs: The sample rate of the signal in Hertz.
+%chunkSize: The chunk size used to compute the detection values in seconds.
+[x, tx] = readPCM(PCMfile, fs);
+[d, td] = readDetection(DATfile, fs, chunkSize);
+plot(tx, x, td, d);
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/test/readDetection.m b/third_party/libwebrtc/modules/audio_processing/transient/test/readDetection.m
new file mode 100644
index 0000000000..832bf31ec8
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/test/readDetection.m
@@ -0,0 +1,26 @@
+%
+% Copyright (c) 2014 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.
+%
+
+function [d, t] = readDetection(file, fs, chunkSize)
+%[d, t] = readDetection(file, fs, chunkSize)
+%
+%Reads a detection signal from a DAT file.
+%
+%d: The detection signal.
+%t: The respective time vector.
+%
+%file: The DAT file where the detection signal is stored in float format.
+%fs: The signal sample rate in Hertz.
+%chunkSize: The chunk size used for the detection in seconds.
+fid = fopen(file);
+d = fread(fid, inf, 'float');
+fclose(fid);
+t = 0:(1 / fs):(length(d) * chunkSize - 1 / fs);
+d = d(floor(t / chunkSize) + 1);
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/test/readPCM.m b/third_party/libwebrtc/modules/audio_processing/transient/test/readPCM.m
new file mode 100644
index 0000000000..cd3cef8a3c
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/test/readPCM.m
@@ -0,0 +1,26 @@
+%
+% Copyright (c) 2014 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.
+%
+
+function [x, t] = readPCM(file, fs)
+%[x, t] = readPCM(file, fs)
+%
+%Reads a signal from a PCM file.
+%
+%x: The read signal after normalization.
+%t: The respective time vector.
+%
+%file: The PCM file where the signal is stored in int16 format.
+%fs: The signal sample rate in Hertz.
+fid = fopen(file);
+x = fread(fid, inf, 'int16');
+fclose(fid);
+x = x - mean(x);
+x = x / max(abs(x));
+t = 0:(1 / fs):((length(x) - 1) / fs);
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_detector.cc b/third_party/libwebrtc/modules/audio_processing/transient/transient_detector.cc
new file mode 100644
index 0000000000..5c35505368
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_detector.cc
@@ -0,0 +1,176 @@
+/*
+ * 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 "modules/audio_processing/transient/transient_detector.h"
+
+#include <float.h>
+#include <string.h>
+
+#include <algorithm>
+#include <cmath>
+
+#include "modules/audio_processing/transient/common.h"
+#include "modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h"
+#include "modules/audio_processing/transient/moving_moments.h"
+#include "modules/audio_processing/transient/wpd_node.h"
+#include "modules/audio_processing/transient/wpd_tree.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+static const int kTransientLengthMs = 30;
+static const int kChunksAtStartupLeftToDelete =
+ kTransientLengthMs / ts::kChunkSizeMs;
+static const float kDetectThreshold = 16.f;
+
+TransientDetector::TransientDetector(int sample_rate_hz)
+ : samples_per_chunk_(sample_rate_hz * ts::kChunkSizeMs / 1000),
+ last_first_moment_(),
+ last_second_moment_(),
+ chunks_at_startup_left_to_delete_(kChunksAtStartupLeftToDelete),
+ reference_energy_(1.f),
+ using_reference_(false) {
+ RTC_DCHECK(sample_rate_hz == ts::kSampleRate8kHz ||
+ sample_rate_hz == ts::kSampleRate16kHz ||
+ sample_rate_hz == ts::kSampleRate32kHz ||
+ sample_rate_hz == ts::kSampleRate48kHz);
+ int samples_per_transient = sample_rate_hz * kTransientLengthMs / 1000;
+ // Adjustment to avoid data loss while downsampling, making
+ // `samples_per_chunk_` and `samples_per_transient` always divisible by
+ // `kLeaves`.
+ samples_per_chunk_ -= samples_per_chunk_ % kLeaves;
+ samples_per_transient -= samples_per_transient % kLeaves;
+
+ tree_leaves_data_length_ = samples_per_chunk_ / kLeaves;
+ wpd_tree_.reset(new WPDTree(samples_per_chunk_,
+ kDaubechies8HighPassCoefficients,
+ kDaubechies8LowPassCoefficients,
+ kDaubechies8CoefficientsLength, kLevels));
+ for (size_t i = 0; i < kLeaves; ++i) {
+ moving_moments_[i].reset(
+ new MovingMoments(samples_per_transient / kLeaves));
+ }
+
+ first_moments_.reset(new float[tree_leaves_data_length_]);
+ second_moments_.reset(new float[tree_leaves_data_length_]);
+
+ for (int i = 0; i < kChunksAtStartupLeftToDelete; ++i) {
+ previous_results_.push_back(0.f);
+ }
+}
+
+TransientDetector::~TransientDetector() {}
+
+float TransientDetector::Detect(const float* data,
+ size_t data_length,
+ const float* reference_data,
+ size_t reference_length) {
+ RTC_DCHECK(data);
+ RTC_DCHECK_EQ(samples_per_chunk_, data_length);
+
+ // TODO(aluebs): Check if these errors can logically happen and if not assert
+ // on them.
+ if (wpd_tree_->Update(data, samples_per_chunk_) != 0) {
+ return -1.f;
+ }
+
+ float result = 0.f;
+
+ for (size_t i = 0; i < kLeaves; ++i) {
+ WPDNode* leaf = wpd_tree_->NodeAt(kLevels, i);
+
+ moving_moments_[i]->CalculateMoments(leaf->data(), tree_leaves_data_length_,
+ first_moments_.get(),
+ second_moments_.get());
+
+ // Add value delayed (Use the last moments from the last call to Detect).
+ float unbiased_data = leaf->data()[0] - last_first_moment_[i];
+ result +=
+ unbiased_data * unbiased_data / (last_second_moment_[i] + FLT_MIN);
+
+ // Add new values.
+ for (size_t j = 1; j < tree_leaves_data_length_; ++j) {
+ unbiased_data = leaf->data()[j] - first_moments_[j - 1];
+ result +=
+ unbiased_data * unbiased_data / (second_moments_[j - 1] + FLT_MIN);
+ }
+
+ last_first_moment_[i] = first_moments_[tree_leaves_data_length_ - 1];
+ last_second_moment_[i] = second_moments_[tree_leaves_data_length_ - 1];
+ }
+
+ result /= tree_leaves_data_length_;
+
+ result *= ReferenceDetectionValue(reference_data, reference_length);
+
+ if (chunks_at_startup_left_to_delete_ > 0) {
+ chunks_at_startup_left_to_delete_--;
+ result = 0.f;
+ }
+
+ if (result >= kDetectThreshold) {
+ result = 1.f;
+ } else {
+ // Get proportional value.
+ // Proportion achieved with a squared raised cosine function with domain
+ // [0, kDetectThreshold) and image [0, 1), it's always increasing.
+ const float horizontal_scaling = ts::kPi / kDetectThreshold;
+ const float kHorizontalShift = ts::kPi;
+ const float kVerticalScaling = 0.5f;
+ const float kVerticalShift = 1.f;
+
+ result = (std::cos(result * horizontal_scaling + kHorizontalShift) +
+ kVerticalShift) *
+ kVerticalScaling;
+ result *= result;
+ }
+
+ previous_results_.pop_front();
+ previous_results_.push_back(result);
+
+ // In the current implementation we return the max of the current result and
+ // the previous results, so the high results have a width equals to
+ // `transient_length`.
+ return *std::max_element(previous_results_.begin(), previous_results_.end());
+}
+
+// Looks for the highest slope and compares it with the previous ones.
+// An exponential transformation takes this to the [0, 1] range. This value is
+// multiplied by the detection result to avoid false positives.
+float TransientDetector::ReferenceDetectionValue(const float* data,
+ size_t length) {
+ if (data == NULL) {
+ using_reference_ = false;
+ return 1.f;
+ }
+ static const float kEnergyRatioThreshold = 0.2f;
+ static const float kReferenceNonLinearity = 20.f;
+ static const float kMemory = 0.99f;
+ float reference_energy = 0.f;
+ for (size_t i = 1; i < length; ++i) {
+ reference_energy += data[i] * data[i];
+ }
+ if (reference_energy == 0.f) {
+ using_reference_ = false;
+ return 1.f;
+ }
+ RTC_DCHECK_NE(0, reference_energy_);
+ float result = 1.f / (1.f + std::exp(kReferenceNonLinearity *
+ (kEnergyRatioThreshold -
+ reference_energy / reference_energy_)));
+ reference_energy_ =
+ kMemory * reference_energy_ + (1.f - kMemory) * reference_energy;
+
+ using_reference_ = true;
+
+ return result;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_detector.h b/third_party/libwebrtc/modules/audio_processing/transient/transient_detector.h
new file mode 100644
index 0000000000..a3dbb7ffde
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_detector.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
+
+#include <stddef.h>
+
+#include <deque>
+#include <memory>
+
+#include "modules/audio_processing/transient/moving_moments.h"
+#include "modules/audio_processing/transient/wpd_tree.h"
+
+namespace webrtc {
+
+// This is an implementation of the transient detector described in "Causal
+// Wavelet based transient detector".
+// Calculates the log-likelihood of a transient to happen on a signal at any
+// given time based on the previous samples; it uses a WPD tree to analyze the
+// signal. It preserves its state, so it can be multiple-called.
+class TransientDetector {
+ public:
+ // TODO(chadan): The only supported wavelet is Daubechies 8 using a WPD tree
+ // of 3 levels. Make an overloaded constructor to allow different wavelets and
+ // depths of the tree. When needed.
+
+ // Creates a wavelet based transient detector.
+ TransientDetector(int sample_rate_hz);
+
+ ~TransientDetector();
+
+ // Calculates the log-likelihood of the existence of a transient in `data`.
+ // `data_length` has to be equal to `samples_per_chunk_`.
+ // Returns a value between 0 and 1, as a non linear representation of this
+ // likelihood.
+ // Returns a negative value on error.
+ float Detect(const float* data,
+ size_t data_length,
+ const float* reference_data,
+ size_t reference_length);
+
+ bool using_reference() { return using_reference_; }
+
+ private:
+ float ReferenceDetectionValue(const float* data, size_t length);
+
+ static const size_t kLevels = 3;
+ static const size_t kLeaves = 1 << kLevels;
+
+ size_t samples_per_chunk_;
+
+ std::unique_ptr<WPDTree> wpd_tree_;
+ size_t tree_leaves_data_length_;
+
+ // A MovingMoments object is needed for each leaf in the WPD tree.
+ std::unique_ptr<MovingMoments> moving_moments_[kLeaves];
+
+ std::unique_ptr<float[]> first_moments_;
+ std::unique_ptr<float[]> second_moments_;
+
+ // Stores the last calculated moments from the previous detection.
+ float last_first_moment_[kLeaves];
+ float last_second_moment_[kLeaves];
+
+ // We keep track of the previous results from the previous chunks, so it can
+ // be used to effectively give results according to the `transient_length`.
+ std::deque<float> previous_results_;
+
+ // Number of chunks that are going to return only zeros at the beginning of
+ // the detection. It helps to avoid infs and nans due to the lack of
+ // information.
+ int chunks_at_startup_left_to_delete_;
+
+ float reference_energy_;
+
+ bool using_reference_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_DETECTOR_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_detector_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/transient_detector_unittest.cc
new file mode 100644
index 0000000000..a7364626fd
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_detector_unittest.cc
@@ -0,0 +1,95 @@
+/*
+ * 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 "modules/audio_processing/transient/transient_detector.h"
+
+#include <memory>
+#include <string>
+
+#include "modules/audio_processing/transient/common.h"
+#include "modules/audio_processing/transient/file_utils.h"
+#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/system/file_wrapper.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+static const int kSampleRatesHz[] = {ts::kSampleRate8kHz, ts::kSampleRate16kHz,
+ ts::kSampleRate32kHz,
+ ts::kSampleRate48kHz};
+static const size_t kNumberOfSampleRates =
+ sizeof(kSampleRatesHz) / sizeof(*kSampleRatesHz);
+
+// This test is for the correctness of the transient detector.
+// Checks the results comparing them with the ones stored in the detect files in
+// the directory: resources/audio_processing/transient/
+// The files contain all the results in double precision (Little endian).
+// The audio files used with different sample rates are stored in the same
+// directory.
+#if defined(WEBRTC_IOS)
+TEST(TransientDetectorTest, DISABLED_CorrectnessBasedOnFiles) {
+#else
+TEST(TransientDetectorTest, CorrectnessBasedOnFiles) {
+#endif
+ for (size_t i = 0; i < kNumberOfSampleRates; ++i) {
+ int sample_rate_hz = kSampleRatesHz[i];
+
+ // Prepare detect file.
+ rtc::StringBuilder detect_file_name;
+ detect_file_name << "audio_processing/transient/detect"
+ << (sample_rate_hz / 1000) << "kHz";
+
+ FileWrapper detect_file = FileWrapper::OpenReadOnly(
+ test::ResourcePath(detect_file_name.str(), "dat"));
+
+ bool file_opened = detect_file.is_open();
+ ASSERT_TRUE(file_opened) << "File could not be opened.\n"
+ << detect_file_name.str().c_str();
+
+ // Prepare audio file.
+ rtc::StringBuilder audio_file_name;
+ audio_file_name << "audio_processing/transient/audio"
+ << (sample_rate_hz / 1000) << "kHz";
+
+ FileWrapper audio_file = FileWrapper::OpenReadOnly(
+ test::ResourcePath(audio_file_name.str(), "pcm"));
+
+ // Create detector.
+ TransientDetector detector(sample_rate_hz);
+
+ const size_t buffer_length = sample_rate_hz * ts::kChunkSizeMs / 1000;
+ std::unique_ptr<float[]> buffer(new float[buffer_length]);
+
+ const float kTolerance = 0.02f;
+
+ size_t frames_read = 0;
+
+ while (ReadInt16FromFileToFloatBuffer(&audio_file, buffer_length,
+ buffer.get()) == buffer_length) {
+ ++frames_read;
+
+ float detector_value =
+ detector.Detect(buffer.get(), buffer_length, NULL, 0);
+ double file_value;
+ ASSERT_EQ(1u, ReadDoubleBufferFromFile(&detect_file, 1, &file_value))
+ << "Detect test file is malformed.\n";
+
+ // Compare results with data from the matlab test file.
+ EXPECT_NEAR(file_value, detector_value, kTolerance)
+ << "Frame: " << frames_read;
+ }
+
+ detect_file.Close();
+ audio_file.Close();
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_suppression_test.cc b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppression_test.cc
new file mode 100644
index 0000000000..2d8baf9416
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppression_test.cc
@@ -0,0 +1,238 @@
+/*
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "common_audio/include/audio_util.h"
+#include "modules/audio_processing/agc/agc.h"
+#include "modules/audio_processing/transient/transient_suppressor.h"
+#include "modules/audio_processing/transient/transient_suppressor_impl.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+ABSL_FLAG(std::string, in_file_name, "", "PCM file that contains the signal.");
+ABSL_FLAG(std::string,
+ detection_file_name,
+ "",
+ "PCM file that contains the detection signal.");
+ABSL_FLAG(std::string,
+ reference_file_name,
+ "",
+ "PCM file that contains the reference signal.");
+
+ABSL_FLAG(int,
+ chunk_size_ms,
+ 10,
+ "Time between each chunk of samples in milliseconds.");
+
+ABSL_FLAG(int,
+ sample_rate_hz,
+ 16000,
+ "Sampling frequency of the signal in Hertz.");
+ABSL_FLAG(int,
+ detection_rate_hz,
+ 0,
+ "Sampling frequency of the detection signal in Hertz.");
+
+ABSL_FLAG(int, num_channels, 1, "Number of channels.");
+
+namespace webrtc {
+
+const char kUsage[] =
+ "\nDetects and suppresses transients from file.\n\n"
+ "This application loads the signal from the in_file_name with a specific\n"
+ "num_channels and sample_rate_hz, the detection signal from the\n"
+ "detection_file_name with a specific detection_rate_hz, and the reference\n"
+ "signal from the reference_file_name with sample_rate_hz, divides them\n"
+ "into chunk_size_ms blocks, computes its voice value and depending on the\n"
+ "voice_threshold does the respective restoration. You can always get the\n"
+ "all-voiced or all-unvoiced cases by setting the voice_threshold to 0 or\n"
+ "1 respectively.\n\n";
+
+// Read next buffers from the test files (signed 16-bit host-endian PCM
+// format). audio_buffer has int16 samples, detection_buffer has float samples
+// with range [-32768,32767], and reference_buffer has float samples with range
+// [-1,1]. Return true iff all the buffers were filled completely.
+bool ReadBuffers(FILE* in_file,
+ size_t audio_buffer_size,
+ int num_channels,
+ int16_t* audio_buffer,
+ FILE* detection_file,
+ size_t detection_buffer_size,
+ float* detection_buffer,
+ FILE* reference_file,
+ float* reference_buffer) {
+ std::unique_ptr<int16_t[]> tmpbuf;
+ int16_t* read_ptr = audio_buffer;
+ if (num_channels > 1) {
+ tmpbuf.reset(new int16_t[num_channels * audio_buffer_size]);
+ read_ptr = tmpbuf.get();
+ }
+ if (fread(read_ptr, sizeof(*read_ptr), num_channels * audio_buffer_size,
+ in_file) != num_channels * audio_buffer_size) {
+ return false;
+ }
+ // De-interleave.
+ if (num_channels > 1) {
+ for (int i = 0; i < num_channels; ++i) {
+ for (size_t j = 0; j < audio_buffer_size; ++j) {
+ audio_buffer[i * audio_buffer_size + j] =
+ read_ptr[i + j * num_channels];
+ }
+ }
+ }
+ if (detection_file) {
+ std::unique_ptr<int16_t[]> ibuf(new int16_t[detection_buffer_size]);
+ if (fread(ibuf.get(), sizeof(ibuf[0]), detection_buffer_size,
+ detection_file) != detection_buffer_size)
+ return false;
+ for (size_t i = 0; i < detection_buffer_size; ++i)
+ detection_buffer[i] = ibuf[i];
+ }
+ if (reference_file) {
+ std::unique_ptr<int16_t[]> ibuf(new int16_t[audio_buffer_size]);
+ if (fread(ibuf.get(), sizeof(ibuf[0]), audio_buffer_size, reference_file) !=
+ audio_buffer_size)
+ return false;
+ S16ToFloat(ibuf.get(), audio_buffer_size, reference_buffer);
+ }
+ return true;
+}
+
+// Write a number of samples to an open signed 16-bit host-endian PCM file.
+static void WritePCM(FILE* f,
+ size_t num_samples,
+ int num_channels,
+ const float* buffer) {
+ std::unique_ptr<int16_t[]> ibuf(new int16_t[num_channels * num_samples]);
+ // Interleave.
+ for (int i = 0; i < num_channels; ++i) {
+ for (size_t j = 0; j < num_samples; ++j) {
+ ibuf[i + j * num_channels] = FloatS16ToS16(buffer[i * num_samples + j]);
+ }
+ }
+ fwrite(ibuf.get(), sizeof(ibuf[0]), num_channels * num_samples, f);
+}
+
+// This application tests the transient suppression by providing a processed
+// PCM file, which has to be listened to in order to evaluate the
+// performance.
+// It gets an audio file, and its voice gain information, and the suppressor
+// process it giving the output file "suppressed_keystrokes.pcm".
+void void_main() {
+ // TODO(aluebs): Remove all FileWrappers.
+ // Prepare the input file.
+ FILE* in_file = fopen(absl::GetFlag(FLAGS_in_file_name).c_str(), "rb");
+ ASSERT_TRUE(in_file != NULL);
+
+ // Prepare the detection file.
+ FILE* detection_file = NULL;
+ if (!absl::GetFlag(FLAGS_detection_file_name).empty()) {
+ detection_file =
+ fopen(absl::GetFlag(FLAGS_detection_file_name).c_str(), "rb");
+ }
+
+ // Prepare the reference file.
+ FILE* reference_file = NULL;
+ if (!absl::GetFlag(FLAGS_reference_file_name).empty()) {
+ reference_file =
+ fopen(absl::GetFlag(FLAGS_reference_file_name).c_str(), "rb");
+ }
+
+ // Prepare the output file.
+ std::string out_file_name = test::OutputPath() + "suppressed_keystrokes.pcm";
+ FILE* out_file = fopen(out_file_name.c_str(), "wb");
+ ASSERT_TRUE(out_file != NULL);
+
+ int detection_rate_hz = absl::GetFlag(FLAGS_detection_rate_hz);
+ if (detection_rate_hz == 0) {
+ detection_rate_hz = absl::GetFlag(FLAGS_sample_rate_hz);
+ }
+
+ Agc agc;
+
+ TransientSuppressorImpl suppressor(TransientSuppressor::VadMode::kDefault,
+ absl::GetFlag(FLAGS_sample_rate_hz),
+ detection_rate_hz,
+ absl::GetFlag(FLAGS_num_channels));
+
+ const size_t audio_buffer_size = absl::GetFlag(FLAGS_chunk_size_ms) *
+ absl::GetFlag(FLAGS_sample_rate_hz) / 1000;
+ const size_t detection_buffer_size =
+ absl::GetFlag(FLAGS_chunk_size_ms) * detection_rate_hz / 1000;
+
+ // int16 and float variants of the same data.
+ std::unique_ptr<int16_t[]> audio_buffer_i(
+ new int16_t[absl::GetFlag(FLAGS_num_channels) * audio_buffer_size]);
+ std::unique_ptr<float[]> audio_buffer_f(
+ new float[absl::GetFlag(FLAGS_num_channels) * audio_buffer_size]);
+
+ std::unique_ptr<float[]> detection_buffer, reference_buffer;
+
+ if (detection_file)
+ detection_buffer.reset(new float[detection_buffer_size]);
+ if (reference_file)
+ reference_buffer.reset(new float[audio_buffer_size]);
+
+ while (ReadBuffers(
+ in_file, audio_buffer_size, absl::GetFlag(FLAGS_num_channels),
+ audio_buffer_i.get(), detection_file, detection_buffer_size,
+ detection_buffer.get(), reference_file, reference_buffer.get())) {
+ agc.Process({audio_buffer_i.get(), audio_buffer_size});
+
+ for (size_t i = 0;
+ i < absl::GetFlag(FLAGS_num_channels) * audio_buffer_size; ++i) {
+ audio_buffer_f[i] = audio_buffer_i[i];
+ }
+
+ suppressor.Suppress(audio_buffer_f.get(), audio_buffer_size,
+ absl::GetFlag(FLAGS_num_channels),
+ detection_buffer.get(), detection_buffer_size,
+ reference_buffer.get(), audio_buffer_size,
+ agc.voice_probability(), true);
+
+ // Write result to out file.
+ WritePCM(out_file, audio_buffer_size, absl::GetFlag(FLAGS_num_channels),
+ audio_buffer_f.get());
+ }
+
+ fclose(in_file);
+ if (detection_file) {
+ fclose(detection_file);
+ }
+ if (reference_file) {
+ fclose(reference_file);
+ }
+ fclose(out_file);
+}
+
+} // namespace webrtc
+
+int main(int argc, char* argv[]) {
+ std::vector<char*> args = absl::ParseCommandLine(argc, argv);
+ if (args.size() != 1) {
+ printf("%s", webrtc::kUsage);
+ return 1;
+ }
+ RTC_CHECK_GT(absl::GetFlag(FLAGS_chunk_size_ms), 0);
+ RTC_CHECK_GT(absl::GetFlag(FLAGS_sample_rate_hz), 0);
+ RTC_CHECK_GT(absl::GetFlag(FLAGS_num_channels), 0);
+
+ webrtc::void_main();
+ return 0;
+}
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor.h b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor.h
new file mode 100644
index 0000000000..ecb3c3baab
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2020 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_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
+
+#include <cstddef>
+
+namespace webrtc {
+
+// Detects transients in an audio stream and suppress them using a simple
+// restoration algorithm that attenuates unexpected spikes in the spectrum.
+class TransientSuppressor {
+ public:
+ // Type of VAD used by the caller to compute the `voice_probability` argument
+ // `Suppress()`.
+ enum class VadMode {
+ // By default, `TransientSuppressor` assumes that `voice_probability` is
+ // computed by `AgcManagerDirect`.
+ kDefault = 0,
+ // Use this mode when `TransientSuppressor` must assume that
+ // `voice_probability` is computed by the RNN VAD.
+ kRnnVad,
+ // Use this mode to let `TransientSuppressor::Suppressor()` ignore
+ // `voice_probability` and behave as if voice information is unavailable
+ // (regardless of the passed value).
+ kNoVad,
+ };
+
+ virtual ~TransientSuppressor() {}
+
+ virtual void Initialize(int sample_rate_hz,
+ int detector_rate_hz,
+ int num_channels) = 0;
+
+ // Processes a `data` chunk, and returns it with keystrokes suppressed from
+ // it. The float format is assumed to be int16 ranged. If there are more than
+ // one channel, the chunks are concatenated one after the other in `data`.
+ // `data_length` must be equal to `data_length_`.
+ // `num_channels` must be equal to `num_channels_`.
+ // A sub-band, ideally the higher, can be used as `detection_data`. If it is
+ // NULL, `data` is used for the detection too. The `detection_data` is always
+ // assumed mono.
+ // If a reference signal (e.g. keyboard microphone) is available, it can be
+ // passed in as `reference_data`. It is assumed mono and must have the same
+ // length as `data`. NULL is accepted if unavailable.
+ // This suppressor performs better if voice information is available.
+ // `voice_probability` is the probability of voice being present in this chunk
+ // of audio. If voice information is not available, `voice_probability` must
+ // always be set to 1.
+ // `key_pressed` determines if a key was pressed on this audio chunk.
+ // Returns a delayed version of `voice_probability` according to the
+ // algorithmic delay introduced by this method. In this way, the modified
+ // `data` and the returned voice probability will be temporally aligned.
+ virtual float Suppress(float* data,
+ size_t data_length,
+ int num_channels,
+ const float* detection_data,
+ size_t detection_length,
+ const float* reference_data,
+ size_t reference_length,
+ float voice_probability,
+ bool key_pressed) = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_api_gn/moz.build b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_api_gn/moz.build
new file mode 100644
index 0000000000..5988e89a6a
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_api_gn/moz.build
@@ -0,0 +1,201 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("transient_suppressor_api_gn")
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.cc b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.cc
new file mode 100644
index 0000000000..90428464e3
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.cc
@@ -0,0 +1,455 @@
+/*
+ * 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 "modules/audio_processing/transient/transient_suppressor_impl.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cmath>
+#include <complex>
+#include <deque>
+#include <limits>
+#include <set>
+#include <string>
+
+#include "common_audio/include/audio_util.h"
+#include "common_audio/signal_processing/include/signal_processing_library.h"
+#include "common_audio/third_party/ooura/fft_size_256/fft4g.h"
+#include "modules/audio_processing/transient/common.h"
+#include "modules/audio_processing/transient/transient_detector.h"
+#include "modules/audio_processing/transient/transient_suppressor.h"
+#include "modules/audio_processing/transient/windows_private.h"
+#include "rtc_base/checks.h"
+#include "rtc_base/logging.h"
+
+namespace webrtc {
+
+static const float kMeanIIRCoefficient = 0.5f;
+
+// TODO(aluebs): Check if these values work also for 48kHz.
+static const size_t kMinVoiceBin = 3;
+static const size_t kMaxVoiceBin = 60;
+
+namespace {
+
+float ComplexMagnitude(float a, float b) {
+ return std::abs(a) + std::abs(b);
+}
+
+std::string GetVadModeLabel(TransientSuppressor::VadMode vad_mode) {
+ switch (vad_mode) {
+ case TransientSuppressor::VadMode::kDefault:
+ return "default";
+ case TransientSuppressor::VadMode::kRnnVad:
+ return "RNN VAD";
+ case TransientSuppressor::VadMode::kNoVad:
+ return "no VAD";
+ }
+}
+
+} // namespace
+
+TransientSuppressorImpl::TransientSuppressorImpl(VadMode vad_mode,
+ int sample_rate_hz,
+ int detector_rate_hz,
+ int num_channels)
+ : vad_mode_(vad_mode),
+ voice_probability_delay_unit_(/*delay_num_samples=*/0, sample_rate_hz),
+ analyzed_audio_is_silent_(false),
+ data_length_(0),
+ detection_length_(0),
+ analysis_length_(0),
+ buffer_delay_(0),
+ complex_analysis_length_(0),
+ num_channels_(0),
+ window_(NULL),
+ detector_smoothed_(0.f),
+ keypress_counter_(0),
+ chunks_since_keypress_(0),
+ detection_enabled_(false),
+ suppression_enabled_(false),
+ use_hard_restoration_(false),
+ chunks_since_voice_change_(0),
+ seed_(182),
+ using_reference_(false) {
+ RTC_LOG(LS_INFO) << "VAD mode: " << GetVadModeLabel(vad_mode_);
+ Initialize(sample_rate_hz, detector_rate_hz, num_channels);
+}
+
+TransientSuppressorImpl::~TransientSuppressorImpl() {}
+
+void TransientSuppressorImpl::Initialize(int sample_rate_hz,
+ int detection_rate_hz,
+ int num_channels) {
+ RTC_DCHECK(sample_rate_hz == ts::kSampleRate8kHz ||
+ sample_rate_hz == ts::kSampleRate16kHz ||
+ sample_rate_hz == ts::kSampleRate32kHz ||
+ sample_rate_hz == ts::kSampleRate48kHz);
+ RTC_DCHECK(detection_rate_hz == ts::kSampleRate8kHz ||
+ detection_rate_hz == ts::kSampleRate16kHz ||
+ detection_rate_hz == ts::kSampleRate32kHz ||
+ detection_rate_hz == ts::kSampleRate48kHz);
+ RTC_DCHECK_GT(num_channels, 0);
+
+ switch (sample_rate_hz) {
+ case ts::kSampleRate8kHz:
+ analysis_length_ = 128u;
+ window_ = kBlocks80w128;
+ break;
+ case ts::kSampleRate16kHz:
+ analysis_length_ = 256u;
+ window_ = kBlocks160w256;
+ break;
+ case ts::kSampleRate32kHz:
+ analysis_length_ = 512u;
+ window_ = kBlocks320w512;
+ break;
+ case ts::kSampleRate48kHz:
+ analysis_length_ = 1024u;
+ window_ = kBlocks480w1024;
+ break;
+ default:
+ RTC_DCHECK_NOTREACHED();
+ return;
+ }
+
+ detector_.reset(new TransientDetector(detection_rate_hz));
+ data_length_ = sample_rate_hz * ts::kChunkSizeMs / 1000;
+ RTC_DCHECK_LE(data_length_, analysis_length_);
+ buffer_delay_ = analysis_length_ - data_length_;
+
+ voice_probability_delay_unit_.Initialize(/*delay_num_samples=*/buffer_delay_,
+ sample_rate_hz);
+
+ complex_analysis_length_ = analysis_length_ / 2 + 1;
+ RTC_DCHECK_GE(complex_analysis_length_, kMaxVoiceBin);
+ num_channels_ = num_channels;
+ in_buffer_.reset(new float[analysis_length_ * num_channels_]);
+ memset(in_buffer_.get(), 0,
+ analysis_length_ * num_channels_ * sizeof(in_buffer_[0]));
+ detection_length_ = detection_rate_hz * ts::kChunkSizeMs / 1000;
+ detection_buffer_.reset(new float[detection_length_]);
+ memset(detection_buffer_.get(), 0,
+ detection_length_ * sizeof(detection_buffer_[0]));
+ out_buffer_.reset(new float[analysis_length_ * num_channels_]);
+ memset(out_buffer_.get(), 0,
+ analysis_length_ * num_channels_ * sizeof(out_buffer_[0]));
+ // ip[0] must be zero to trigger initialization using rdft().
+ size_t ip_length = 2 + sqrtf(analysis_length_);
+ ip_.reset(new size_t[ip_length]());
+ memset(ip_.get(), 0, ip_length * sizeof(ip_[0]));
+ wfft_.reset(new float[complex_analysis_length_ - 1]);
+ memset(wfft_.get(), 0, (complex_analysis_length_ - 1) * sizeof(wfft_[0]));
+ spectral_mean_.reset(new float[complex_analysis_length_ * num_channels_]);
+ memset(spectral_mean_.get(), 0,
+ complex_analysis_length_ * num_channels_ * sizeof(spectral_mean_[0]));
+ fft_buffer_.reset(new float[analysis_length_ + 2]);
+ memset(fft_buffer_.get(), 0, (analysis_length_ + 2) * sizeof(fft_buffer_[0]));
+ magnitudes_.reset(new float[complex_analysis_length_]);
+ memset(magnitudes_.get(), 0,
+ complex_analysis_length_ * sizeof(magnitudes_[0]));
+ mean_factor_.reset(new float[complex_analysis_length_]);
+
+ static const float kFactorHeight = 10.f;
+ static const float kLowSlope = 1.f;
+ static const float kHighSlope = 0.3f;
+ for (size_t i = 0; i < complex_analysis_length_; ++i) {
+ mean_factor_[i] =
+ kFactorHeight /
+ (1.f + std::exp(kLowSlope * static_cast<int>(i - kMinVoiceBin))) +
+ kFactorHeight /
+ (1.f + std::exp(kHighSlope * static_cast<int>(kMaxVoiceBin - i)));
+ }
+ detector_smoothed_ = 0.f;
+ keypress_counter_ = 0;
+ chunks_since_keypress_ = 0;
+ detection_enabled_ = false;
+ suppression_enabled_ = false;
+ use_hard_restoration_ = false;
+ chunks_since_voice_change_ = 0;
+ seed_ = 182;
+ using_reference_ = false;
+}
+
+float TransientSuppressorImpl::Suppress(float* data,
+ size_t data_length,
+ int num_channels,
+ const float* detection_data,
+ size_t detection_length,
+ const float* reference_data,
+ size_t reference_length,
+ float voice_probability,
+ bool key_pressed) {
+ if (!data || data_length != data_length_ || num_channels != num_channels_ ||
+ detection_length != detection_length_ || voice_probability < 0 ||
+ voice_probability > 1) {
+ // The audio is not modified, so the voice probability is returned as is
+ // (delay not applied).
+ return voice_probability;
+ }
+
+ UpdateKeypress(key_pressed);
+ UpdateBuffers(data);
+
+ if (detection_enabled_) {
+ UpdateRestoration(voice_probability);
+
+ if (!detection_data) {
+ // Use the input data of the first channel if special detection data is
+ // not supplied.
+ detection_data = &in_buffer_[buffer_delay_];
+ }
+
+ float detector_result = detector_->Detect(detection_data, detection_length,
+ reference_data, reference_length);
+ if (detector_result < 0) {
+ // The audio is not modified, so the voice probability is returned as is
+ // (delay not applied).
+ return voice_probability;
+ }
+
+ using_reference_ = detector_->using_reference();
+
+ // `detector_smoothed_` follows the `detector_result` when this last one is
+ // increasing, but has an exponential decaying tail to be able to suppress
+ // the ringing of keyclicks.
+ float smooth_factor = using_reference_ ? 0.6 : 0.1;
+ detector_smoothed_ = detector_result >= detector_smoothed_
+ ? detector_result
+ : smooth_factor * detector_smoothed_ +
+ (1 - smooth_factor) * detector_result;
+
+ for (int i = 0; i < num_channels_; ++i) {
+ Suppress(&in_buffer_[i * analysis_length_],
+ &spectral_mean_[i * complex_analysis_length_],
+ &out_buffer_[i * analysis_length_]);
+ }
+ }
+
+ // If the suppression isn't enabled, we use the in buffer to delay the signal
+ // appropriately. This also gives time for the out buffer to be refreshed with
+ // new data between detection and suppression getting enabled.
+ for (int i = 0; i < num_channels_; ++i) {
+ memcpy(&data[i * data_length_],
+ suppression_enabled_ ? &out_buffer_[i * analysis_length_]
+ : &in_buffer_[i * analysis_length_],
+ data_length_ * sizeof(*data));
+ }
+
+ // The audio has been modified, return the delayed voice probability.
+ return voice_probability_delay_unit_.Delay(voice_probability);
+}
+
+// This should only be called when detection is enabled. UpdateBuffers() must
+// have been called. At return, `out_buffer_` will be filled with the
+// processed output.
+void TransientSuppressorImpl::Suppress(float* in_ptr,
+ float* spectral_mean,
+ float* out_ptr) {
+ // Go to frequency domain.
+ for (size_t i = 0; i < analysis_length_; ++i) {
+ // TODO(aluebs): Rename windows
+ fft_buffer_[i] = in_ptr[i] * window_[i];
+ }
+
+ WebRtc_rdft(analysis_length_, 1, fft_buffer_.get(), ip_.get(), wfft_.get());
+
+ // Since WebRtc_rdft puts R[n/2] in fft_buffer_[1], we move it to the end
+ // for convenience.
+ fft_buffer_[analysis_length_] = fft_buffer_[1];
+ fft_buffer_[analysis_length_ + 1] = 0.f;
+ fft_buffer_[1] = 0.f;
+
+ for (size_t i = 0; i < complex_analysis_length_; ++i) {
+ magnitudes_[i] =
+ ComplexMagnitude(fft_buffer_[i * 2], fft_buffer_[i * 2 + 1]);
+ }
+ // Restore audio if necessary.
+ if (suppression_enabled_) {
+ if (use_hard_restoration_) {
+ HardRestoration(spectral_mean);
+ } else {
+ SoftRestoration(spectral_mean);
+ }
+ }
+
+ // Update the spectral mean.
+ for (size_t i = 0; i < complex_analysis_length_; ++i) {
+ spectral_mean[i] = (1 - kMeanIIRCoefficient) * spectral_mean[i] +
+ kMeanIIRCoefficient * magnitudes_[i];
+ }
+
+ // Back to time domain.
+ // Put R[n/2] back in fft_buffer_[1].
+ fft_buffer_[1] = fft_buffer_[analysis_length_];
+
+ WebRtc_rdft(analysis_length_, -1, fft_buffer_.get(), ip_.get(), wfft_.get());
+ const float fft_scaling = 2.f / analysis_length_;
+
+ for (size_t i = 0; i < analysis_length_; ++i) {
+ out_ptr[i] += fft_buffer_[i] * window_[i] * fft_scaling;
+ }
+}
+
+void TransientSuppressorImpl::UpdateKeypress(bool key_pressed) {
+ const int kKeypressPenalty = 1000 / ts::kChunkSizeMs;
+ const int kIsTypingThreshold = 1000 / ts::kChunkSizeMs;
+ const int kChunksUntilNotTyping = 4000 / ts::kChunkSizeMs; // 4 seconds.
+
+ if (key_pressed) {
+ keypress_counter_ += kKeypressPenalty;
+ chunks_since_keypress_ = 0;
+ detection_enabled_ = true;
+ }
+ keypress_counter_ = std::max(0, keypress_counter_ - 1);
+
+ if (keypress_counter_ > kIsTypingThreshold) {
+ if (!suppression_enabled_) {
+ RTC_LOG(LS_INFO) << "[ts] Transient suppression is now enabled.";
+ }
+ suppression_enabled_ = true;
+ keypress_counter_ = 0;
+ }
+
+ if (detection_enabled_ && ++chunks_since_keypress_ > kChunksUntilNotTyping) {
+ if (suppression_enabled_) {
+ RTC_LOG(LS_INFO) << "[ts] Transient suppression is now disabled.";
+ }
+ detection_enabled_ = false;
+ suppression_enabled_ = false;
+ keypress_counter_ = 0;
+ }
+}
+
+void TransientSuppressorImpl::UpdateRestoration(float voice_probability) {
+ bool not_voiced;
+ switch (vad_mode_) {
+ case TransientSuppressor::VadMode::kDefault: {
+ constexpr float kVoiceThreshold = 0.02f;
+ not_voiced = voice_probability < kVoiceThreshold;
+ break;
+ }
+ case TransientSuppressor::VadMode::kRnnVad: {
+ constexpr float kVoiceThreshold = 0.7f;
+ not_voiced = voice_probability < kVoiceThreshold;
+ break;
+ }
+ case TransientSuppressor::VadMode::kNoVad:
+ // Always assume that voice is detected.
+ not_voiced = false;
+ break;
+ }
+
+ if (not_voiced == use_hard_restoration_) {
+ chunks_since_voice_change_ = 0;
+ } else {
+ ++chunks_since_voice_change_;
+
+ // Number of 10 ms frames to wait to transition to and from hard
+ // restoration.
+ constexpr int kHardRestorationOffsetDelay = 3;
+ constexpr int kHardRestorationOnsetDelay = 80;
+
+ if ((use_hard_restoration_ &&
+ chunks_since_voice_change_ > kHardRestorationOffsetDelay) ||
+ (!use_hard_restoration_ &&
+ chunks_since_voice_change_ > kHardRestorationOnsetDelay)) {
+ use_hard_restoration_ = not_voiced;
+ chunks_since_voice_change_ = 0;
+ }
+ }
+}
+
+// Shift buffers to make way for new data. Must be called after
+// `detection_enabled_` is updated by UpdateKeypress().
+void TransientSuppressorImpl::UpdateBuffers(float* data) {
+ // TODO(aluebs): Change to ring buffer.
+ memmove(in_buffer_.get(), &in_buffer_[data_length_],
+ (buffer_delay_ + (num_channels_ - 1) * analysis_length_) *
+ sizeof(in_buffer_[0]));
+ // Copy new chunk to buffer.
+ for (int i = 0; i < num_channels_; ++i) {
+ memcpy(&in_buffer_[buffer_delay_ + i * analysis_length_],
+ &data[i * data_length_], data_length_ * sizeof(*data));
+ }
+ if (detection_enabled_) {
+ // Shift previous chunk in out buffer.
+ memmove(out_buffer_.get(), &out_buffer_[data_length_],
+ (buffer_delay_ + (num_channels_ - 1) * analysis_length_) *
+ sizeof(out_buffer_[0]));
+ // Initialize new chunk in out buffer.
+ for (int i = 0; i < num_channels_; ++i) {
+ memset(&out_buffer_[buffer_delay_ + i * analysis_length_], 0,
+ data_length_ * sizeof(out_buffer_[0]));
+ }
+ }
+}
+
+// Restores the unvoiced signal if a click is present.
+// Attenuates by a certain factor every peak in the `fft_buffer_` that exceeds
+// the spectral mean. The attenuation depends on `detector_smoothed_`.
+// If a restoration takes place, the `magnitudes_` are updated to the new value.
+void TransientSuppressorImpl::HardRestoration(float* spectral_mean) {
+ const float detector_result =
+ 1.f - std::pow(1.f - detector_smoothed_, using_reference_ ? 200.f : 50.f);
+ // To restore, we get the peaks in the spectrum. If higher than the previous
+ // spectral mean we adjust them.
+ for (size_t i = 0; i < complex_analysis_length_; ++i) {
+ if (magnitudes_[i] > spectral_mean[i] && magnitudes_[i] > 0) {
+ // RandU() generates values on [0, int16::max()]
+ const float phase = 2 * ts::kPi * WebRtcSpl_RandU(&seed_) /
+ std::numeric_limits<int16_t>::max();
+ const float scaled_mean = detector_result * spectral_mean[i];
+
+ fft_buffer_[i * 2] = (1 - detector_result) * fft_buffer_[i * 2] +
+ scaled_mean * cosf(phase);
+ fft_buffer_[i * 2 + 1] = (1 - detector_result) * fft_buffer_[i * 2 + 1] +
+ scaled_mean * sinf(phase);
+ magnitudes_[i] = magnitudes_[i] -
+ detector_result * (magnitudes_[i] - spectral_mean[i]);
+ }
+ }
+}
+
+// Restores the voiced signal if a click is present.
+// Attenuates by a certain factor every peak in the `fft_buffer_` that exceeds
+// the spectral mean and that is lower than some function of the current block
+// frequency mean. The attenuation depends on `detector_smoothed_`.
+// If a restoration takes place, the `magnitudes_` are updated to the new value.
+void TransientSuppressorImpl::SoftRestoration(float* spectral_mean) {
+ // Get the spectral magnitude mean of the current block.
+ float block_frequency_mean = 0;
+ for (size_t i = kMinVoiceBin; i < kMaxVoiceBin; ++i) {
+ block_frequency_mean += magnitudes_[i];
+ }
+ block_frequency_mean /= (kMaxVoiceBin - kMinVoiceBin);
+
+ // To restore, we get the peaks in the spectrum. If higher than the
+ // previous spectral mean and lower than a factor of the block mean
+ // we adjust them. The factor is a double sigmoid that has a minimum in the
+ // voice frequency range (300Hz - 3kHz).
+ for (size_t i = 0; i < complex_analysis_length_; ++i) {
+ if (magnitudes_[i] > spectral_mean[i] && magnitudes_[i] > 0 &&
+ (using_reference_ ||
+ magnitudes_[i] < block_frequency_mean * mean_factor_[i])) {
+ const float new_magnitude =
+ magnitudes_[i] -
+ detector_smoothed_ * (magnitudes_[i] - spectral_mean[i]);
+ const float magnitude_ratio = new_magnitude / magnitudes_[i];
+
+ fft_buffer_[i * 2] *= magnitude_ratio;
+ fft_buffer_[i * 2 + 1] *= magnitude_ratio;
+ magnitudes_[i] = new_magnitude;
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.h b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.h
new file mode 100644
index 0000000000..4005a16b0a
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.h
@@ -0,0 +1,115 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <memory>
+
+#include "modules/audio_processing/transient/transient_suppressor.h"
+#include "modules/audio_processing/transient/voice_probability_delay_unit.h"
+#include "rtc_base/gtest_prod_util.h"
+
+namespace webrtc {
+
+class TransientDetector;
+
+// Detects transients in an audio stream and suppress them using a simple
+// restoration algorithm that attenuates unexpected spikes in the spectrum.
+class TransientSuppressorImpl : public TransientSuppressor {
+ public:
+ TransientSuppressorImpl(VadMode vad_mode,
+ int sample_rate_hz,
+ int detector_rate_hz,
+ int num_channels);
+ ~TransientSuppressorImpl() override;
+
+ void Initialize(int sample_rate_hz,
+ int detector_rate_hz,
+ int num_channels) override;
+
+ float Suppress(float* data,
+ size_t data_length,
+ int num_channels,
+ const float* detection_data,
+ size_t detection_length,
+ const float* reference_data,
+ size_t reference_length,
+ float voice_probability,
+ bool key_pressed) override;
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(TransientSuppressorVadModeParametrization,
+ TypingDetectionLogicWorksAsExpectedForMono);
+ void Suppress(float* in_ptr, float* spectral_mean, float* out_ptr);
+
+ void UpdateKeypress(bool key_pressed);
+ void UpdateRestoration(float voice_probability);
+
+ void UpdateBuffers(float* data);
+
+ void HardRestoration(float* spectral_mean);
+ void SoftRestoration(float* spectral_mean);
+
+ const VadMode vad_mode_;
+ VoiceProbabilityDelayUnit voice_probability_delay_unit_;
+
+ std::unique_ptr<TransientDetector> detector_;
+
+ bool analyzed_audio_is_silent_;
+
+ size_t data_length_;
+ size_t detection_length_;
+ size_t analysis_length_;
+ size_t buffer_delay_;
+ size_t complex_analysis_length_;
+ int num_channels_;
+ // Input buffer where the original samples are stored.
+ std::unique_ptr<float[]> in_buffer_;
+ std::unique_ptr<float[]> detection_buffer_;
+ // Output buffer where the restored samples are stored.
+ std::unique_ptr<float[]> out_buffer_;
+
+ // Arrays for fft.
+ std::unique_ptr<size_t[]> ip_;
+ std::unique_ptr<float[]> wfft_;
+
+ std::unique_ptr<float[]> spectral_mean_;
+
+ // Stores the data for the fft.
+ std::unique_ptr<float[]> fft_buffer_;
+
+ std::unique_ptr<float[]> magnitudes_;
+
+ const float* window_;
+
+ std::unique_ptr<float[]> mean_factor_;
+
+ float detector_smoothed_;
+
+ int keypress_counter_;
+ int chunks_since_keypress_;
+ bool detection_enabled_;
+ bool suppression_enabled_;
+
+ bool use_hard_restoration_;
+ int chunks_since_voice_change_;
+
+ uint32_t seed_;
+
+ bool using_reference_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_TRANSIENT_SUPPRESSOR_IMPL_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl_gn/moz.build b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl_gn/moz.build
new file mode 100644
index 0000000000..ee6b82a2f6
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl_gn/moz.build
@@ -0,0 +1,236 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/modules/audio_processing/transient/moving_moments.cc",
+ "/third_party/libwebrtc/modules/audio_processing/transient/transient_detector.cc",
+ "/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_impl.cc",
+ "/third_party/libwebrtc/modules/audio_processing/transient/wpd_node.cc",
+ "/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "rt"
+ ]
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+ OS_LIBS += [
+ "crypt32",
+ "iphlpapi",
+ "secur32",
+ "winmm"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("transient_suppressor_impl_gn")
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_unittest.cc
new file mode 100644
index 0000000000..ab48504af6
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/transient_suppressor_unittest.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright (c) 2014 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/transient/transient_suppressor.h"
+
+#include <vector>
+
+#include "absl/types/optional.h"
+#include "modules/audio_processing/transient/common.h"
+#include "modules/audio_processing/transient/transient_suppressor_impl.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+constexpr int kMono = 1;
+
+// Returns the index of the first non-zero sample in `samples` or an unspecified
+// value if no value is zero.
+absl::optional<int> FindFirstNonZeroSample(const std::vector<float>& samples) {
+ for (size_t i = 0; i < samples.size(); ++i) {
+ if (samples[i] != 0.0f) {
+ return i;
+ }
+ }
+ return absl::nullopt;
+}
+
+} // namespace
+
+class TransientSuppressorVadModeParametrization
+ : public ::testing::TestWithParam<TransientSuppressor::VadMode> {};
+
+TEST_P(TransientSuppressorVadModeParametrization,
+ TypingDetectionLogicWorksAsExpectedForMono) {
+ TransientSuppressorImpl ts(GetParam(), ts::kSampleRate16kHz,
+ ts::kSampleRate16kHz, kMono);
+
+ // Each key-press enables detection.
+ EXPECT_FALSE(ts.detection_enabled_);
+ ts.UpdateKeypress(true);
+ EXPECT_TRUE(ts.detection_enabled_);
+
+ // It takes four seconds without any key-press to disable the detection
+ for (int time_ms = 0; time_ms < 3990; time_ms += ts::kChunkSizeMs) {
+ ts.UpdateKeypress(false);
+ EXPECT_TRUE(ts.detection_enabled_);
+ }
+ ts.UpdateKeypress(false);
+ EXPECT_FALSE(ts.detection_enabled_);
+
+ // Key-presses that are more than a second apart from each other don't enable
+ // suppression.
+ for (int i = 0; i < 100; ++i) {
+ EXPECT_FALSE(ts.suppression_enabled_);
+ ts.UpdateKeypress(true);
+ EXPECT_TRUE(ts.detection_enabled_);
+ EXPECT_FALSE(ts.suppression_enabled_);
+ for (int time_ms = 0; time_ms < 990; time_ms += ts::kChunkSizeMs) {
+ ts.UpdateKeypress(false);
+ EXPECT_TRUE(ts.detection_enabled_);
+ EXPECT_FALSE(ts.suppression_enabled_);
+ }
+ ts.UpdateKeypress(false);
+ }
+
+ // Two consecutive key-presses is enough to enable the suppression.
+ ts.UpdateKeypress(true);
+ EXPECT_FALSE(ts.suppression_enabled_);
+ ts.UpdateKeypress(true);
+ EXPECT_TRUE(ts.suppression_enabled_);
+
+ // Key-presses that are less than a second apart from each other don't disable
+ // detection nor suppression.
+ for (int i = 0; i < 100; ++i) {
+ for (int time_ms = 0; time_ms < 1000; time_ms += ts::kChunkSizeMs) {
+ ts.UpdateKeypress(false);
+ EXPECT_TRUE(ts.detection_enabled_);
+ EXPECT_TRUE(ts.suppression_enabled_);
+ }
+ ts.UpdateKeypress(true);
+ EXPECT_TRUE(ts.detection_enabled_);
+ EXPECT_TRUE(ts.suppression_enabled_);
+ }
+
+ // It takes four seconds without any key-press to disable the detection and
+ // suppression.
+ for (int time_ms = 0; time_ms < 3990; time_ms += ts::kChunkSizeMs) {
+ ts.UpdateKeypress(false);
+ EXPECT_TRUE(ts.detection_enabled_);
+ EXPECT_TRUE(ts.suppression_enabled_);
+ }
+ for (int time_ms = 0; time_ms < 1000; time_ms += ts::kChunkSizeMs) {
+ ts.UpdateKeypress(false);
+ EXPECT_FALSE(ts.detection_enabled_);
+ EXPECT_FALSE(ts.suppression_enabled_);
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ TransientSuppressorImplTest,
+ TransientSuppressorVadModeParametrization,
+ ::testing::Values(TransientSuppressor::VadMode::kDefault,
+ TransientSuppressor::VadMode::kRnnVad,
+ TransientSuppressor::VadMode::kNoVad));
+
+class TransientSuppressorSampleRateParametrization
+ : public ::testing::TestWithParam<int> {};
+
+// Checks that voice probability and processed audio data are temporally aligned
+// after `Suppress()` is called.
+TEST_P(TransientSuppressorSampleRateParametrization,
+ CheckAudioAndVoiceProbabilityTemporallyAligned) {
+ const int sample_rate_hz = GetParam();
+ TransientSuppressorImpl ts(TransientSuppressor::VadMode::kDefault,
+ sample_rate_hz,
+ /*detection_rate_hz=*/sample_rate_hz, kMono);
+
+ const int frame_size = sample_rate_hz * ts::kChunkSizeMs / 1000;
+ std::vector<float> frame(frame_size);
+
+ constexpr int kMaxAttempts = 3;
+ for (int i = 0; i < kMaxAttempts; ++i) {
+ SCOPED_TRACE(i);
+
+ // Call `Suppress()` on frames of non-zero audio samples.
+ std::fill(frame.begin(), frame.end(), 1000.0f);
+ float delayed_voice_probability = ts.Suppress(
+ frame.data(), frame.size(), kMono, /*detection_data=*/nullptr,
+ /*detection_length=*/frame_size, /*reference_data=*/nullptr,
+ /*reference_length=*/frame_size, /*voice_probability=*/1.0f,
+ /*key_pressed=*/false);
+
+ // Detect the algorithmic delay of `TransientSuppressorImpl`.
+ absl::optional<int> frame_delay = FindFirstNonZeroSample(frame);
+
+ // Check that the delayed voice probability is delayed according to the
+ // measured delay.
+ if (frame_delay.has_value()) {
+ if (*frame_delay == 0) {
+ // When the delay is a multiple integer of the frame duration,
+ // `Suppress()` returns a copy of a previously observed voice
+ // probability value.
+ EXPECT_EQ(delayed_voice_probability, 1.0f);
+ } else {
+ // Instead, when the delay is fractional, `Suppress()` returns an
+ // interpolated value. Since the exact value depends on the
+ // interpolation method, we only check that the delayed voice
+ // probability is not zero as it must converge towards the previoulsy
+ // observed value.
+ EXPECT_GT(delayed_voice_probability, 0.0f);
+ }
+ break;
+ } else {
+ // The algorithmic delay is longer than the duration of a single frame.
+ // Until the delay is detected, the delayed voice probability is zero.
+ EXPECT_EQ(delayed_voice_probability, 0.0f);
+ }
+ }
+}
+
+INSTANTIATE_TEST_SUITE_P(TransientSuppressorImplTest,
+ TransientSuppressorSampleRateParametrization,
+ ::testing::Values(ts::kSampleRate8kHz,
+ ts::kSampleRate16kHz,
+ ts::kSampleRate32kHz,
+ ts::kSampleRate48kHz));
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.cc b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.cc
new file mode 100644
index 0000000000..27b2b42b38
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2022 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/transient/voice_probability_delay_unit.h"
+
+#include <array>
+
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+VoiceProbabilityDelayUnit::VoiceProbabilityDelayUnit(int delay_num_samples,
+ int sample_rate_hz) {
+ Initialize(delay_num_samples, sample_rate_hz);
+}
+
+void VoiceProbabilityDelayUnit::Initialize(int delay_num_samples,
+ int sample_rate_hz) {
+ RTC_DCHECK_GE(delay_num_samples, 0);
+ RTC_DCHECK_LE(delay_num_samples, sample_rate_hz / 50)
+ << "The implementation does not support delays greater than 20 ms.";
+ int frame_size = rtc::CheckedDivExact(sample_rate_hz, 100); // 10 ms.
+ if (delay_num_samples <= frame_size) {
+ weights_[0] = 0.0f;
+ weights_[1] = static_cast<float>(delay_num_samples) / frame_size;
+ weights_[2] =
+ static_cast<float>(frame_size - delay_num_samples) / frame_size;
+ } else {
+ delay_num_samples -= frame_size;
+ weights_[0] = static_cast<float>(delay_num_samples) / frame_size;
+ weights_[1] =
+ static_cast<float>(frame_size - delay_num_samples) / frame_size;
+ weights_[2] = 0.0f;
+ }
+
+ // Resets the delay unit.
+ last_probabilities_.fill(0.0f);
+}
+
+float VoiceProbabilityDelayUnit::Delay(float voice_probability) {
+ float weighted_probability = weights_[0] * last_probabilities_[0] +
+ weights_[1] * last_probabilities_[1] +
+ weights_[2] * voice_probability;
+ last_probabilities_[0] = last_probabilities_[1];
+ last_probabilities_[1] = voice_probability;
+ return weighted_probability;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.h b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.h
new file mode 100644
index 0000000000..05961663e3
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2022 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_TRANSIENT_VOICE_PROBABILITY_DELAY_UNIT_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_VOICE_PROBABILITY_DELAY_UNIT_H_
+
+#include <array>
+
+namespace webrtc {
+
+// Iteratively produces a sequence of delayed voice probability values given a
+// fixed delay between 0 and 20 ms and given a sequence of voice probability
+// values observed every 10 ms. Supports fractional delays, that are delays
+// which are not a multiple integer of 10 ms. Applies interpolation with
+// fractional delays; otherwise, returns a previously observed value according
+// to the given fixed delay.
+class VoiceProbabilityDelayUnit {
+ public:
+ // Ctor. `delay_num_samples` is the delay in number of samples and it must be
+ // non-negative and less than 20 ms.
+ VoiceProbabilityDelayUnit(int delay_num_samples, int sample_rate_hz);
+
+ // Handles delay and sample rate changes and resets the delay unit.
+ void Initialize(int delay_num_samples, int sample_rate_hz);
+
+ // Observes `voice_probability` and returns a delayed voice probability.
+ float Delay(float voice_probability);
+
+ private:
+ std::array<float, 3> weights_;
+ std::array<float, 2> last_probabilities_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_VOICE_PROBABILITY_DELAY_UNIT_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_gn/moz.build b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_gn/moz.build
new file mode 100644
index 0000000000..e2abcb8490
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_gn/moz.build
@@ -0,0 +1,221 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+
+ ### This moz.build was AUTOMATICALLY GENERATED from a GN config, ###
+ ### DO NOT edit it by hand. ###
+
+COMPILE_FLAGS["OS_INCLUDES"] = []
+AllowCompilerWarnings()
+
+DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1"
+DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True
+DEFINES["RTC_ENABLE_VP9"] = True
+DEFINES["WEBRTC_ENABLE_PROTOBUF"] = "0"
+DEFINES["WEBRTC_LIBRARY_IMPL"] = True
+DEFINES["WEBRTC_MOZILLA_BUILD"] = True
+DEFINES["WEBRTC_NON_STATIC_TRACE_EVENT_HANDLERS"] = "0"
+DEFINES["WEBRTC_STRICT_FIELD_TRIALS"] = "0"
+
+FINAL_LIBRARY = "webrtc"
+
+
+LOCAL_INCLUDES += [
+ "!/ipc/ipdl/_ipdlheaders",
+ "!/third_party/libwebrtc/gen",
+ "/ipc/chromium/src",
+ "/third_party/libwebrtc/",
+ "/third_party/libwebrtc/third_party/abseil-cpp/",
+ "/tools/profiler/public"
+]
+
+UNIFIED_SOURCES += [
+ "/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit.cc"
+]
+
+if not CONFIG["MOZ_DEBUG"]:
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "0"
+ DEFINES["NDEBUG"] = True
+ DEFINES["NVALGRIND"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1":
+
+ DEFINES["DYNAMIC_ANNOTATIONS_ENABLED"] = "1"
+
+if CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["ANDROID"] = True
+ DEFINES["ANDROID_NDK_VERSION_ROLL"] = "r22_1"
+ DEFINES["HAVE_SYS_UIO_H"] = True
+ DEFINES["WEBRTC_ANDROID"] = True
+ DEFINES["WEBRTC_ANDROID_OPENSLES"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_GNU_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+ OS_LIBS += [
+ "log"
+ ]
+
+if CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["WEBRTC_MAC"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_LIBCPP_HAS_NO_ALIGNED_ALLOCATION"] = True
+ DEFINES["__ASSERT_MACROS_DEFINE_VERSIONS_WITHOUT_UNDERSCORES"] = "0"
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_NSS_CERTS"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_UDEV"] = True
+ DEFINES["WEBRTC_LINUX"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["USE_GLIB"] = "1"
+ DEFINES["USE_OZONE"] = "1"
+ DEFINES["USE_X11"] = "1"
+ DEFINES["WEBRTC_BSD"] = True
+ DEFINES["WEBRTC_POSIX"] = True
+ DEFINES["_FILE_OFFSET_BITS"] = "64"
+ DEFINES["_LARGEFILE64_SOURCE"] = True
+ DEFINES["_LARGEFILE_SOURCE"] = True
+ DEFINES["__STDC_CONSTANT_MACROS"] = True
+ DEFINES["__STDC_FORMAT_MACROS"] = True
+
+if CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["CERT_CHAIN_PARA_HAS_EXTRA_FIELDS"] = True
+ DEFINES["NOMINMAX"] = True
+ DEFINES["NTDDI_VERSION"] = "0x0A000000"
+ DEFINES["PSAPI_VERSION"] = "2"
+ DEFINES["UNICODE"] = True
+ DEFINES["USE_AURA"] = "1"
+ DEFINES["WEBRTC_WIN"] = True
+ DEFINES["WIN32"] = True
+ DEFINES["WIN32_LEAN_AND_MEAN"] = True
+ DEFINES["WINAPI_FAMILY"] = "WINAPI_FAMILY_DESKTOP_APP"
+ DEFINES["WINVER"] = "0x0A00"
+ DEFINES["_ATL_NO_OPENGL"] = True
+ DEFINES["_CRT_RAND_S"] = True
+ DEFINES["_CRT_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_ENABLE_EXTENDED_ALIGNED_STORAGE"] = True
+ DEFINES["_HAS_EXCEPTIONS"] = "0"
+ DEFINES["_HAS_NODISCARD"] = True
+ DEFINES["_SCL_SECURE_NO_DEPRECATE"] = True
+ DEFINES["_SECURE_ATL"] = True
+ DEFINES["_UNICODE"] = True
+ DEFINES["_WIN32_WINNT"] = "0x0A00"
+ DEFINES["_WINDOWS"] = True
+ DEFINES["__STD_C"] = True
+
+if CONFIG["CPU_ARCH"] == "aarch64":
+
+ DEFINES["WEBRTC_ARCH_ARM64"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "arm":
+
+ CXXFLAGS += [
+ "-mfpu=neon"
+ ]
+
+ DEFINES["WEBRTC_ARCH_ARM"] = True
+ DEFINES["WEBRTC_ARCH_ARM_V7"] = True
+ DEFINES["WEBRTC_HAS_NEON"] = True
+
+if CONFIG["CPU_ARCH"] == "mips32":
+
+ DEFINES["MIPS32_LE"] = True
+ DEFINES["MIPS_FPU_LE"] = True
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "mips64":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64":
+
+ DEFINES["WEBRTC_ENABLE_AVX2"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Android":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Darwin":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "OpenBSD":
+
+ DEFINES["_DEBUG"] = True
+
+if CONFIG["MOZ_DEBUG"] == "1" and CONFIG["OS_TARGET"] == "WINNT":
+
+ DEFINES["_HAS_ITERATOR_DEBUGGING"] = "0"
+
+if CONFIG["MOZ_X11"] == "1" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["USE_X11"] = "1"
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android":
+
+ OS_LIBS += [
+ "android_support",
+ "unwind"
+ ]
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Android":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ OS_LIBS += [
+ "android_support"
+ ]
+
+if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux":
+
+ CXXFLAGS += [
+ "-msse2"
+ ]
+
+ DEFINES["_GNU_SOURCE"] = True
+
+if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux":
+
+ DEFINES["_GNU_SOURCE"] = True
+
+Library("voice_probability_delay_unit_gn")
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc
new file mode 100644
index 0000000000..04848e6f2c
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/voice_probability_delay_unit_unittest.cc
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2022 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/transient/voice_probability_delay_unit.h"
+
+#include "test/gtest.h"
+
+namespace webrtc {
+namespace {
+
+// Checks that with zero delay, the observed value is immediately returned as
+// delayed value.
+TEST(VoiceProbabilityDelayUnit, NoDelay) {
+ VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/0,
+ /*sample_rate_hz=*/48000);
+ constexpr int kMax = 5;
+ for (int i = 0; i <= kMax; ++i) {
+ SCOPED_TRACE(i);
+ float voice_probability = static_cast<float>(i) / kMax;
+ EXPECT_EQ(voice_probability, delay_unit.Delay(voice_probability));
+ }
+}
+
+// Checks that with integer delays, an exact copy of a previously observed value
+// is returned.
+TEST(VoiceProbabilityDelayUnit, IntegerDelay) {
+ VoiceProbabilityDelayUnit delay_unit_10ms(/*delay_num_samples=*/480,
+ /*sample_rate_hz=*/48000);
+ delay_unit_10ms.Delay(0.125f);
+ EXPECT_EQ(0.125f, delay_unit_10ms.Delay(0.9f));
+
+ VoiceProbabilityDelayUnit delay_unit_20ms(/*delay_num_samples=*/960,
+ /*sample_rate_hz=*/48000);
+ delay_unit_20ms.Delay(0.125f);
+ delay_unit_20ms.Delay(0.8f);
+ EXPECT_EQ(0.125f, delay_unit_20ms.Delay(0.9f));
+}
+
+// Checks that with a fractional delay < 10 ms, interpolation is applied.
+TEST(VoiceProbabilityDelayUnit, FractionalDelayLessThan10ms) {
+ // Create delay unit with fractional delay of 6 ms.
+ VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/288,
+ /*sample_rate_hz=*/48000);
+ // frame 0
+ // --------- frame 1
+ // ---------
+ // 0000001111
+ delay_unit.Delay(1.0f);
+ EXPECT_FLOAT_EQ(0.68f, delay_unit.Delay(0.2f));
+}
+
+// Checks that with a fractional delay > 10 ms, interpolation is applied.
+TEST(VoiceProbabilityDelayUnit, FractionalDelayGreaterThan10ms) {
+ // Create delay unit with fractional delay of 14 ms.
+ VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/672,
+ /*sample_rate_hz=*/48000);
+ // frame 0
+ // --------- frame 1
+ // --------- frame 2
+ // ---------
+ // 0000111111
+ delay_unit.Delay(1.0f);
+ delay_unit.Delay(0.2f);
+ EXPECT_FLOAT_EQ(0.52f, delay_unit.Delay(1.0f));
+}
+
+// Checks that `Initialize()` resets the delay unit.
+TEST(VoiceProbabilityDelayUnit, InitializeResetsDelayUnit) {
+ VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/960,
+ /*sample_rate_hz=*/48000);
+ delay_unit.Delay(1.0f);
+ delay_unit.Delay(0.9f);
+
+ delay_unit.Initialize(/*delay_num_samples=*/160, /*sample_rate_hz=*/8000);
+ EXPECT_EQ(0.0f, delay_unit.Delay(0.1f));
+ EXPECT_EQ(0.0f, delay_unit.Delay(0.2f));
+ EXPECT_EQ(0.1f, delay_unit.Delay(0.3f));
+}
+
+// Checks that `Initialize()` handles delay changes.
+TEST(VoiceProbabilityDelayUnit, InitializeHandlesDelayChanges) {
+ // Start with a 20 ms delay.
+ VoiceProbabilityDelayUnit delay_unit(/*delay_num_samples=*/960,
+ /*sample_rate_hz=*/48000);
+ delay_unit.Delay(1.0f);
+ delay_unit.Delay(0.9f);
+
+ // Lower the delay to 10 ms.
+ delay_unit.Initialize(/*delay_num_samples=*/80, /*sample_rate_hz=*/8000);
+ EXPECT_EQ(0.0f, delay_unit.Delay(0.1f));
+ EXPECT_EQ(0.1f, delay_unit.Delay(0.2f));
+
+ // Increase the delay to 15 ms.
+ delay_unit.Initialize(/*delay_num_samples=*/120, /*sample_rate_hz=*/8000);
+ EXPECT_EQ(0.0f, delay_unit.Delay(0.1f));
+ EXPECT_EQ(0.05f, delay_unit.Delay(0.2f));
+ EXPECT_EQ(0.15f, delay_unit.Delay(0.3f));
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/windows_private.h b/third_party/libwebrtc/modules/audio_processing/transient/windows_private.h
new file mode 100644
index 0000000000..54e3c25785
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/windows_private.h
@@ -0,0 +1,557 @@
+/*
+ * 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_TRANSIENT_WINDOWS_PRIVATE_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_
+
+namespace webrtc {
+
+// 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};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WINDOWS_PRIVATE_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/wpd_node.cc b/third_party/libwebrtc/modules/audio_processing/transient/wpd_node.cc
new file mode 100644
index 0000000000..2e0ee7e5b7
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/wpd_node.cc
@@ -0,0 +1,72 @@
+/*
+ * 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 "modules/audio_processing/transient/wpd_node.h"
+
+#include <math.h>
+#include <string.h>
+
+#include "common_audio/fir_filter.h"
+#include "common_audio/fir_filter_factory.h"
+#include "modules/audio_processing/transient/dyadic_decimator.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+WPDNode::WPDNode(size_t length,
+ const float* coefficients,
+ size_t coefficients_length)
+ : // The data buffer has parent data length to be able to contain and
+ // filter it.
+ data_(new float[2 * length + 1]),
+ length_(length),
+ filter_(
+ CreateFirFilter(coefficients, coefficients_length, 2 * length + 1)) {
+ RTC_DCHECK_GT(length, 0);
+ RTC_DCHECK(coefficients);
+ RTC_DCHECK_GT(coefficients_length, 0);
+ memset(data_.get(), 0.f, (2 * length + 1) * sizeof(data_[0]));
+}
+
+WPDNode::~WPDNode() {}
+
+int WPDNode::Update(const float* parent_data, size_t parent_data_length) {
+ if (!parent_data || (parent_data_length / 2) != length_) {
+ return -1;
+ }
+
+ // Filter data.
+ filter_->Filter(parent_data, parent_data_length, data_.get());
+
+ // Decimate data.
+ const bool kOddSequence = true;
+ size_t output_samples = DyadicDecimate(data_.get(), parent_data_length,
+ kOddSequence, data_.get(), length_);
+ if (output_samples != length_) {
+ return -1;
+ }
+
+ // Get abs to all values.
+ for (size_t i = 0; i < length_; ++i) {
+ data_[i] = fabs(data_[i]);
+ }
+
+ return 0;
+}
+
+int WPDNode::set_data(const float* new_data, size_t length) {
+ if (!new_data || length != length_) {
+ return -1;
+ }
+ memcpy(data_.get(), new_data, length * sizeof(data_[0]));
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/wpd_node.h b/third_party/libwebrtc/modules/audio_processing/transient/wpd_node.h
new file mode 100644
index 0000000000..41614fab0f
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/wpd_node.h
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
+
+#include <memory>
+
+namespace webrtc {
+
+class FIRFilter;
+
+// A single node of a Wavelet Packet Decomposition (WPD) tree.
+class WPDNode {
+ public:
+ // Creates a WPDNode. The data vector will contain zeros. The filter will have
+ // the coefficients provided.
+ WPDNode(size_t length, const float* coefficients, size_t coefficients_length);
+ ~WPDNode();
+
+ // Updates the node data. `parent_data` / 2 must be equals to `length_`.
+ // Returns 0 if correct, and -1 otherwise.
+ int Update(const float* parent_data, size_t parent_data_length);
+
+ const float* data() const { return data_.get(); }
+ // Returns 0 if correct, and -1 otherwise.
+ int set_data(const float* new_data, size_t length);
+ size_t length() const { return length_; }
+
+ private:
+ std::unique_ptr<float[]> data_;
+ size_t length_;
+ std::unique_ptr<FIRFilter> filter_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_NODE_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/wpd_node_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/wpd_node_unittest.cc
new file mode 100644
index 0000000000..5f9238255c
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/wpd_node_unittest.cc
@@ -0,0 +1,64 @@
+/*
+ * 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 "modules/audio_processing/transient/wpd_node.h"
+
+#include <string.h>
+
+#include "test/gtest.h"
+
+namespace webrtc {
+
+static const size_t kDataLength = 5;
+static const float kTolerance = 0.0001f;
+
+static const size_t kParentDataLength = kDataLength * 2;
+static const float kParentData[kParentDataLength] = {1.f, 2.f, 3.f, 4.f, 5.f,
+ 6.f, 7.f, 8.f, 9.f, 10.f};
+
+static const float kCoefficients[] = {0.2f, -0.3f, 0.5f, -0.7f, 0.11f};
+static const size_t kCoefficientsLength =
+ sizeof(kCoefficients) / sizeof(kCoefficients[0]);
+
+TEST(WPDNodeTest, Accessors) {
+ WPDNode node(kDataLength, kCoefficients, kCoefficientsLength);
+ EXPECT_EQ(0, node.set_data(kParentData, kDataLength));
+ EXPECT_EQ(0, memcmp(node.data(), kParentData,
+ kDataLength * sizeof(node.data()[0])));
+}
+
+TEST(WPDNodeTest, UpdateThatOnlyDecimates) {
+ const float kIndentyCoefficient = 1.f;
+ WPDNode node(kDataLength, &kIndentyCoefficient, 1);
+ EXPECT_EQ(0, node.Update(kParentData, kParentDataLength));
+ for (size_t i = 0; i < kDataLength; ++i) {
+ EXPECT_FLOAT_EQ(kParentData[i * 2 + 1], node.data()[i]);
+ }
+}
+
+TEST(WPDNodeTest, UpdateWithArbitraryDataAndArbitraryFilter) {
+ WPDNode node(kDataLength, kCoefficients, kCoefficientsLength);
+ EXPECT_EQ(0, node.Update(kParentData, kParentDataLength));
+ EXPECT_NEAR(0.1f, node.data()[0], kTolerance);
+ EXPECT_NEAR(0.2f, node.data()[1], kTolerance);
+ EXPECT_NEAR(0.18f, node.data()[2], kTolerance);
+ EXPECT_NEAR(0.56f, node.data()[3], kTolerance);
+ EXPECT_NEAR(0.94f, node.data()[4], kTolerance);
+}
+
+TEST(WPDNodeTest, ExpectedErrorReturnValue) {
+ WPDNode node(kDataLength, kCoefficients, kCoefficientsLength);
+ EXPECT_EQ(-1, node.Update(kParentData, kParentDataLength - 1));
+ EXPECT_EQ(-1, node.Update(NULL, kParentDataLength));
+ EXPECT_EQ(-1, node.set_data(kParentData, kDataLength - 1));
+ EXPECT_EQ(-1, node.set_data(NULL, kDataLength));
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.cc b/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.cc
new file mode 100644
index 0000000000..c8aa615881
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.cc
@@ -0,0 +1,118 @@
+/*
+ * 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 "modules/audio_processing/transient/wpd_tree.h"
+
+#include <string.h>
+
+#include "modules/audio_processing/transient/wpd_node.h"
+#include "rtc_base/checks.h"
+
+namespace webrtc {
+
+WPDTree::WPDTree(size_t data_length,
+ const float* high_pass_coefficients,
+ const float* low_pass_coefficients,
+ size_t coefficients_length,
+ int levels)
+ : data_length_(data_length),
+ levels_(levels),
+ num_nodes_((1 << (levels + 1)) - 1) {
+ RTC_DCHECK_GT(data_length, (static_cast<size_t>(1) << levels));
+ RTC_DCHECK(high_pass_coefficients);
+ RTC_DCHECK(low_pass_coefficients);
+ RTC_DCHECK_GT(levels, 0);
+ // Size is 1 more, so we can use the array as 1-based. nodes_[0] is never
+ // allocated.
+ nodes_.reset(new std::unique_ptr<WPDNode>[num_nodes_ + 1]);
+
+ // Create the first node
+ const float kRootCoefficient = 1.f; // Identity Coefficient.
+ nodes_[1].reset(new WPDNode(data_length, &kRootCoefficient, 1));
+ // Variables used to create the rest of the nodes.
+ size_t index = 1;
+ size_t index_left_child = 0;
+ size_t index_right_child = 0;
+
+ int num_nodes_at_curr_level = 0;
+
+ // Branching each node in each level to create its children. The last level is
+ // not branched (all the nodes of that level are leaves).
+ for (int current_level = 0; current_level < levels; ++current_level) {
+ num_nodes_at_curr_level = 1 << current_level;
+ for (int i = 0; i < num_nodes_at_curr_level; ++i) {
+ index = (1 << current_level) + i;
+ // Obtain the index of the current node children.
+ index_left_child = index * 2;
+ index_right_child = index_left_child + 1;
+ nodes_[index_left_child].reset(new WPDNode(nodes_[index]->length() / 2,
+ low_pass_coefficients,
+ coefficients_length));
+ nodes_[index_right_child].reset(new WPDNode(nodes_[index]->length() / 2,
+ high_pass_coefficients,
+ coefficients_length));
+ }
+ }
+}
+
+WPDTree::~WPDTree() {}
+
+WPDNode* WPDTree::NodeAt(int level, int index) {
+ if (level < 0 || level > levels_ || index < 0 || index >= 1 << level) {
+ return NULL;
+ }
+
+ return nodes_[(1 << level) + index].get();
+}
+
+int WPDTree::Update(const float* data, size_t data_length) {
+ if (!data || data_length != data_length_) {
+ return -1;
+ }
+
+ // Update the root node.
+ int update_result = nodes_[1]->set_data(data, data_length);
+ if (update_result != 0) {
+ return -1;
+ }
+
+ // Variables used to update the rest of the nodes.
+ size_t index = 1;
+ size_t index_left_child = 0;
+ size_t index_right_child = 0;
+
+ int num_nodes_at_curr_level = 0;
+
+ for (int current_level = 0; current_level < levels_; ++current_level) {
+ num_nodes_at_curr_level = 1 << current_level;
+ for (int i = 0; i < num_nodes_at_curr_level; ++i) {
+ index = (1 << current_level) + i;
+ // Obtain the index of the current node children.
+ index_left_child = index * 2;
+ index_right_child = index_left_child + 1;
+
+ update_result = nodes_[index_left_child]->Update(nodes_[index]->data(),
+ nodes_[index]->length());
+ if (update_result != 0) {
+ return -1;
+ }
+
+ update_result = nodes_[index_right_child]->Update(
+ nodes_[index]->data(), nodes_[index]->length());
+ if (update_result != 0) {
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.h b/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.h
new file mode 100644
index 0000000000..13cb8d9c2f
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree.h
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
+#define MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
+
+#include <stddef.h>
+
+#include <memory>
+
+#include "modules/audio_processing/transient/wpd_node.h"
+
+namespace webrtc {
+
+// Tree of a Wavelet Packet Decomposition (WPD).
+//
+// The root node contains all the data provided; for each node in the tree, the
+// left child contains the approximation coefficients extracted from the node,
+// and the right child contains the detail coefficients.
+// It preserves its state, so it can be multiple-called.
+//
+// The number of nodes in the tree will be 2 ^ levels - 1.
+//
+// Implementation details: Since the tree always will be a complete binary tree,
+// it is implemented using a single linear array instead of managing the
+// relationships in each node. For convience is better to use a array that
+// starts in 1 (instead of 0). Taking that into account, the following formulas
+// apply:
+// Root node index: 1.
+// Node(Level, Index in that level): 2 ^ Level + (Index in that level).
+// Left Child: Current node index * 2.
+// Right Child: Current node index * 2 + 1.
+// Parent: Current Node Index / 2 (Integer division).
+class WPDTree {
+ public:
+ // Creates a WPD tree using the data length and coefficients provided.
+ WPDTree(size_t data_length,
+ const float* high_pass_coefficients,
+ const float* low_pass_coefficients,
+ size_t coefficients_length,
+ int levels);
+ ~WPDTree();
+
+ // Returns the number of nodes at any given level.
+ static int NumberOfNodesAtLevel(int level) { return 1 << level; }
+
+ // Returns a pointer to the node at the given level and index(of that level).
+ // Level goes from 0 to levels().
+ // Index goes from 0 to the number of NumberOfNodesAtLevel(level) - 1.
+ //
+ // You can use the following formulas to get any node within the tree:
+ // Notation: (Level, Index of node in that level).
+ // Root node: (0/0).
+ // Left Child: (Current node level + 1, Current node index * 2).
+ // Right Child: (Current node level + 1, Current node index * 2 + 1).
+ // Parent: (Current node level - 1, Current node index / 2) (Integer division)
+ //
+ // If level or index are out of bounds the function will return NULL.
+ WPDNode* NodeAt(int level, int index);
+
+ // Updates all the nodes of the tree with the new data. `data_length` must be
+ // teh same that was used for the creation of the tree.
+ // Returns 0 if correct, and -1 otherwise.
+ int Update(const float* data, size_t data_length);
+
+ // Returns the total number of levels below the root. Root is cosidered level
+ // 0.
+ int levels() const { return levels_; }
+
+ // Returns the total number of nodes.
+ int num_nodes() const { return num_nodes_; }
+
+ // Returns the total number of leaves.
+ int num_leaves() const { return 1 << levels_; }
+
+ private:
+ size_t data_length_;
+ int levels_;
+ int num_nodes_;
+ std::unique_ptr<std::unique_ptr<WPDNode>[]> nodes_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_PROCESSING_TRANSIENT_WPD_TREE_H_
diff --git a/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree_unittest.cc b/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree_unittest.cc
new file mode 100644
index 0000000000..bf3ff987d7
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_processing/transient/wpd_tree_unittest.cc
@@ -0,0 +1,177 @@
+/*
+ * 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 "modules/audio_processing/transient/wpd_tree.h"
+
+#include <memory>
+#include <string>
+
+#include "modules/audio_processing/transient/daubechies_8_wavelet_coeffs.h"
+#include "modules/audio_processing/transient/file_utils.h"
+#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/system/file_wrapper.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+TEST(WPDTreeTest, Construction) {
+ const size_t kTestBufferSize = 100;
+ const int kLevels = 5;
+ const int kExpectedNumberOfNodes = (1 << (kLevels + 1)) - 1;
+
+ float test_buffer[kTestBufferSize];
+ memset(test_buffer, 0.f, kTestBufferSize * sizeof(*test_buffer));
+ float test_coefficients[] = {1.f, 2.f, 3.f, 4.f, 5.f};
+ const size_t kTestCoefficientsLength =
+ sizeof(test_coefficients) / sizeof(test_coefficients[0]);
+ WPDTree tree(kTestBufferSize, test_coefficients, test_coefficients,
+ kTestCoefficientsLength, kLevels);
+ ASSERT_EQ(kExpectedNumberOfNodes, tree.num_nodes());
+ // Checks for NodeAt(level, index).
+ int nodes_at_level = 0;
+ for (int level = 0; level <= kLevels; ++level) {
+ nodes_at_level = 1 << level;
+ for (int i = 0; i < nodes_at_level; ++i) {
+ ASSERT_TRUE(NULL != tree.NodeAt(level, i));
+ }
+ // Out of bounds.
+ EXPECT_EQ(NULL, tree.NodeAt(level, -1));
+ EXPECT_EQ(NULL, tree.NodeAt(level, -12));
+ EXPECT_EQ(NULL, tree.NodeAt(level, nodes_at_level));
+ EXPECT_EQ(NULL, tree.NodeAt(level, nodes_at_level + 5));
+ }
+ // Out of bounds.
+ EXPECT_EQ(NULL, tree.NodeAt(-1, 0));
+ EXPECT_EQ(NULL, tree.NodeAt(-12, 0));
+ EXPECT_EQ(NULL, tree.NodeAt(kLevels + 1, 0));
+ EXPECT_EQ(NULL, tree.NodeAt(kLevels + 5, 0));
+ // Checks for Update().
+ EXPECT_EQ(0, tree.Update(test_buffer, kTestBufferSize));
+ EXPECT_EQ(-1, tree.Update(NULL, kTestBufferSize));
+ EXPECT_EQ(-1, tree.Update(test_buffer, kTestBufferSize - 1));
+}
+
+// This test is for the correctness of the tree.
+// Checks the results from the Matlab equivalent, it is done comparing the
+// results that are stored in the output files from Matlab.
+// It also writes the results in its own set of files in the out directory.
+// Matlab and output files contain all the results in double precision (Little
+// endian) appended.
+#if defined(WEBRTC_IOS)
+TEST(WPDTreeTest, DISABLED_CorrectnessBasedOnMatlabFiles) {
+#else
+TEST(WPDTreeTest, CorrectnessBasedOnMatlabFiles) {
+#endif
+ // 10 ms at 16000 Hz.
+ const size_t kTestBufferSize = 160;
+ const int kLevels = 3;
+ const int kLeaves = 1 << kLevels;
+ const size_t kLeavesSamples = kTestBufferSize >> kLevels;
+ // Create tree with Discrete Meyer Wavelet Coefficients.
+ WPDTree tree(kTestBufferSize, kDaubechies8HighPassCoefficients,
+ kDaubechies8LowPassCoefficients, kDaubechies8CoefficientsLength,
+ kLevels);
+ // Allocate and open all matlab and out files.
+ FileWrapper matlab_files_data[kLeaves];
+ FileWrapper out_files_data[kLeaves];
+
+ for (int i = 0; i < kLeaves; ++i) {
+ // Matlab files.
+ rtc::StringBuilder matlab_stream;
+ matlab_stream << "audio_processing/transient/wpd" << i;
+ std::string matlab_string = test::ResourcePath(matlab_stream.str(), "dat");
+ matlab_files_data[i] = FileWrapper::OpenReadOnly(matlab_string);
+
+ bool file_opened = matlab_files_data[i].is_open();
+ ASSERT_TRUE(file_opened) << "File could not be opened.\n" << matlab_string;
+
+ // Out files.
+ rtc::StringBuilder out_stream;
+ out_stream << test::OutputPath() << "wpd_" << i << ".out";
+ std::string out_string = out_stream.str();
+
+ out_files_data[i] = FileWrapper::OpenWriteOnly(out_string);
+
+ file_opened = out_files_data[i].is_open();
+ ASSERT_TRUE(file_opened) << "File could not be opened.\n" << out_string;
+ }
+
+ // Prepare the test file.
+ std::string test_file_name = test::ResourcePath(
+ "audio_processing/transient/ajm-macbook-1-spke16m", "pcm");
+
+ FileWrapper test_file = FileWrapper::OpenReadOnly(test_file_name);
+
+ bool file_opened = test_file.is_open();
+ ASSERT_TRUE(file_opened) << "File could not be opened.\n" << test_file_name;
+
+ float test_buffer[kTestBufferSize];
+
+ // Only the first frames of the audio file are tested. The matlab files also
+ // only contains information about the first frames.
+ const size_t kMaxFramesToTest = 100;
+ const float kTolerance = 0.03f;
+
+ size_t frames_read = 0;
+
+ // Read first buffer from the PCM test file.
+ size_t file_samples_read =
+ ReadInt16FromFileToFloatBuffer(&test_file, kTestBufferSize, test_buffer);
+ while (file_samples_read > 0 && frames_read < kMaxFramesToTest) {
+ ++frames_read;
+
+ if (file_samples_read < kTestBufferSize) {
+ // Pad the rest of the buffer with zeros.
+ for (size_t i = file_samples_read; i < kTestBufferSize; ++i) {
+ test_buffer[i] = 0.0;
+ }
+ }
+ tree.Update(test_buffer, kTestBufferSize);
+ double matlab_buffer[kTestBufferSize];
+
+ // Compare results with data from the matlab test files.
+ for (int i = 0; i < kLeaves; ++i) {
+ // Compare data values
+ size_t matlab_samples_read = ReadDoubleBufferFromFile(
+ &matlab_files_data[i], kLeavesSamples, matlab_buffer);
+
+ ASSERT_EQ(kLeavesSamples, matlab_samples_read)
+ << "Matlab test files are malformed.\n"
+ "File: 3_"
+ << i;
+ // Get output data from the corresponding node
+ const float* node_data = tree.NodeAt(kLevels, i)->data();
+ // Compare with matlab files.
+ for (size_t j = 0; j < kLeavesSamples; ++j) {
+ EXPECT_NEAR(matlab_buffer[j], node_data[j], kTolerance)
+ << "\nLeaf: " << i << "\nSample: " << j
+ << "\nFrame: " << frames_read - 1;
+ }
+
+ // Write results to out files.
+ WriteFloatBufferToFile(&out_files_data[i], kLeavesSamples, node_data);
+ }
+
+ // Read next buffer from the PCM test file.
+ file_samples_read = ReadInt16FromFileToFloatBuffer(
+ &test_file, kTestBufferSize, test_buffer);
+ }
+
+ // Close all matlab and out files.
+ for (int i = 0; i < kLeaves; ++i) {
+ matlab_files_data[i].Close();
+ out_files_data[i].Close();
+ }
+
+ test_file.Close();
+}
+
+} // namespace webrtc