diff options
Diffstat (limited to 'third_party/libwebrtc/common_audio')
171 files changed, 29228 insertions, 0 deletions
diff --git a/third_party/libwebrtc/common_audio/BUILD.gn b/third_party/libwebrtc/common_audio/BUILD.gn new file mode 100644 index 0000000000..79d9321bbd --- /dev/null +++ b/third_party/libwebrtc/common_audio/BUILD.gn @@ -0,0 +1,391 @@ +# 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. + +import("../webrtc.gni") + +visibility = [ ":*" ] + +rtc_library("common_audio") { + visibility += [ "*" ] + sources = [ + "audio_converter.cc", + "audio_converter.h", + "audio_util.cc", + "channel_buffer.cc", + "channel_buffer.h", + "include/audio_util.h", + "real_fourier.cc", + "real_fourier.h", + "real_fourier_ooura.cc", + "real_fourier_ooura.h", + "resampler/include/push_resampler.h", + "resampler/include/resampler.h", + "resampler/push_resampler.cc", + "resampler/push_sinc_resampler.cc", + "resampler/push_sinc_resampler.h", + "resampler/resampler.cc", + "resampler/sinc_resampler.cc", + "smoothing_filter.cc", + "smoothing_filter.h", + "vad/include/vad.h", + "vad/vad.cc", + "wav_file.cc", + "wav_file.h", + "wav_header.cc", + "wav_header.h", + "window_generator.cc", + "window_generator.h", + ] + + deps = [ + ":common_audio_c", + ":sinc_resampler", + "../api:array_view", + "../rtc_base:checks", + "../rtc_base:gtest_prod", + "../rtc_base:logging", + "../rtc_base:safe_conversions", + "../rtc_base:sanitizer", + "../rtc_base:timeutils", + "../rtc_base/memory:aligned_malloc", + "../rtc_base/system:arch", + "../rtc_base/system:file_wrapper", + "../system_wrappers", + "third_party/ooura:fft_size_256", + ] + absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ] + + defines = [] + + if (rtc_build_with_neon) { + deps += [ ":common_audio_neon" ] + } + + if (target_cpu == "x86" || target_cpu == "x64") { + deps += [ ":common_audio_sse2" ] + deps += [ ":common_audio_avx2" ] + } +} + +rtc_source_set("mock_common_audio") { + visibility += webrtc_default_visibility + testonly = true + sources = [ + "mocks/mock_smoothing_filter.h", + "vad/mock/mock_vad.h", + ] + deps = [ + ":common_audio", + "../test:test_support", + ] +} + +rtc_source_set("common_audio_c_arm_asm") { + sources = [] + deps = [] + if (target_cpu == "arm") { + sources += [ "signal_processing/complex_bit_reverse_arm.S" ] + + if (arm_version >= 7) { + sources += [ "signal_processing/filter_ar_fast_q12_armv7.S" ] + } else { + sources += [ "signal_processing/filter_ar_fast_q12.c" ] + } + deps += [ "../rtc_base/system:asm_defines" ] + } +} + +rtc_library("common_audio_c") { + visibility += webrtc_default_visibility + sources = [ + "ring_buffer.c", + "ring_buffer.h", + "signal_processing/auto_corr_to_refl_coef.c", + "signal_processing/auto_correlation.c", + "signal_processing/complex_fft_tables.h", + "signal_processing/copy_set_operations.c", + "signal_processing/cross_correlation.c", + "signal_processing/division_operations.c", + "signal_processing/downsample_fast.c", + "signal_processing/energy.c", + "signal_processing/filter_ar.c", + "signal_processing/filter_ma_fast_q12.c", + "signal_processing/get_hanning_window.c", + "signal_processing/get_scaling_square.c", + "signal_processing/ilbc_specific_functions.c", + "signal_processing/include/real_fft.h", + "signal_processing/include/signal_processing_library.h", + "signal_processing/include/spl_inl.h", + "signal_processing/include/spl_inl_armv7.h", + "signal_processing/levinson_durbin.c", + "signal_processing/lpc_to_refl_coef.c", + "signal_processing/min_max_operations.c", + "signal_processing/randomization_functions.c", + "signal_processing/real_fft.c", + "signal_processing/refl_coef_to_lpc.c", + "signal_processing/resample.c", + "signal_processing/resample_48khz.c", + "signal_processing/resample_by_2.c", + "signal_processing/resample_by_2_internal.c", + "signal_processing/resample_by_2_internal.h", + "signal_processing/resample_fractional.c", + "signal_processing/spl_init.c", + "signal_processing/spl_inl.c", + "signal_processing/spl_sqrt.c", + "signal_processing/splitting_filter.c", + "signal_processing/sqrt_of_one_minus_x_squared.c", + "signal_processing/vector_scaling_operations.c", + "vad/include/webrtc_vad.h", + "vad/vad_core.c", + "vad/vad_core.h", + "vad/vad_filterbank.c", + "vad/vad_filterbank.h", + "vad/vad_gmm.c", + "vad/vad_gmm.h", + "vad/vad_sp.c", + "vad/vad_sp.h", + "vad/webrtc_vad.c", + ] + + if (target_cpu == "mipsel") { + sources += [ + "signal_processing/complex_bit_reverse_mips.c", + "signal_processing/complex_fft_mips.c", + "signal_processing/cross_correlation_mips.c", + "signal_processing/downsample_fast_mips.c", + "signal_processing/filter_ar_fast_q12_mips.c", + "signal_processing/include/spl_inl_mips.h", + "signal_processing/min_max_operations_mips.c", + "signal_processing/resample_by_2_mips.c", + ] + if (mips_dsp_rev > 0) { + sources += [ "signal_processing/vector_scaling_operations_mips.c" ] + } + } else { + sources += [ "signal_processing/complex_fft.c" ] + } + + if (target_cpu != "arm" && target_cpu != "mipsel") { + sources += [ + "signal_processing/complex_bit_reverse.c", + "signal_processing/filter_ar_fast_q12.c", + ] + } + + deps = [ + ":common_audio_c_arm_asm", + ":common_audio_cc", + "../rtc_base:checks", + "../rtc_base:compile_assert_c", + "../rtc_base:sanitizer", + "../rtc_base/system:arch", + "../system_wrappers", + "third_party/ooura:fft_size_256", + "third_party/spl_sqrt_floor", + ] +} + +rtc_library("common_audio_cc") { + sources = [ + "signal_processing/dot_product_with_scale.cc", + "signal_processing/dot_product_with_scale.h", + ] + + deps = [ + "../rtc_base:safe_conversions", + "../system_wrappers", + ] +} + +rtc_source_set("sinc_resampler") { + sources = [ "resampler/sinc_resampler.h" ] + deps = [ + "../rtc_base:gtest_prod", + "../rtc_base/memory:aligned_malloc", + "../rtc_base/system:arch", + "../system_wrappers", + ] +} + +rtc_source_set("fir_filter") { + visibility += webrtc_default_visibility + sources = [ "fir_filter.h" ] +} + +rtc_library("fir_filter_factory") { + visibility += webrtc_default_visibility + sources = [ + "fir_filter_c.cc", + "fir_filter_c.h", + "fir_filter_factory.cc", + "fir_filter_factory.h", + ] + deps = [ + ":fir_filter", + "../rtc_base:checks", + "../rtc_base/system:arch", + "../system_wrappers", + ] + if (target_cpu == "x86" || target_cpu == "x64") { + deps += [ ":common_audio_sse2" ] + deps += [ ":common_audio_avx2" ] + } + if (rtc_build_with_neon) { + deps += [ ":common_audio_neon" ] + } +} + +if (target_cpu == "x86" || target_cpu == "x64") { + rtc_library("common_audio_sse2") { + sources = [ + "fir_filter_sse.cc", + "fir_filter_sse.h", + "resampler/sinc_resampler_sse.cc", + ] + + if (is_posix || is_fuchsia) { + cflags = [ "-msse2" ] + } + + deps = [ + ":fir_filter", + ":sinc_resampler", + "../rtc_base:checks", + "../rtc_base/memory:aligned_malloc", + ] + } + + rtc_library("common_audio_avx2") { + sources = [ + "fir_filter_avx2.cc", + "fir_filter_avx2.h", + "resampler/sinc_resampler_avx2.cc", + ] + + cflags = [ + "-mavx2", + "-mfma", + ] + + deps = [ + ":fir_filter", + ":sinc_resampler", + "../rtc_base:checks", + "../rtc_base/memory:aligned_malloc", + ] + } +} + +if (rtc_build_with_neon) { + rtc_library("common_audio_neon") { + sources = [ + "fir_filter_neon.cc", + "fir_filter_neon.h", + "resampler/sinc_resampler_neon.cc", + ] + + if (target_cpu != "arm64") { + # Enable compilation for the NEON instruction set. + suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] + cflags = [ "-mfpu=neon" ] + } + + deps = [ + ":common_audio_neon_c", + ":fir_filter", + ":sinc_resampler", + "../rtc_base:checks", + "../rtc_base/memory:aligned_malloc", + ] + } + + rtc_library("common_audio_neon_c") { + visibility += webrtc_default_visibility + sources = [ + "signal_processing/cross_correlation_neon.c", + "signal_processing/downsample_fast_neon.c", + "signal_processing/min_max_operations_neon.c", + ] + + if (target_cpu != "arm64") { + # Enable compilation for the NEON instruction set. + suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] + cflags = [ "-mfpu=neon" ] + } + + deps = [ + ":common_audio_c", + "../rtc_base:checks", + "../rtc_base/system:arch", + ] + } +} + +if (rtc_include_tests && !build_with_chromium) { + rtc_test("common_audio_unittests") { + visibility += webrtc_default_visibility + testonly = true + + sources = [ + "audio_converter_unittest.cc", + "audio_util_unittest.cc", + "channel_buffer_unittest.cc", + "fir_filter_unittest.cc", + "real_fourier_unittest.cc", + "resampler/push_resampler_unittest.cc", + "resampler/push_sinc_resampler_unittest.cc", + "resampler/resampler_unittest.cc", + "resampler/sinusoidal_linear_chirp_source.cc", + "resampler/sinusoidal_linear_chirp_source.h", + "ring_buffer_unittest.cc", + "signal_processing/real_fft_unittest.cc", + "signal_processing/signal_processing_unittest.cc", + "smoothing_filter_unittest.cc", + "vad/vad_core_unittest.cc", + "vad/vad_filterbank_unittest.cc", + "vad/vad_gmm_unittest.cc", + "vad/vad_sp_unittest.cc", + "vad/vad_unittest.cc", + "vad/vad_unittest.h", + "wav_file_unittest.cc", + "wav_header_unittest.cc", + "window_generator_unittest.cc", + ] + + # Does not compile on iOS for arm: webrtc:5544. + if (!is_ios || target_cpu != "arm") { + sources += [ "resampler/sinc_resampler_unittest.cc" ] + } + + deps = [ + ":common_audio", + ":common_audio_c", + ":fir_filter", + ":fir_filter_factory", + ":sinc_resampler", + "../rtc_base:checks", + "../rtc_base:macromagic", + "../rtc_base:rtc_base_tests_utils", + "../rtc_base:stringutils", + "../rtc_base:timeutils", + "../rtc_base/system:arch", + "../system_wrappers", + "../test:fileutils", + "../test:rtc_expect_death", + "../test:test_main", + "../test:test_support", + "//testing/gtest", + ] + + if (is_android) { + deps += [ "//testing/android/native_test:native_test_support" ] + + shard_timeout = 900 + } + } +} diff --git a/third_party/libwebrtc/common_audio/DEPS b/third_party/libwebrtc/common_audio/DEPS new file mode 100644 index 0000000000..8a9adf19f9 --- /dev/null +++ b/third_party/libwebrtc/common_audio/DEPS @@ -0,0 +1,3 @@ +include_rules = [ + "+system_wrappers", +] diff --git a/third_party/libwebrtc/common_audio/OWNERS b/third_party/libwebrtc/common_audio/OWNERS new file mode 100644 index 0000000000..4cb53169b3 --- /dev/null +++ b/third_party/libwebrtc/common_audio/OWNERS @@ -0,0 +1,3 @@ +henrik.lundin@webrtc.org +minyue@webrtc.org +peah@webrtc.org diff --git a/third_party/libwebrtc/common_audio/audio_converter.cc b/third_party/libwebrtc/common_audio/audio_converter.cc new file mode 100644 index 0000000000..485ec80c56 --- /dev/null +++ b/third_party/libwebrtc/common_audio/audio_converter.cc @@ -0,0 +1,219 @@ +/* + * 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 "common_audio/audio_converter.h" + +#include <cstring> +#include <memory> +#include <utility> +#include <vector> + +#include "common_audio/channel_buffer.h" +#include "common_audio/resampler/push_sinc_resampler.h" +#include "rtc_base/checks.h" +#include "rtc_base/numerics/safe_conversions.h" + +namespace webrtc { + +class CopyConverter : public AudioConverter { + public: + CopyConverter(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames) + : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} + ~CopyConverter() override {} + + void Convert(const float* const* src, + size_t src_size, + float* const* dst, + size_t dst_capacity) override { + CheckSizes(src_size, dst_capacity); + if (src != dst) { + for (size_t i = 0; i < src_channels(); ++i) + std::memcpy(dst[i], src[i], dst_frames() * sizeof(*dst[i])); + } + } +}; + +class UpmixConverter : public AudioConverter { + public: + UpmixConverter(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames) + : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} + ~UpmixConverter() override {} + + void Convert(const float* const* src, + size_t src_size, + float* const* dst, + size_t dst_capacity) override { + CheckSizes(src_size, dst_capacity); + for (size_t i = 0; i < dst_frames(); ++i) { + const float value = src[0][i]; + for (size_t j = 0; j < dst_channels(); ++j) + dst[j][i] = value; + } + } +}; + +class DownmixConverter : public AudioConverter { + public: + DownmixConverter(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames) + : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {} + ~DownmixConverter() override {} + + void Convert(const float* const* src, + size_t src_size, + float* const* dst, + size_t dst_capacity) override { + CheckSizes(src_size, dst_capacity); + float* dst_mono = dst[0]; + for (size_t i = 0; i < src_frames(); ++i) { + float sum = 0; + for (size_t j = 0; j < src_channels(); ++j) + sum += src[j][i]; + dst_mono[i] = sum / src_channels(); + } + } +}; + +class ResampleConverter : public AudioConverter { + public: + ResampleConverter(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames) + : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) { + resamplers_.reserve(src_channels); + for (size_t i = 0; i < src_channels; ++i) + resamplers_.push_back(std::unique_ptr<PushSincResampler>( + new PushSincResampler(src_frames, dst_frames))); + } + ~ResampleConverter() override {} + + void Convert(const float* const* src, + size_t src_size, + float* const* dst, + size_t dst_capacity) override { + CheckSizes(src_size, dst_capacity); + for (size_t i = 0; i < resamplers_.size(); ++i) + resamplers_[i]->Resample(src[i], src_frames(), dst[i], dst_frames()); + } + + private: + std::vector<std::unique_ptr<PushSincResampler>> resamplers_; +}; + +// Apply a vector of converters in serial, in the order given. At least two +// converters must be provided. +class CompositionConverter : public AudioConverter { + public: + explicit CompositionConverter( + std::vector<std::unique_ptr<AudioConverter>> converters) + : converters_(std::move(converters)) { + RTC_CHECK_GE(converters_.size(), 2); + // We need an intermediate buffer after every converter. + for (auto it = converters_.begin(); it != converters_.end() - 1; ++it) + buffers_.push_back( + std::unique_ptr<ChannelBuffer<float>>(new ChannelBuffer<float>( + (*it)->dst_frames(), (*it)->dst_channels()))); + } + ~CompositionConverter() override {} + + void Convert(const float* const* src, + size_t src_size, + float* const* dst, + size_t dst_capacity) override { + converters_.front()->Convert(src, src_size, buffers_.front()->channels(), + buffers_.front()->size()); + for (size_t i = 2; i < converters_.size(); ++i) { + auto& src_buffer = buffers_[i - 2]; + auto& dst_buffer = buffers_[i - 1]; + converters_[i]->Convert(src_buffer->channels(), src_buffer->size(), + dst_buffer->channels(), dst_buffer->size()); + } + converters_.back()->Convert(buffers_.back()->channels(), + buffers_.back()->size(), dst, dst_capacity); + } + + private: + std::vector<std::unique_ptr<AudioConverter>> converters_; + std::vector<std::unique_ptr<ChannelBuffer<float>>> buffers_; +}; + +std::unique_ptr<AudioConverter> AudioConverter::Create(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames) { + std::unique_ptr<AudioConverter> sp; + if (src_channels > dst_channels) { + if (src_frames != dst_frames) { + std::vector<std::unique_ptr<AudioConverter>> converters; + converters.push_back(std::unique_ptr<AudioConverter>(new DownmixConverter( + src_channels, src_frames, dst_channels, src_frames))); + converters.push_back( + std::unique_ptr<AudioConverter>(new ResampleConverter( + dst_channels, src_frames, dst_channels, dst_frames))); + sp.reset(new CompositionConverter(std::move(converters))); + } else { + sp.reset(new DownmixConverter(src_channels, src_frames, dst_channels, + dst_frames)); + } + } else if (src_channels < dst_channels) { + if (src_frames != dst_frames) { + std::vector<std::unique_ptr<AudioConverter>> converters; + converters.push_back( + std::unique_ptr<AudioConverter>(new ResampleConverter( + src_channels, src_frames, src_channels, dst_frames))); + converters.push_back(std::unique_ptr<AudioConverter>(new UpmixConverter( + src_channels, dst_frames, dst_channels, dst_frames))); + sp.reset(new CompositionConverter(std::move(converters))); + } else { + sp.reset(new UpmixConverter(src_channels, src_frames, dst_channels, + dst_frames)); + } + } else if (src_frames != dst_frames) { + sp.reset(new ResampleConverter(src_channels, src_frames, dst_channels, + dst_frames)); + } else { + sp.reset( + new CopyConverter(src_channels, src_frames, dst_channels, dst_frames)); + } + + return sp; +} + +// For CompositionConverter. +AudioConverter::AudioConverter() + : src_channels_(0), src_frames_(0), dst_channels_(0), dst_frames_(0) {} + +AudioConverter::AudioConverter(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames) + : src_channels_(src_channels), + src_frames_(src_frames), + dst_channels_(dst_channels), + dst_frames_(dst_frames) { + RTC_CHECK(dst_channels == src_channels || dst_channels == 1 || + src_channels == 1); +} + +void AudioConverter::CheckSizes(size_t src_size, size_t dst_capacity) const { + RTC_CHECK_EQ(src_size, src_channels() * src_frames()); + RTC_CHECK_GE(dst_capacity, dst_channels() * dst_frames()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/audio_converter.h b/third_party/libwebrtc/common_audio/audio_converter.h new file mode 100644 index 0000000000..4afbb6d0fd --- /dev/null +++ b/third_party/libwebrtc/common_audio/audio_converter.h @@ -0,0 +1,72 @@ +/* + * 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 COMMON_AUDIO_AUDIO_CONVERTER_H_ +#define COMMON_AUDIO_AUDIO_CONVERTER_H_ + +#include <stddef.h> + +#include <memory> + +namespace webrtc { + +// Format conversion (remixing and resampling) for audio. Only simple remixing +// conversions are supported: downmix to mono (i.e. `dst_channels` == 1) or +// upmix from mono (i.e. |src_channels == 1|). +// +// The source and destination chunks have the same duration in time; specifying +// the number of frames is equivalent to specifying the sample rates. +class AudioConverter { + public: + // Returns a new AudioConverter, which will use the supplied format for its + // lifetime. Caller is responsible for the memory. + static std::unique_ptr<AudioConverter> Create(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames); + virtual ~AudioConverter() {} + + AudioConverter(const AudioConverter&) = delete; + AudioConverter& operator=(const AudioConverter&) = delete; + + // Convert `src`, containing `src_size` samples, to `dst`, having a sample + // capacity of `dst_capacity`. Both point to a series of buffers containing + // the samples for each channel. The sizes must correspond to the format + // passed to Create(). + virtual void Convert(const float* const* src, + size_t src_size, + float* const* dst, + size_t dst_capacity) = 0; + + size_t src_channels() const { return src_channels_; } + size_t src_frames() const { return src_frames_; } + size_t dst_channels() const { return dst_channels_; } + size_t dst_frames() const { return dst_frames_; } + + protected: + AudioConverter(); + AudioConverter(size_t src_channels, + size_t src_frames, + size_t dst_channels, + size_t dst_frames); + + // Helper to RTC_CHECK that inputs are correctly sized. + void CheckSizes(size_t src_size, size_t dst_capacity) const; + + private: + const size_t src_channels_; + const size_t src_frames_; + const size_t dst_channels_; + const size_t dst_frames_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_AUDIO_CONVERTER_H_ diff --git a/third_party/libwebrtc/common_audio/audio_converter_unittest.cc b/third_party/libwebrtc/common_audio/audio_converter_unittest.cc new file mode 100644 index 0000000000..7fbd06d1b4 --- /dev/null +++ b/third_party/libwebrtc/common_audio/audio_converter_unittest.cc @@ -0,0 +1,159 @@ +/* + * 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 "common_audio/audio_converter.h" + +#include <algorithm> +#include <cmath> +#include <memory> +#include <vector> + +#include "common_audio/channel_buffer.h" +#include "common_audio/resampler/push_sinc_resampler.h" +#include "rtc_base/arraysize.h" +#include "test/gtest.h" + +namespace webrtc { + +typedef std::unique_ptr<ChannelBuffer<float>> ScopedBuffer; + +// Sets the signal value to increase by `data` with every sample. +ScopedBuffer CreateBuffer(const std::vector<float>& data, size_t frames) { + const size_t num_channels = data.size(); + ScopedBuffer sb(new ChannelBuffer<float>(frames, num_channels)); + for (size_t i = 0; i < num_channels; ++i) + for (size_t j = 0; j < frames; ++j) + sb->channels()[i][j] = data[i] * j; + return sb; +} + +void VerifyParams(const ChannelBuffer<float>& ref, + const ChannelBuffer<float>& test) { + EXPECT_EQ(ref.num_channels(), test.num_channels()); + EXPECT_EQ(ref.num_frames(), test.num_frames()); +} + +// Computes the best SNR based on the error between `ref_frame` and +// `test_frame`. It searches around `expected_delay` in samples between the +// signals to compensate for the resampling delay. +float ComputeSNR(const ChannelBuffer<float>& ref, + const ChannelBuffer<float>& test, + size_t expected_delay) { + VerifyParams(ref, test); + float best_snr = 0; + size_t best_delay = 0; + + // Search within one sample of the expected delay. + for (size_t delay = std::max(expected_delay, static_cast<size_t>(1)) - 1; + delay <= std::min(expected_delay + 1, ref.num_frames()); ++delay) { + float mse = 0; + float variance = 0; + float mean = 0; + for (size_t i = 0; i < ref.num_channels(); ++i) { + for (size_t j = 0; j < ref.num_frames() - delay; ++j) { + float error = ref.channels()[i][j] - test.channels()[i][j + delay]; + mse += error * error; + variance += ref.channels()[i][j] * ref.channels()[i][j]; + mean += ref.channels()[i][j]; + } + } + + const size_t length = ref.num_channels() * (ref.num_frames() - delay); + mse /= length; + variance /= length; + mean /= length; + variance -= mean * mean; + float snr = 100; // We assign 100 dB to the zero-error case. + if (mse > 0) + snr = 10 * std::log10(variance / mse); + if (snr > best_snr) { + best_snr = snr; + best_delay = delay; + } + } + printf("SNR=%.1f dB at delay=%zu\n", best_snr, best_delay); + return best_snr; +} + +// Sets the source to a linearly increasing signal for which we can easily +// generate a reference. Runs the AudioConverter and ensures the output has +// sufficiently high SNR relative to the reference. +void RunAudioConverterTest(size_t src_channels, + int src_sample_rate_hz, + size_t dst_channels, + int dst_sample_rate_hz) { + const float kSrcLeft = 0.0002f; + const float kSrcRight = 0.0001f; + const float resampling_factor = + (1.f * src_sample_rate_hz) / dst_sample_rate_hz; + const float dst_left = resampling_factor * kSrcLeft; + const float dst_right = resampling_factor * kSrcRight; + const float dst_mono = (dst_left + dst_right) / 2; + const size_t src_frames = static_cast<size_t>(src_sample_rate_hz / 100); + const size_t dst_frames = static_cast<size_t>(dst_sample_rate_hz / 100); + + std::vector<float> src_data(1, kSrcLeft); + if (src_channels == 2) + src_data.push_back(kSrcRight); + ScopedBuffer src_buffer = CreateBuffer(src_data, src_frames); + + std::vector<float> dst_data(1, 0); + std::vector<float> ref_data; + if (dst_channels == 1) { + if (src_channels == 1) + ref_data.push_back(dst_left); + else + ref_data.push_back(dst_mono); + } else { + dst_data.push_back(0); + ref_data.push_back(dst_left); + if (src_channels == 1) + ref_data.push_back(dst_left); + else + ref_data.push_back(dst_right); + } + ScopedBuffer dst_buffer = CreateBuffer(dst_data, dst_frames); + ScopedBuffer ref_buffer = CreateBuffer(ref_data, dst_frames); + + // The sinc resampler has a known delay, which we compute here. + const size_t delay_frames = + src_sample_rate_hz == dst_sample_rate_hz + ? 0 + : static_cast<size_t>( + PushSincResampler::AlgorithmicDelaySeconds(src_sample_rate_hz) * + dst_sample_rate_hz); + // SNR reported on the same line later. + printf("(%zu, %d Hz) -> (%zu, %d Hz) ", src_channels, src_sample_rate_hz, + dst_channels, dst_sample_rate_hz); + + std::unique_ptr<AudioConverter> converter = AudioConverter::Create( + src_channels, src_frames, dst_channels, dst_frames); + converter->Convert(src_buffer->channels(), src_buffer->size(), + dst_buffer->channels(), dst_buffer->size()); + + EXPECT_LT(43.f, + ComputeSNR(*ref_buffer.get(), *dst_buffer.get(), delay_frames)); +} + +TEST(AudioConverterTest, ConversionsPassSNRThreshold) { + const int kSampleRates[] = {8000, 11025, 16000, 22050, 32000, 44100, 48000}; + const int kChannels[] = {1, 2}; + for (int src_rate : kSampleRates) { + for (int dst_rate : kSampleRates) { + for (size_t src_channels : kChannels) { + for (size_t dst_channels : kChannels) { + RunAudioConverterTest(src_channels, src_rate, dst_channels, dst_rate); + } + } + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/audio_util.cc b/third_party/libwebrtc/common_audio/audio_util.cc new file mode 100644 index 0000000000..b1e4d9ac3c --- /dev/null +++ b/third_party/libwebrtc/common_audio/audio_util.cc @@ -0,0 +1,54 @@ +/* + * 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 "common_audio/include/audio_util.h" + +namespace webrtc { + +void FloatToS16(const float* src, size_t size, int16_t* dest) { + for (size_t i = 0; i < size; ++i) + dest[i] = FloatToS16(src[i]); +} + +void S16ToFloat(const int16_t* src, size_t size, float* dest) { + for (size_t i = 0; i < size; ++i) + dest[i] = S16ToFloat(src[i]); +} + +void S16ToFloatS16(const int16_t* src, size_t size, float* dest) { + for (size_t i = 0; i < size; ++i) + dest[i] = src[i]; +} + +void FloatS16ToS16(const float* src, size_t size, int16_t* dest) { + for (size_t i = 0; i < size; ++i) + dest[i] = FloatS16ToS16(src[i]); +} + +void FloatToFloatS16(const float* src, size_t size, float* dest) { + for (size_t i = 0; i < size; ++i) + dest[i] = FloatToFloatS16(src[i]); +} + +void FloatS16ToFloat(const float* src, size_t size, float* dest) { + for (size_t i = 0; i < size; ++i) + dest[i] = FloatS16ToFloat(src[i]); +} + +template <> +void DownmixInterleavedToMono<int16_t>(const int16_t* interleaved, + size_t num_frames, + int num_channels, + int16_t* deinterleaved) { + DownmixInterleavedToMonoImpl<int16_t, int32_t>(interleaved, num_frames, + num_channels, deinterleaved); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/audio_util_unittest.cc b/third_party/libwebrtc/common_audio/audio_util_unittest.cc new file mode 100644 index 0000000000..a215a123b1 --- /dev/null +++ b/third_party/libwebrtc/common_audio/audio_util_unittest.cc @@ -0,0 +1,250 @@ +/* + * 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 "common_audio/include/audio_util.h" + +#include "rtc_base/arraysize.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +using ::testing::ElementsAreArray; + +void ExpectArraysEq(const int16_t* ref, const int16_t* test, size_t length) { + for (size_t i = 0; i < length; ++i) { + EXPECT_EQ(ref[i], test[i]); + } +} + +void ExpectArraysEq(const float* ref, const float* test, size_t length) { + for (size_t i = 0; i < length; ++i) { + EXPECT_NEAR(ref[i], test[i], 0.01f); + } +} + +TEST(AudioUtilTest, S16ToFloat) { + static constexpr int16_t kInput[] = {0, 1, -1, 16384, -16384, 32767, -32768}; + static constexpr float kReference[] = { + 0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + float output[kSize]; + S16ToFloat(kInput, kSize, output); + ExpectArraysEq(kReference, output, kSize); +} + +TEST(AudioUtilTest, FloatS16ToS16) { + static constexpr float kInput[] = {0.f, 0.4f, 0.5f, -0.4f, + -0.5f, 32768.f, -32769.f}; + static constexpr int16_t kReference[] = {0, 0, 1, 0, -1, 32767, -32768}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + int16_t output[kSize]; + FloatS16ToS16(kInput, kSize, output); + ExpectArraysEq(kReference, output, kSize); +} + +TEST(AudioUtilTest, FloatToFloatS16) { + static constexpr float kInput[] = {0.f, + 0.4f / 32768.f, + 0.6f / 32768.f, + -0.4f / 32768.f, + -0.6f / 32768.f, + 1.f, + -1.f, + 1.f, + -1.f}; + static constexpr float kReference[] = { + 0.f, 0.4f, 0.6f, -0.4f, -0.6f, 32768.f, -32768.f, 32768.f, -32768.f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + float output[kSize]; + FloatToFloatS16(kInput, kSize, output); + ExpectArraysEq(kReference, output, kSize); +} + +TEST(AudioUtilTest, FloatS16ToFloat) { + static constexpr float kInput[] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f, + 32767.f, -32768.f, 32767.f, -32768.f}; + static constexpr float kReference[] = {0.f, + 0.4f / 32768.f, + 0.6f / 32768.f, + -0.4f / 32768.f, + -0.6f / 32768.f, + 1.f, + -1.f, + 1.f, + -1.f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + float output[kSize]; + FloatS16ToFloat(kInput, kSize, output); + ExpectArraysEq(kReference, output, kSize); +} + +TEST(AudioUtilTest, DbfsToFloatS16) { + static constexpr float kInput[] = {-90.f, -70.f, -30.f, -20.f, -10.f, + -5.f, -1.f, 0.f, 1.f}; + static constexpr float kReference[] = { + 1.036215186f, 10.36215115f, 1036.215088f, 3276.800049f, 10362.15137f, + 18426.80078f, 29204.51172f, 32768.f, 36766.30078f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + float output[kSize]; + for (size_t i = 0; i < kSize; ++i) { + output[i] = DbfsToFloatS16(kInput[i]); + } + ExpectArraysEq(kReference, output, kSize); +} + +TEST(AudioUtilTest, FloatS16ToDbfs) { + static constexpr float kInput[] = {1.036215143f, 10.36215143f, 1036.215143f, + 3276.8f, 10362.151436f, 18426.800543f, + 29204.51074f, 32768.0f, 36766.30071f}; + + static constexpr float kReference[] = { + -90.f, -70.f, -30.f, -20.f, -10.f, -5.f, -1.f, 0.f, 0.9999923706f}; + static constexpr size_t kSize = arraysize(kInput); + static_assert(arraysize(kReference) == kSize, ""); + + float output[kSize]; + for (size_t i = 0; i < kSize; ++i) { + output[i] = FloatS16ToDbfs(kInput[i]); + } + ExpectArraysEq(kReference, output, kSize); +} + +TEST(AudioUtilTest, InterleavingStereo) { + const int16_t kInterleaved[] = {2, 3, 4, 9, 8, 27, 16, 81}; + const size_t kSamplesPerChannel = 4; + const int kNumChannels = 2; + const size_t kLength = kSamplesPerChannel * kNumChannels; + int16_t left[kSamplesPerChannel], right[kSamplesPerChannel]; + int16_t* deinterleaved[] = {left, right}; + Deinterleave(kInterleaved, kSamplesPerChannel, kNumChannels, deinterleaved); + const int16_t kRefLeft[] = {2, 4, 8, 16}; + const int16_t kRefRight[] = {3, 9, 27, 81}; + ExpectArraysEq(kRefLeft, left, kSamplesPerChannel); + ExpectArraysEq(kRefRight, right, kSamplesPerChannel); + + int16_t interleaved[kLength]; + Interleave(deinterleaved, kSamplesPerChannel, kNumChannels, interleaved); + ExpectArraysEq(kInterleaved, interleaved, kLength); +} + +TEST(AudioUtilTest, InterleavingMonoIsIdentical) { + const int16_t kInterleaved[] = {1, 2, 3, 4, 5}; + const size_t kSamplesPerChannel = 5; + const int kNumChannels = 1; + int16_t mono[kSamplesPerChannel]; + int16_t* deinterleaved[] = {mono}; + Deinterleave(kInterleaved, kSamplesPerChannel, kNumChannels, deinterleaved); + ExpectArraysEq(kInterleaved, mono, kSamplesPerChannel); + + int16_t interleaved[kSamplesPerChannel]; + Interleave(deinterleaved, kSamplesPerChannel, kNumChannels, interleaved); + ExpectArraysEq(mono, interleaved, kSamplesPerChannel); +} + +TEST(AudioUtilTest, DownmixInterleavedToMono) { + { + const size_t kNumFrames = 4; + const int kNumChannels = 1; + const int16_t interleaved[kNumChannels * kNumFrames] = {1, 2, -1, -3}; + int16_t deinterleaved[kNumFrames]; + + DownmixInterleavedToMono(interleaved, kNumFrames, kNumChannels, + deinterleaved); + + EXPECT_THAT(deinterleaved, ElementsAreArray(interleaved)); + } + { + const size_t kNumFrames = 2; + const int kNumChannels = 2; + const int16_t interleaved[kNumChannels * kNumFrames] = {10, 20, -10, -30}; + int16_t deinterleaved[kNumFrames]; + + DownmixInterleavedToMono(interleaved, kNumFrames, kNumChannels, + deinterleaved); + const int16_t expected[kNumFrames] = {15, -20}; + + EXPECT_THAT(deinterleaved, ElementsAreArray(expected)); + } + { + const size_t kNumFrames = 3; + const int kNumChannels = 3; + const int16_t interleaved[kNumChannels * kNumFrames] = { + 30000, 30000, 24001, -5, -10, -20, -30000, -30999, -30000}; + int16_t deinterleaved[kNumFrames]; + + DownmixInterleavedToMono(interleaved, kNumFrames, kNumChannels, + deinterleaved); + const int16_t expected[kNumFrames] = {28000, -11, -30333}; + + EXPECT_THAT(deinterleaved, ElementsAreArray(expected)); + } +} + +TEST(AudioUtilTest, DownmixToMonoTest) { + { + const size_t kNumFrames = 4; + const int kNumChannels = 1; + const float input_data[kNumChannels][kNumFrames] = {{1.f, 2.f, -1.f, -3.f}}; + const float* input[kNumChannels]; + for (int i = 0; i < kNumChannels; ++i) { + input[i] = input_data[i]; + } + + float downmixed[kNumFrames]; + + DownmixToMono<float, float>(input, kNumFrames, kNumChannels, downmixed); + + EXPECT_THAT(downmixed, ElementsAreArray(input_data[0])); + } + { + const size_t kNumFrames = 3; + const int kNumChannels = 2; + const float input_data[kNumChannels][kNumFrames] = {{1.f, 2.f, -1.f}, + {3.f, 0.f, 1.f}}; + const float* input[kNumChannels]; + for (int i = 0; i < kNumChannels; ++i) { + input[i] = input_data[i]; + } + + float downmixed[kNumFrames]; + const float expected[kNumFrames] = {2.f, 1.f, 0.f}; + + DownmixToMono<float, float>(input, kNumFrames, kNumChannels, downmixed); + + EXPECT_THAT(downmixed, ElementsAreArray(expected)); + } + { + const size_t kNumFrames = 3; + const int kNumChannels = 3; + const int16_t input_data[kNumChannels][kNumFrames] = { + {30000, -5, -30000}, {30000, -10, -30999}, {24001, -20, -30000}}; + const int16_t* input[kNumChannels]; + for (int i = 0; i < kNumChannels; ++i) { + input[i] = input_data[i]; + } + + int16_t downmixed[kNumFrames]; + const int16_t expected[kNumFrames] = {28000, -11, -30333}; + + DownmixToMono<int16_t, int32_t>(input, kNumFrames, kNumChannels, downmixed); + + EXPECT_THAT(downmixed, ElementsAreArray(expected)); + } +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/channel_buffer.cc b/third_party/libwebrtc/common_audio/channel_buffer.cc new file mode 100644 index 0000000000..b9b8c25e37 --- /dev/null +++ b/third_party/libwebrtc/common_audio/channel_buffer.cc @@ -0,0 +1,80 @@ +/* + * 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 "common_audio/channel_buffer.h" + +#include <cstdint> + +#include "common_audio/include/audio_util.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +IFChannelBuffer::IFChannelBuffer(size_t num_frames, + size_t num_channels, + size_t num_bands) + : ivalid_(true), + ibuf_(num_frames, num_channels, num_bands), + fvalid_(true), + fbuf_(num_frames, num_channels, num_bands) {} + +IFChannelBuffer::~IFChannelBuffer() = default; + +ChannelBuffer<int16_t>* IFChannelBuffer::ibuf() { + RefreshI(); + fvalid_ = false; + return &ibuf_; +} + +ChannelBuffer<float>* IFChannelBuffer::fbuf() { + RefreshF(); + ivalid_ = false; + return &fbuf_; +} + +const ChannelBuffer<int16_t>* IFChannelBuffer::ibuf_const() const { + RefreshI(); + return &ibuf_; +} + +const ChannelBuffer<float>* IFChannelBuffer::fbuf_const() const { + RefreshF(); + return &fbuf_; +} + +void IFChannelBuffer::RefreshF() const { + if (!fvalid_) { + RTC_DCHECK(ivalid_); + fbuf_.set_num_channels(ibuf_.num_channels()); + const int16_t* const* int_channels = ibuf_.channels(); + float* const* float_channels = fbuf_.channels(); + for (size_t i = 0; i < ibuf_.num_channels(); ++i) { + for (size_t j = 0; j < ibuf_.num_frames(); ++j) { + float_channels[i][j] = int_channels[i][j]; + } + } + fvalid_ = true; + } +} + +void IFChannelBuffer::RefreshI() const { + if (!ivalid_) { + RTC_DCHECK(fvalid_); + int16_t* const* int_channels = ibuf_.channels(); + ibuf_.set_num_channels(fbuf_.num_channels()); + const float* const* float_channels = fbuf_.channels(); + for (size_t i = 0; i < fbuf_.num_channels(); ++i) { + FloatS16ToS16(float_channels[i], ibuf_.num_frames(), int_channels[i]); + } + ivalid_ = true; + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/channel_buffer.h b/third_party/libwebrtc/common_audio/channel_buffer.h new file mode 100644 index 0000000000..9f08d6089b --- /dev/null +++ b/third_party/libwebrtc/common_audio/channel_buffer.h @@ -0,0 +1,215 @@ +/* + * 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 COMMON_AUDIO_CHANNEL_BUFFER_H_ +#define COMMON_AUDIO_CHANNEL_BUFFER_H_ + +#include <string.h> + +#include <memory> +#include <vector> + +#include "api/array_view.h" +#include "common_audio/include/audio_util.h" +#include "rtc_base/checks.h" +#include "rtc_base/gtest_prod_util.h" + +namespace webrtc { + +// Helper to encapsulate a contiguous data buffer, full or split into frequency +// bands, with access to a pointer arrays of the deinterleaved channels and +// bands. The buffer is zero initialized at creation. +// +// The buffer structure is showed below for a 2 channel and 2 bands case: +// +// `data_`: +// { [ --- b1ch1 --- ] [ --- b2ch1 --- ] [ --- b1ch2 --- ] [ --- b2ch2 --- ] } +// +// The pointer arrays for the same example are as follows: +// +// `channels_`: +// { [ b1ch1* ] [ b1ch2* ] [ b2ch1* ] [ b2ch2* ] } +// +// `bands_`: +// { [ b1ch1* ] [ b2ch1* ] [ b1ch2* ] [ b2ch2* ] } +template <typename T> +class ChannelBuffer { + public: + ChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1) + : data_(new T[num_frames * num_channels]()), + channels_(new T*[num_channels * num_bands]), + bands_(new T*[num_channels * num_bands]), + num_frames_(num_frames), + num_frames_per_band_(num_frames / num_bands), + num_allocated_channels_(num_channels), + num_channels_(num_channels), + num_bands_(num_bands), + bands_view_(num_allocated_channels_, + std::vector<rtc::ArrayView<T>>(num_bands_)), + channels_view_( + num_bands_, + std::vector<rtc::ArrayView<T>>(num_allocated_channels_)) { + // Temporarily cast away const_ness to allow populating the array views. + auto* bands_view = + const_cast<std::vector<std::vector<rtc::ArrayView<T>>>*>(&bands_view_); + auto* channels_view = + const_cast<std::vector<std::vector<rtc::ArrayView<T>>>*>( + &channels_view_); + + for (size_t ch = 0; ch < num_allocated_channels_; ++ch) { + for (size_t band = 0; band < num_bands_; ++band) { + (*channels_view)[band][ch] = rtc::ArrayView<T>( + &data_[ch * num_frames_ + band * num_frames_per_band_], + num_frames_per_band_); + (*bands_view)[ch][band] = channels_view_[band][ch]; + channels_[band * num_allocated_channels_ + ch] = + channels_view_[band][ch].data(); + bands_[ch * num_bands_ + band] = + channels_[band * num_allocated_channels_ + ch]; + } + } + } + + // Returns a pointer array to the channels. + // If band is explicitly specificed, the channels for a specific band are + // returned and the usage becomes: channels(band)[channel][sample]. + // Where: + // 0 <= band < `num_bands_` + // 0 <= channel < `num_allocated_channels_` + // 0 <= sample < `num_frames_per_band_` + + // If band is not explicitly specified, the full-band channels (or lower band + // channels) are returned and the usage becomes: channels()[channel][sample]. + // Where: + // 0 <= channel < `num_allocated_channels_` + // 0 <= sample < `num_frames_` + const T* const* channels(size_t band = 0) const { + RTC_DCHECK_LT(band, num_bands_); + return &channels_[band * num_allocated_channels_]; + } + T* const* channels(size_t band = 0) { + const ChannelBuffer<T>* t = this; + return const_cast<T* const*>(t->channels(band)); + } + rtc::ArrayView<const rtc::ArrayView<T>> channels_view(size_t band = 0) { + return channels_view_[band]; + } + rtc::ArrayView<const rtc::ArrayView<T>> channels_view(size_t band = 0) const { + return channels_view_[band]; + } + + // Returns a pointer array to the bands for a specific channel. + // Usage: + // bands(channel)[band][sample]. + // Where: + // 0 <= channel < `num_channels_` + // 0 <= band < `num_bands_` + // 0 <= sample < `num_frames_per_band_` + const T* const* bands(size_t channel) const { + RTC_DCHECK_LT(channel, num_channels_); + RTC_DCHECK_GE(channel, 0); + return &bands_[channel * num_bands_]; + } + T* const* bands(size_t channel) { + const ChannelBuffer<T>* t = this; + return const_cast<T* const*>(t->bands(channel)); + } + + rtc::ArrayView<const rtc::ArrayView<T>> bands_view(size_t channel) { + return bands_view_[channel]; + } + rtc::ArrayView<const rtc::ArrayView<T>> bands_view(size_t channel) const { + return bands_view_[channel]; + } + + // Sets the `slice` pointers to the `start_frame` position for each channel. + // Returns `slice` for convenience. + const T* const* Slice(T** slice, size_t start_frame) const { + RTC_DCHECK_LT(start_frame, num_frames_); + for (size_t i = 0; i < num_channels_; ++i) + slice[i] = &channels_[i][start_frame]; + return slice; + } + T** Slice(T** slice, size_t start_frame) { + const ChannelBuffer<T>* t = this; + return const_cast<T**>(t->Slice(slice, start_frame)); + } + + size_t num_frames() const { return num_frames_; } + size_t num_frames_per_band() const { return num_frames_per_band_; } + size_t num_channels() const { return num_channels_; } + size_t num_bands() const { return num_bands_; } + size_t size() const { return num_frames_ * num_allocated_channels_; } + + void set_num_channels(size_t num_channels) { + RTC_DCHECK_LE(num_channels, num_allocated_channels_); + num_channels_ = num_channels; + } + + void SetDataForTesting(const T* data, size_t size) { + RTC_CHECK_EQ(size, this->size()); + memcpy(data_.get(), data, size * sizeof(*data)); + } + + private: + std::unique_ptr<T[]> data_; + std::unique_ptr<T*[]> channels_; + std::unique_ptr<T*[]> bands_; + const size_t num_frames_; + const size_t num_frames_per_band_; + // Number of channels the internal buffer holds. + const size_t num_allocated_channels_; + // Number of channels the user sees. + size_t num_channels_; + const size_t num_bands_; + const std::vector<std::vector<rtc::ArrayView<T>>> bands_view_; + const std::vector<std::vector<rtc::ArrayView<T>>> channels_view_; +}; + +// One int16_t and one float ChannelBuffer that are kept in sync. The sync is +// broken when someone requests write access to either ChannelBuffer, and +// reestablished when someone requests the outdated ChannelBuffer. It is +// therefore safe to use the return value of ibuf_const() and fbuf_const() +// until the next call to ibuf() or fbuf(), and the return value of ibuf() and +// fbuf() until the next call to any of the other functions. +class IFChannelBuffer { + public: + IFChannelBuffer(size_t num_frames, size_t num_channels, size_t num_bands = 1); + ~IFChannelBuffer(); + + ChannelBuffer<int16_t>* ibuf(); + ChannelBuffer<float>* fbuf(); + const ChannelBuffer<int16_t>* ibuf_const() const; + const ChannelBuffer<float>* fbuf_const() const; + + size_t num_frames() const { return ibuf_.num_frames(); } + size_t num_frames_per_band() const { return ibuf_.num_frames_per_band(); } + size_t num_channels() const { + return ivalid_ ? ibuf_.num_channels() : fbuf_.num_channels(); + } + void set_num_channels(size_t num_channels) { + ibuf_.set_num_channels(num_channels); + fbuf_.set_num_channels(num_channels); + } + size_t num_bands() const { return ibuf_.num_bands(); } + + private: + void RefreshF() const; + void RefreshI() const; + + mutable bool ivalid_; + mutable ChannelBuffer<int16_t> ibuf_; + mutable bool fvalid_; + mutable ChannelBuffer<float> fbuf_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_CHANNEL_BUFFER_H_ diff --git a/third_party/libwebrtc/common_audio/channel_buffer_unittest.cc b/third_party/libwebrtc/common_audio/channel_buffer_unittest.cc new file mode 100644 index 0000000000..a8b64891d6 --- /dev/null +++ b/third_party/libwebrtc/common_audio/channel_buffer_unittest.cc @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/channel_buffer.h" + +#include "test/gtest.h" +#include "test/testsupport/rtc_expect_death.h" + +namespace webrtc { + +namespace { + +const size_t kNumFrames = 480u; +const size_t kStereo = 2u; +const size_t kMono = 1u; + +void ExpectNumChannels(const IFChannelBuffer& ifchb, size_t num_channels) { + EXPECT_EQ(ifchb.ibuf_const()->num_channels(), num_channels); + EXPECT_EQ(ifchb.fbuf_const()->num_channels(), num_channels); + EXPECT_EQ(ifchb.num_channels(), num_channels); +} + +} // namespace + +TEST(ChannelBufferTest, SetNumChannelsSetsNumChannels) { + ChannelBuffer<float> chb(kNumFrames, kStereo); + EXPECT_EQ(chb.num_channels(), kStereo); + chb.set_num_channels(kMono); + EXPECT_EQ(chb.num_channels(), kMono); +} + +TEST(IFChannelBufferTest, SetNumChannelsSetsChannelBuffersNumChannels) { + IFChannelBuffer ifchb(kNumFrames, kStereo); + ExpectNumChannels(ifchb, kStereo); + ifchb.set_num_channels(kMono); + ExpectNumChannels(ifchb, kMono); +} + +TEST(IFChannelBufferTest, SettingNumChannelsOfOneChannelBufferSetsTheOther) { + IFChannelBuffer ifchb(kNumFrames, kStereo); + ExpectNumChannels(ifchb, kStereo); + ifchb.ibuf()->set_num_channels(kMono); + ExpectNumChannels(ifchb, kMono); + ifchb.fbuf()->set_num_channels(kStereo); + ExpectNumChannels(ifchb, kStereo); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(ChannelBufferDeathTest, SetNumChannelsDeathTest) { + ChannelBuffer<float> chb(kNumFrames, kMono); + RTC_EXPECT_DEATH(chb.set_num_channels(kStereo), "num_channels"); +} + +TEST(IFChannelBufferDeathTest, SetNumChannelsDeathTest) { + IFChannelBuffer ifchb(kNumFrames, kMono); + RTC_EXPECT_DEATH(ifchb.ibuf()->set_num_channels(kStereo), "num_channels"); +} +#endif + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/common_audio_avx2_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_avx2_gn/moz.build new file mode 100644 index 0000000000..5526be7b8b --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_avx2_gn/moz.build @@ -0,0 +1,186 @@ +# 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() + +CXXFLAGS += [ + "-mavx2", + "-mfma" +] + +DEFINES["ABSL_ALLOCATOR_NOTHROW"] = "1" +DEFINES["RTC_DAV1D_IN_INTERNAL_DECODER_FACTORY"] = True +DEFINES["RTC_ENABLE_VP9"] = True +DEFINES["WEBRTC_ENABLE_AVX2"] = 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/common_audio/fir_filter_avx2.cc", + "/third_party/libwebrtc/common_audio/resampler/sinc_resampler_avx2.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["_GNU_SOURCE"] = True + 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["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"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + +Library("common_audio_avx2_gn") diff --git a/third_party/libwebrtc/common_audio/common_audio_c_arm_asm_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_c_arm_asm_gn/moz.build new file mode 100644 index 0000000000..9381d65cea --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_c_arm_asm_gn/moz.build @@ -0,0 +1,206 @@ +# 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 + + SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_arm.S", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S" + ] + +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("common_audio_c_arm_asm_gn") diff --git a/third_party/libwebrtc/common_audio/common_audio_c_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_c_gn/moz.build new file mode 100644 index 0000000000..c9d2d98633 --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_c_gn/moz.build @@ -0,0 +1,367 @@ +# 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" +] + +SOURCES += [ + "/third_party/libwebrtc/common_audio/vad/vad_core.c", + "/third_party/libwebrtc/common_audio/vad/webrtc_vad.c" +] + +UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/ring_buffer.c", + "/third_party/libwebrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c", + "/third_party/libwebrtc/common_audio/signal_processing/auto_correlation.c", + "/third_party/libwebrtc/common_audio/signal_processing/copy_set_operations.c", + "/third_party/libwebrtc/common_audio/signal_processing/cross_correlation.c", + "/third_party/libwebrtc/common_audio/signal_processing/division_operations.c", + "/third_party/libwebrtc/common_audio/signal_processing/downsample_fast.c", + "/third_party/libwebrtc/common_audio/signal_processing/energy.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ma_fast_q12.c", + "/third_party/libwebrtc/common_audio/signal_processing/get_hanning_window.c", + "/third_party/libwebrtc/common_audio/signal_processing/get_scaling_square.c", + "/third_party/libwebrtc/common_audio/signal_processing/ilbc_specific_functions.c", + "/third_party/libwebrtc/common_audio/signal_processing/levinson_durbin.c", + "/third_party/libwebrtc/common_audio/signal_processing/lpc_to_refl_coef.c", + "/third_party/libwebrtc/common_audio/signal_processing/min_max_operations.c", + "/third_party/libwebrtc/common_audio/signal_processing/randomization_functions.c", + "/third_party/libwebrtc/common_audio/signal_processing/real_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/refl_coef_to_lpc.c", + "/third_party/libwebrtc/common_audio/signal_processing/resample.c", + "/third_party/libwebrtc/common_audio/signal_processing/resample_48khz.c", + "/third_party/libwebrtc/common_audio/signal_processing/resample_by_2.c", + "/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_internal.c", + "/third_party/libwebrtc/common_audio/signal_processing/resample_fractional.c", + "/third_party/libwebrtc/common_audio/signal_processing/spl_init.c", + "/third_party/libwebrtc/common_audio/signal_processing/spl_inl.c", + "/third_party/libwebrtc/common_audio/signal_processing/spl_sqrt.c", + "/third_party/libwebrtc/common_audio/signal_processing/splitting_filter.c", + "/third_party/libwebrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c", + "/third_party/libwebrtc/common_audio/signal_processing/vector_scaling_operations.c", + "/third_party/libwebrtc/common_audio/vad/vad_filterbank.c", + "/third_party/libwebrtc/common_audio/vad/vad_gmm.c", + "/third_party/libwebrtc/common_audio/vad/vad_sp.c" +] + +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" + ] + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c" + ] + +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 + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +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 + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +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" + ] + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +if CONFIG["CPU_ARCH"] == "aarch64": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + +if CONFIG["CPU_ARCH"] == "arm": + + CFLAGS += [ + "-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 + + SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_mips.c" + ] + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_mips.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft_mips.c", + "/third_party/libwebrtc/common_audio/signal_processing/cross_correlation_mips.c", + "/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_mips.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c", + "/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_mips.c" + ] + +if CONFIG["CPU_ARCH"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +if CONFIG["CPU_ARCH"] == "ppc64": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +if CONFIG["CPU_ARCH"] == "riscv64": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +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"] == "aarch64" and CONFIG["OS_TARGET"] == "Android": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +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": + + CFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Android": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c", + "/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c", + "/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c" + ] + +Library("common_audio_c_gn") diff --git a/third_party/libwebrtc/common_audio/common_audio_cc_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_cc_gn/moz.build new file mode 100644 index 0000000000..90260ba864 --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_cc_gn/moz.build @@ -0,0 +1,232 @@ +# 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/common_audio/signal_processing/dot_product_with_scale.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("common_audio_cc_gn") diff --git a/third_party/libwebrtc/common_audio/common_audio_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_gn/moz.build new file mode 100644 index 0000000000..c7b74d2e51 --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_gn/moz.build @@ -0,0 +1,245 @@ +# 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/common_audio/audio_converter.cc", + "/third_party/libwebrtc/common_audio/audio_util.cc", + "/third_party/libwebrtc/common_audio/channel_buffer.cc", + "/third_party/libwebrtc/common_audio/real_fourier.cc", + "/third_party/libwebrtc/common_audio/real_fourier_ooura.cc", + "/third_party/libwebrtc/common_audio/resampler/push_resampler.cc", + "/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler.cc", + "/third_party/libwebrtc/common_audio/resampler/resampler.cc", + "/third_party/libwebrtc/common_audio/resampler/sinc_resampler.cc", + "/third_party/libwebrtc/common_audio/smoothing_filter.cc", + "/third_party/libwebrtc/common_audio/vad/vad.cc", + "/third_party/libwebrtc/common_audio/wav_file.cc", + "/third_party/libwebrtc/common_audio/wav_header.cc", + "/third_party/libwebrtc/common_audio/window_generator.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("common_audio_gn") diff --git a/third_party/libwebrtc/common_audio/common_audio_neon_c_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_neon_c_gn/moz.build new file mode 100644 index 0000000000..d51e7f4e35 --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_neon_c_gn/moz.build @@ -0,0 +1,193 @@ +# 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_HAS_NEON"] = True +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/common_audio/signal_processing/cross_correlation_neon.c", + "/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_neon.c", + "/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_neon.c" +] + +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_ARCH_ARM64"] = True + 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["_GNU_SOURCE"] = True + 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_ARCH_ARM64"] = True + 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_ARCH_ARM64"] = True + 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"] == "arm": + + CFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = 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"] == "aarch64" and CONFIG["OS_TARGET"] == "Android": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + +Library("common_audio_neon_c_gn") diff --git a/third_party/libwebrtc/common_audio/common_audio_neon_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_neon_gn/moz.build new file mode 100644 index 0000000000..8df7017bff --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_neon_gn/moz.build @@ -0,0 +1,192 @@ +# 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_HAS_NEON"] = True +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/common_audio/fir_filter_neon.cc", + "/third_party/libwebrtc/common_audio/resampler/sinc_resampler_neon.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_ARCH_ARM64"] = True + 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["_GNU_SOURCE"] = True + 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_ARCH_ARM64"] = True + 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_ARCH_ARM64"] = True + 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"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = 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"] == "aarch64" and CONFIG["OS_TARGET"] == "Android": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Android": + + OS_LIBS += [ + "android_support", + "unwind" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["WEBRTC_ARCH_ARM64"] = True + +Library("common_audio_neon_gn") diff --git a/third_party/libwebrtc/common_audio/common_audio_sse2_gn/moz.build b/third_party/libwebrtc/common_audio/common_audio_sse2_gn/moz.build new file mode 100644 index 0000000000..022ff28455 --- /dev/null +++ b/third_party/libwebrtc/common_audio/common_audio_sse2_gn/moz.build @@ -0,0 +1,203 @@ +# 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_AVX2"] = 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/common_audio/fir_filter_sse.cc", + "/third_party/libwebrtc/common_audio/resampler/sinc_resampler_sse.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": + + CXXFLAGS += [ + "-msse2" + ] + + 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["_GNU_SOURCE"] = True + 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": + + CXXFLAGS += [ + "-msse2" + ] + + 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["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"] == "x86" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2", + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2", + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + +Library("common_audio_sse2_gn") diff --git a/third_party/libwebrtc/common_audio/fir_filter.h b/third_party/libwebrtc/common_audio/fir_filter.h new file mode 100644 index 0000000000..e0b18ca44c --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter.h @@ -0,0 +1,30 @@ +/* + * 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 COMMON_AUDIO_FIR_FILTER_H_ +#define COMMON_AUDIO_FIR_FILTER_H_ + +#include <string.h> + +namespace webrtc { + +// Finite Impulse Response filter using floating-point arithmetic. +class FIRFilter { + public: + virtual ~FIRFilter() {} + + // Filters the `in` data supplied. + // `out` must be previously allocated and it must be at least of `length`. + virtual void Filter(const float* in, size_t length, float* out) = 0; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_FIR_FILTER_H_ diff --git a/third_party/libwebrtc/common_audio/fir_filter_avx2.cc b/third_party/libwebrtc/common_audio/fir_filter_avx2.cc new file mode 100644 index 0000000000..0031392f8a --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_avx2.cc @@ -0,0 +1,90 @@ +/* + * 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. + */ + +#include "common_audio/fir_filter_avx2.h" + +#include <immintrin.h> +#include <stdint.h> +#include <string.h> +#include <xmmintrin.h> + +#include "common_audio/intrin.h" + +#include "rtc_base/checks.h" +#include "rtc_base/memory/aligned_malloc.h" + +namespace webrtc { + +FIRFilterAVX2::FIRFilterAVX2(const float* unaligned_coefficients, + size_t unaligned_coefficients_length, + size_t max_input_length) + : // Closest higher multiple of eight. + coefficients_length_((unaligned_coefficients_length + 7) & ~0x07), + state_length_(coefficients_length_ - 1), + coefficients_(static_cast<float*>( + AlignedMalloc(sizeof(float) * coefficients_length_, 32))), + state_(static_cast<float*>( + AlignedMalloc(sizeof(float) * (max_input_length + state_length_), + 32))) { + // Add zeros at the end of the coefficients. + RTC_DCHECK_GE(coefficients_length_, unaligned_coefficients_length); + size_t padding = coefficients_length_ - unaligned_coefficients_length; + memset(coefficients_.get(), 0, padding * sizeof(coefficients_[0])); + // The coefficients are reversed to compensate for the order in which the + // input samples are acquired (most recent last). + for (size_t i = 0; i < unaligned_coefficients_length; ++i) { + coefficients_[i + padding] = + unaligned_coefficients[unaligned_coefficients_length - i - 1]; + } + memset(state_.get(), 0, + (max_input_length + state_length_) * sizeof(state_[0])); +} + +FIRFilterAVX2::~FIRFilterAVX2() = default; + +void FIRFilterAVX2::Filter(const float* in, size_t length, float* out) { + RTC_DCHECK_GT(length, 0); + + memcpy(&state_[state_length_], in, length * sizeof(*in)); + + // Convolves the input signal `in` with the filter kernel `coefficients_` + // taking into account the previous state. + for (size_t i = 0; i < length; ++i) { + float* in_ptr = &state_[i]; + float* coef_ptr = coefficients_.get(); + + __m256 m_sum = _mm256_setzero_ps(); + __m256 m_in; + + // Depending on if the pointer is aligned with 32 bytes or not it is loaded + // differently. + if (reinterpret_cast<uintptr_t>(in_ptr) & 0x1F) { + for (size_t j = 0; j < coefficients_length_; j += 8) { + m_in = _mm256_loadu_ps(in_ptr + j); + m_sum = _mm256_fmadd_ps(m_in, _mm256_load_ps(coef_ptr + j), m_sum); + } + } else { + for (size_t j = 0; j < coefficients_length_; j += 8) { + m_in = _mm256_load_ps(in_ptr + j); + m_sum = _mm256_fmadd_ps(m_in, _mm256_load_ps(coef_ptr + j), m_sum); + } + } + __m128 m128_sum = _mm_add_ps(_mm256_extractf128_ps(m_sum, 0), + _mm256_extractf128_ps(m_sum, 1)); + m128_sum = _mm_add_ps(_mm_movehl_ps(m128_sum, m128_sum), m128_sum); + _mm_store_ss(out + i, + _mm_add_ss(m128_sum, _mm_shuffle_ps(m128_sum, m128_sum, 1))); + } + + // Update current state. + memmove(state_.get(), &state_[length], state_length_ * sizeof(state_[0])); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/fir_filter_avx2.h b/third_party/libwebrtc/common_audio/fir_filter_avx2.h new file mode 100644 index 0000000000..893b60bf6e --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_avx2.h @@ -0,0 +1,41 @@ +/* + * 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 COMMON_AUDIO_FIR_FILTER_AVX2_H_ +#define COMMON_AUDIO_FIR_FILTER_AVX2_H_ + +#include <stddef.h> + +#include <memory> + +#include "common_audio/fir_filter.h" +#include "rtc_base/memory/aligned_malloc.h" + +namespace webrtc { + +class FIRFilterAVX2 : public FIRFilter { + public: + FIRFilterAVX2(const float* coefficients, + size_t coefficients_length, + size_t max_input_length); + ~FIRFilterAVX2() override; + + void Filter(const float* in, size_t length, float* out) override; + + private: + const size_t coefficients_length_; + const size_t state_length_; + std::unique_ptr<float[], AlignedFreeDeleter> coefficients_; + std::unique_ptr<float[], AlignedFreeDeleter> state_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_FIR_FILTER_AVX2_H_ diff --git a/third_party/libwebrtc/common_audio/fir_filter_c.cc b/third_party/libwebrtc/common_audio/fir_filter_c.cc new file mode 100644 index 0000000000..dc1c8e0d28 --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_c.cc @@ -0,0 +1,61 @@ +/* + * 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 "common_audio/fir_filter_c.h" + +#include <string.h> + +#include <memory> + +#include "rtc_base/checks.h" + +namespace webrtc { + +FIRFilterC::~FIRFilterC() {} + +FIRFilterC::FIRFilterC(const float* coefficients, size_t coefficients_length) + : coefficients_length_(coefficients_length), + state_length_(coefficients_length - 1), + coefficients_(new float[coefficients_length_]), + state_(new float[state_length_]) { + for (size_t i = 0; i < coefficients_length_; ++i) { + coefficients_[i] = coefficients[coefficients_length_ - i - 1]; + } + memset(state_.get(), 0, state_length_ * sizeof(state_[0])); +} + +void FIRFilterC::Filter(const float* in, size_t length, float* out) { + RTC_DCHECK_GT(length, 0); + + // Convolves the input signal `in` with the filter kernel `coefficients_` + // taking into account the previous state. + for (size_t i = 0; i < length; ++i) { + out[i] = 0.f; + size_t j; + for (j = 0; state_length_ > i && j < state_length_ - i; ++j) { + out[i] += state_[i + j] * coefficients_[j]; + } + for (; j < coefficients_length_; ++j) { + out[i] += in[j + i - state_length_] * coefficients_[j]; + } + } + + // Update current state. + if (length >= state_length_) { + memcpy(state_.get(), &in[length - state_length_], + state_length_ * sizeof(*in)); + } else { + memmove(state_.get(), &state_[length], + (state_length_ - length) * sizeof(state_[0])); + memcpy(&state_[state_length_ - length], in, length * sizeof(*in)); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/fir_filter_c.h b/third_party/libwebrtc/common_audio/fir_filter_c.h new file mode 100644 index 0000000000..b2ae4c3217 --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_c.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017 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 COMMON_AUDIO_FIR_FILTER_C_H_ +#define COMMON_AUDIO_FIR_FILTER_C_H_ + +#include <string.h> + +#include <memory> + +#include "common_audio/fir_filter.h" + +namespace webrtc { + +class FIRFilterC : public FIRFilter { + public: + FIRFilterC(const float* coefficients, size_t coefficients_length); + ~FIRFilterC() override; + + void Filter(const float* in, size_t length, float* out) override; + + private: + size_t coefficients_length_; + size_t state_length_; + std::unique_ptr<float[]> coefficients_; + std::unique_ptr<float[]> state_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_FIR_FILTER_C_H_ diff --git a/third_party/libwebrtc/common_audio/fir_filter_factory.cc b/third_party/libwebrtc/common_audio/fir_filter_factory.cc new file mode 100644 index 0000000000..2ecef6501f --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_factory.cc @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2017 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 "common_audio/fir_filter_factory.h" + +#include "common_audio/fir_filter_c.h" +#include "rtc_base/checks.h" +#include "rtc_base/system/arch.h" + +#if defined(WEBRTC_HAS_NEON) +#include "common_audio/fir_filter_neon.h" +#elif defined(WEBRTC_ARCH_X86_FAMILY) +#include "common_audio/fir_filter_avx2.h" +#include "common_audio/fir_filter_sse.h" +#include "system_wrappers/include/cpu_features_wrapper.h" // kSSE2, WebRtc_G... +#endif + +namespace webrtc { + +FIRFilter* CreateFirFilter(const float* coefficients, + size_t coefficients_length, + size_t max_input_length) { + if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) { + RTC_DCHECK_NOTREACHED(); + return nullptr; + } + + FIRFilter* filter = nullptr; +// If we know the minimum architecture at compile time, avoid CPU detection. +#if defined(WEBRTC_ARCH_X86_FAMILY) + // x86 CPU detection required. + if (GetCPUInfo(kAVX2)) { + filter = + new FIRFilterAVX2(coefficients, coefficients_length, max_input_length); + } else if (GetCPUInfo(kSSE2)) { + filter = + new FIRFilterSSE2(coefficients, coefficients_length, max_input_length); + } else { + filter = new FIRFilterC(coefficients, coefficients_length); + } +#elif defined(WEBRTC_HAS_NEON) + filter = + new FIRFilterNEON(coefficients, coefficients_length, max_input_length); +#else + filter = new FIRFilterC(coefficients, coefficients_length); +#endif + + return filter; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/fir_filter_factory.h b/third_party/libwebrtc/common_audio/fir_filter_factory.h new file mode 100644 index 0000000000..e76c3aef7d --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_factory.h @@ -0,0 +1,32 @@ +/* + * 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 COMMON_AUDIO_FIR_FILTER_FACTORY_H_ +#define COMMON_AUDIO_FIR_FILTER_FACTORY_H_ + +#include <string.h> + +namespace webrtc { + +class FIRFilter; + +// Creates a filter with the given coefficients. All initial state values will +// be zeros. +// The length of the chunks fed to the filter should never be greater than +// `max_input_length`. This is needed because, when vectorizing it is +// necessary to concatenate the input after the state, and resizing this array +// dynamically is expensive. +FIRFilter* CreateFirFilter(const float* coefficients, + size_t coefficients_length, + size_t max_input_length); + +} // namespace webrtc + +#endif // COMMON_AUDIO_FIR_FILTER_FACTORY_H_ diff --git a/third_party/libwebrtc/common_audio/fir_filter_factory_gn/moz.build b/third_party/libwebrtc/common_audio/fir_filter_factory_gn/moz.build new file mode 100644 index 0000000000..52e5226e09 --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_factory_gn/moz.build @@ -0,0 +1,233 @@ +# 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/common_audio/fir_filter_c.cc", + "/third_party/libwebrtc/common_audio/fir_filter_factory.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("fir_filter_factory_gn") diff --git a/third_party/libwebrtc/common_audio/fir_filter_gn/moz.build b/third_party/libwebrtc/common_audio/fir_filter_gn/moz.build new file mode 100644 index 0000000000..f931502550 --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_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("fir_filter_gn") diff --git a/third_party/libwebrtc/common_audio/fir_filter_neon.cc b/third_party/libwebrtc/common_audio/fir_filter_neon.cc new file mode 100644 index 0000000000..346cb69f5f --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_neon.cc @@ -0,0 +1,73 @@ +/* + * 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 "common_audio/fir_filter_neon.h" + +#include <arm_neon.h> +#include <string.h> + +#include "rtc_base/checks.h" +#include "rtc_base/memory/aligned_malloc.h" + +namespace webrtc { + +FIRFilterNEON::~FIRFilterNEON() {} + +FIRFilterNEON::FIRFilterNEON(const float* coefficients, + size_t coefficients_length, + size_t max_input_length) + : // Closest higher multiple of four. + coefficients_length_((coefficients_length + 3) & ~0x03), + state_length_(coefficients_length_ - 1), + coefficients_(static_cast<float*>( + AlignedMalloc(sizeof(float) * coefficients_length_, 16))), + state_(static_cast<float*>( + AlignedMalloc(sizeof(float) * (max_input_length + state_length_), + 16))) { + // Add zeros at the end of the coefficients. + size_t padding = coefficients_length_ - coefficients_length; + memset(coefficients_.get(), 0.f, padding * sizeof(coefficients_[0])); + // The coefficients are reversed to compensate for the order in which the + // input samples are acquired (most recent last). + for (size_t i = 0; i < coefficients_length; ++i) { + coefficients_[i + padding] = coefficients[coefficients_length - i - 1]; + } + memset(state_.get(), 0.f, + (max_input_length + state_length_) * sizeof(state_[0])); +} + +void FIRFilterNEON::Filter(const float* in, size_t length, float* out) { + RTC_DCHECK_GT(length, 0); + + memcpy(&state_[state_length_], in, length * sizeof(*in)); + + // Convolves the input signal `in` with the filter kernel `coefficients_` + // taking into account the previous state. + for (size_t i = 0; i < length; ++i) { + float* in_ptr = &state_[i]; + float* coef_ptr = coefficients_.get(); + + float32x4_t m_sum = vmovq_n_f32(0); + float32x4_t m_in; + + for (size_t j = 0; j < coefficients_length_; j += 4) { + m_in = vld1q_f32(in_ptr + j); + m_sum = vmlaq_f32(m_sum, m_in, vld1q_f32(coef_ptr + j)); + } + + float32x2_t m_half = vadd_f32(vget_high_f32(m_sum), vget_low_f32(m_sum)); + out[i] = vget_lane_f32(vpadd_f32(m_half, m_half), 0); + } + + // Update current state. + memmove(state_.get(), &state_[length], state_length_ * sizeof(state_[0])); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/fir_filter_neon.h b/third_party/libwebrtc/common_audio/fir_filter_neon.h new file mode 100644 index 0000000000..1ffefd80dc --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_neon.h @@ -0,0 +1,39 @@ +/* + * 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 COMMON_AUDIO_FIR_FILTER_NEON_H_ +#define COMMON_AUDIO_FIR_FILTER_NEON_H_ + +#include <memory> + +#include "common_audio/fir_filter.h" +#include "rtc_base/memory/aligned_malloc.h" + +namespace webrtc { + +class FIRFilterNEON : public FIRFilter { + public: + FIRFilterNEON(const float* coefficients, + size_t coefficients_length, + size_t max_input_length); + ~FIRFilterNEON() override; + + void Filter(const float* in, size_t length, float* out) override; + + private: + size_t coefficients_length_; + size_t state_length_; + std::unique_ptr<float[], AlignedFreeDeleter> coefficients_; + std::unique_ptr<float[], AlignedFreeDeleter> state_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_FIR_FILTER_NEON_H_ diff --git a/third_party/libwebrtc/common_audio/fir_filter_sse.cc b/third_party/libwebrtc/common_audio/fir_filter_sse.cc new file mode 100644 index 0000000000..0e45994a1d --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_sse.cc @@ -0,0 +1,82 @@ +/* + * 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 "common_audio/fir_filter_sse.h" + +#include <stdint.h> +#include <string.h> +#include <xmmintrin.h> + +#include "rtc_base/checks.h" +#include "rtc_base/memory/aligned_malloc.h" + +namespace webrtc { + +FIRFilterSSE2::~FIRFilterSSE2() {} + +FIRFilterSSE2::FIRFilterSSE2(const float* coefficients, + size_t coefficients_length, + size_t max_input_length) + : // Closest higher multiple of four. + coefficients_length_((coefficients_length + 3) & ~0x03), + state_length_(coefficients_length_ - 1), + coefficients_(static_cast<float*>( + AlignedMalloc(sizeof(float) * coefficients_length_, 16))), + state_(static_cast<float*>( + AlignedMalloc(sizeof(float) * (max_input_length + state_length_), + 16))) { + // Add zeros at the end of the coefficients. + size_t padding = coefficients_length_ - coefficients_length; + memset(coefficients_.get(), 0, padding * sizeof(coefficients_[0])); + // The coefficients are reversed to compensate for the order in which the + // input samples are acquired (most recent last). + for (size_t i = 0; i < coefficients_length; ++i) { + coefficients_[i + padding] = coefficients[coefficients_length - i - 1]; + } + memset(state_.get(), 0, + (max_input_length + state_length_) * sizeof(state_[0])); +} + +void FIRFilterSSE2::Filter(const float* in, size_t length, float* out) { + RTC_DCHECK_GT(length, 0); + + memcpy(&state_[state_length_], in, length * sizeof(*in)); + + // Convolves the input signal `in` with the filter kernel `coefficients_` + // taking into account the previous state. + for (size_t i = 0; i < length; ++i) { + float* in_ptr = &state_[i]; + float* coef_ptr = coefficients_.get(); + + __m128 m_sum = _mm_setzero_ps(); + __m128 m_in; + + // Depending on if the pointer is aligned with 16 bytes or not it is loaded + // differently. + if (reinterpret_cast<uintptr_t>(in_ptr) & 0x0F) { + for (size_t j = 0; j < coefficients_length_; j += 4) { + m_in = _mm_loadu_ps(in_ptr + j); + m_sum = _mm_add_ps(m_sum, _mm_mul_ps(m_in, _mm_load_ps(coef_ptr + j))); + } + } else { + for (size_t j = 0; j < coefficients_length_; j += 4) { + m_in = _mm_load_ps(in_ptr + j); + m_sum = _mm_add_ps(m_sum, _mm_mul_ps(m_in, _mm_load_ps(coef_ptr + j))); + } + } + m_sum = _mm_add_ps(_mm_movehl_ps(m_sum, m_sum), m_sum); + _mm_store_ss(out + i, _mm_add_ss(m_sum, _mm_shuffle_ps(m_sum, m_sum, 1))); + } + + // Update current state. + memmove(state_.get(), &state_[length], state_length_ * sizeof(state_[0])); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/fir_filter_sse.h b/third_party/libwebrtc/common_audio/fir_filter_sse.h new file mode 100644 index 0000000000..32f4945acc --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_sse.h @@ -0,0 +1,41 @@ +/* + * 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 COMMON_AUDIO_FIR_FILTER_SSE_H_ +#define COMMON_AUDIO_FIR_FILTER_SSE_H_ + +#include <stddef.h> + +#include <memory> + +#include "common_audio/fir_filter.h" +#include "rtc_base/memory/aligned_malloc.h" + +namespace webrtc { + +class FIRFilterSSE2 : public FIRFilter { + public: + FIRFilterSSE2(const float* coefficients, + size_t coefficients_length, + size_t max_input_length); + ~FIRFilterSSE2() override; + + void Filter(const float* in, size_t length, float* out) override; + + private: + size_t coefficients_length_; + size_t state_length_; + std::unique_ptr<float[], AlignedFreeDeleter> coefficients_; + std::unique_ptr<float[], AlignedFreeDeleter> state_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_FIR_FILTER_SSE_H_ diff --git a/third_party/libwebrtc/common_audio/fir_filter_unittest.cc b/third_party/libwebrtc/common_audio/fir_filter_unittest.cc new file mode 100644 index 0000000000..5c5880b5eb --- /dev/null +++ b/third_party/libwebrtc/common_audio/fir_filter_unittest.cc @@ -0,0 +1,208 @@ +/* + * 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 "common_audio/fir_filter.h" + +#include <string.h> + +#include <memory> + +#include "common_audio/fir_filter_factory.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +static const float kCoefficients[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f}; +static const size_t kCoefficientsLength = + sizeof(kCoefficients) / sizeof(kCoefficients[0]); + +static const float kInput[] = {1.f, 2.f, 3.f, 4.f, 5.f, + 6.f, 7.f, 8.f, 9.f, 10.f}; +static const size_t kInputLength = sizeof(kInput) / sizeof(kInput[0]); + +void VerifyOutput(const float* expected_output, + const float* output, + size_t length) { + EXPECT_EQ( + 0, memcmp(expected_output, output, length * sizeof(expected_output[0]))); +} + +} // namespace + +TEST(FIRFilterTest, FilterAsIdentity) { + const float kCoefficients[] = {1.f, 0.f, 0.f, 0.f, 0.f}; + float output[kInputLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength)); + filter->Filter(kInput, kInputLength, output); + + VerifyOutput(kInput, output, kInputLength); +} + +TEST(FIRFilterTest, FilterUsedAsScalarMultiplication) { + const float kCoefficients[] = {5.f, 0.f, 0.f, 0.f, 0.f}; + float output[kInputLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength)); + filter->Filter(kInput, kInputLength, output); + + EXPECT_FLOAT_EQ(5.f, output[0]); + EXPECT_FLOAT_EQ(20.f, output[3]); + EXPECT_FLOAT_EQ(25.f, output[4]); + EXPECT_FLOAT_EQ(50.f, output[kInputLength - 1]); +} + +TEST(FIRFilterTest, FilterUsedAsInputShifting) { + const float kCoefficients[] = {0.f, 0.f, 0.f, 0.f, 1.f}; + float output[kInputLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength)); + filter->Filter(kInput, kInputLength, output); + + EXPECT_FLOAT_EQ(0.f, output[0]); + EXPECT_FLOAT_EQ(0.f, output[3]); + EXPECT_FLOAT_EQ(1.f, output[4]); + EXPECT_FLOAT_EQ(2.f, output[5]); + EXPECT_FLOAT_EQ(6.f, output[kInputLength - 1]); +} + +TEST(FIRFilterTest, FilterUsedAsArbitraryWeighting) { + float output[kInputLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength)); + filter->Filter(kInput, kInputLength, output); + + EXPECT_FLOAT_EQ(0.2f, output[0]); + EXPECT_FLOAT_EQ(3.4f, output[3]); + EXPECT_FLOAT_EQ(5.21f, output[4]); + EXPECT_FLOAT_EQ(7.02f, output[5]); + EXPECT_FLOAT_EQ(14.26f, output[kInputLength - 1]); +} + +TEST(FIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) { + float output[kInputLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, 2)); + filter->Filter(kInput, 2, output); + + EXPECT_FLOAT_EQ(0.2f, output[0]); + EXPECT_FLOAT_EQ(0.7f, output[1]); + filter.reset( + CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength)); + filter->Filter(kInput, kCoefficientsLength, output); + + EXPECT_FLOAT_EQ(0.2f, output[0]); + EXPECT_FLOAT_EQ(3.4f, output[3]); + EXPECT_FLOAT_EQ(5.21f, output[4]); +} + +TEST(FIRFilterTest, MultipleFilterCalls) { + float output[kInputLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, 3)); + filter->Filter(kInput, 2, output); + EXPECT_FLOAT_EQ(0.2f, output[0]); + EXPECT_FLOAT_EQ(0.7f, output[1]); + + filter->Filter(kInput, 2, output); + EXPECT_FLOAT_EQ(1.3f, output[0]); + EXPECT_FLOAT_EQ(2.4f, output[1]); + + filter->Filter(kInput, 2, output); + EXPECT_FLOAT_EQ(2.81f, output[0]); + EXPECT_FLOAT_EQ(2.62f, output[1]); + + filter->Filter(kInput, 2, output); + EXPECT_FLOAT_EQ(2.81f, output[0]); + EXPECT_FLOAT_EQ(2.62f, output[1]); + + filter->Filter(&kInput[3], 3, output); + EXPECT_FLOAT_EQ(3.41f, output[0]); + EXPECT_FLOAT_EQ(4.12f, output[1]); + EXPECT_FLOAT_EQ(6.21f, output[2]); + + filter->Filter(&kInput[3], 3, output); + EXPECT_FLOAT_EQ(8.12f, output[0]); + EXPECT_FLOAT_EQ(9.14f, output[1]); + EXPECT_FLOAT_EQ(9.45f, output[2]); +} + +TEST(FIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) { + float output_block_based[kInputLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, kInputLength)); + filter->Filter(kInput, kInputLength, output_block_based); + + float output_sample_based[kInputLength]; + filter.reset(CreateFirFilter(kCoefficients, kCoefficientsLength, 1)); + for (size_t i = 0; i < kInputLength; ++i) { + filter->Filter(&kInput[i], 1, &output_sample_based[i]); + } + + EXPECT_EQ(0, memcmp(output_sample_based, output_block_based, kInputLength)); +} + +TEST(FIRFilterTest, SimplestHighPassFilter) { + const float kCoefficients[] = {1.f, -1.f}; + const size_t kCoefficientsLength = + sizeof(kCoefficients) / sizeof(kCoefficients[0]); + + float kConstantInput[] = {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f}; + const size_t kConstantInputLength = + sizeof(kConstantInput) / sizeof(kConstantInput[0]); + + float output[kConstantInputLength]; + std::unique_ptr<FIRFilter> filter(CreateFirFilter( + kCoefficients, kCoefficientsLength, kConstantInputLength)); + filter->Filter(kConstantInput, kConstantInputLength, output); + EXPECT_FLOAT_EQ(1.f, output[0]); + for (size_t i = kCoefficientsLength - 1; i < kConstantInputLength; ++i) { + EXPECT_FLOAT_EQ(0.f, output[i]); + } +} + +TEST(FIRFilterTest, SimplestLowPassFilter) { + const float kCoefficients[] = {1.f, 1.f}; + const size_t kCoefficientsLength = + sizeof(kCoefficients) / sizeof(kCoefficients[0]); + + float kHighFrequencyInput[] = {-1.f, 1.f, -1.f, 1.f, -1.f, 1.f, -1.f, 1.f}; + const size_t kHighFrequencyInputLength = + sizeof(kHighFrequencyInput) / sizeof(kHighFrequencyInput[0]); + + float output[kHighFrequencyInputLength]; + std::unique_ptr<FIRFilter> filter(CreateFirFilter( + kCoefficients, kCoefficientsLength, kHighFrequencyInputLength)); + filter->Filter(kHighFrequencyInput, kHighFrequencyInputLength, output); + EXPECT_FLOAT_EQ(-1.f, output[0]); + for (size_t i = kCoefficientsLength - 1; i < kHighFrequencyInputLength; ++i) { + EXPECT_FLOAT_EQ(0.f, output[i]); + } +} + +TEST(FIRFilterTest, SameOutputWhenSwapedCoefficientsAndInput) { + float output[kCoefficientsLength]; + float output_swaped[kCoefficientsLength]; + std::unique_ptr<FIRFilter> filter( + CreateFirFilter(kCoefficients, kCoefficientsLength, kCoefficientsLength)); + // Use kCoefficientsLength for in_length to get same-length outputs. + filter->Filter(kInput, kCoefficientsLength, output); + + filter.reset( + CreateFirFilter(kInput, kCoefficientsLength, kCoefficientsLength)); + filter->Filter(kCoefficients, kCoefficientsLength, output_swaped); + + for (size_t i = 0; i < kCoefficientsLength; ++i) { + EXPECT_FLOAT_EQ(output[i], output_swaped[i]); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/include/audio_util.h b/third_party/libwebrtc/common_audio/include/audio_util.h new file mode 100644 index 0000000000..4ce46800f1 --- /dev/null +++ b/third_party/libwebrtc/common_audio/include/audio_util.h @@ -0,0 +1,214 @@ +/* + * 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 COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ +#define COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ + +#include <stdint.h> + +#include <algorithm> +#include <cmath> +#include <cstring> +#include <limits> + +#include "rtc_base/checks.h" + +namespace webrtc { + +typedef std::numeric_limits<int16_t> limits_int16; + +// The conversion functions use the following naming convention: +// S16: int16_t [-32768, 32767] +// Float: float [-1.0, 1.0] +// FloatS16: float [-32768.0, 32768.0] +// Dbfs: float [-20.0*log(10, 32768), 0] = [-90.3, 0] +// The ratio conversion functions use this naming convention: +// Ratio: float (0, +inf) +// Db: float (-inf, +inf) +static inline float S16ToFloat(int16_t v) { + constexpr float kScaling = 1.f / 32768.f; + return v * kScaling; +} + +static inline int16_t FloatS16ToS16(float v) { + v = std::min(v, 32767.f); + v = std::max(v, -32768.f); + return static_cast<int16_t>(v + std::copysign(0.5f, v)); +} + +static inline int16_t FloatToS16(float v) { + v *= 32768.f; + v = std::min(v, 32767.f); + v = std::max(v, -32768.f); + return static_cast<int16_t>(v + std::copysign(0.5f, v)); +} + +static inline float FloatToFloatS16(float v) { + v = std::min(v, 1.f); + v = std::max(v, -1.f); + return v * 32768.f; +} + +static inline float FloatS16ToFloat(float v) { + v = std::min(v, 32768.f); + v = std::max(v, -32768.f); + constexpr float kScaling = 1.f / 32768.f; + return v * kScaling; +} + +void FloatToS16(const float* src, size_t size, int16_t* dest); +void S16ToFloat(const int16_t* src, size_t size, float* dest); +void S16ToFloatS16(const int16_t* src, size_t size, float* dest); +void FloatS16ToS16(const float* src, size_t size, int16_t* dest); +void FloatToFloatS16(const float* src, size_t size, float* dest); +void FloatS16ToFloat(const float* src, size_t size, float* dest); + +inline float DbToRatio(float v) { + return std::pow(10.0f, v / 20.0f); +} + +inline float DbfsToFloatS16(float v) { + static constexpr float kMaximumAbsFloatS16 = -limits_int16::min(); + return DbToRatio(v) * kMaximumAbsFloatS16; +} + +inline float FloatS16ToDbfs(float v) { + RTC_DCHECK_GE(v, 0); + + // kMinDbfs is equal to -20.0 * log10(-limits_int16::min()) + static constexpr float kMinDbfs = -90.30899869919436f; + if (v <= 1.0f) { + return kMinDbfs; + } + // Equal to 20 * log10(v / (-limits_int16::min())) + return 20.0f * std::log10(v) + kMinDbfs; +} + +// Copy audio from `src` channels to `dest` channels unless `src` and `dest` +// point to the same address. `src` and `dest` must have the same number of +// channels, and there must be sufficient space allocated in `dest`. +template <typename T> +void CopyAudioIfNeeded(const T* const* src, + int num_frames, + int num_channels, + T* const* dest) { + for (int i = 0; i < num_channels; ++i) { + if (src[i] != dest[i]) { + std::copy(src[i], src[i] + num_frames, dest[i]); + } + } +} + +// Deinterleave audio from `interleaved` to the channel buffers pointed to +// by `deinterleaved`. There must be sufficient space allocated in the +// `deinterleaved` buffers (`num_channel` buffers with `samples_per_channel` +// per buffer). +template <typename T> +void Deinterleave(const T* interleaved, + size_t samples_per_channel, + size_t num_channels, + T* const* deinterleaved) { + for (size_t i = 0; i < num_channels; ++i) { + T* channel = deinterleaved[i]; + size_t interleaved_idx = i; + for (size_t j = 0; j < samples_per_channel; ++j) { + channel[j] = interleaved[interleaved_idx]; + interleaved_idx += num_channels; + } + } +} + +// Interleave audio from the channel buffers pointed to by `deinterleaved` to +// `interleaved`. There must be sufficient space allocated in `interleaved` +// (`samples_per_channel` * `num_channels`). +template <typename T> +void Interleave(const T* const* deinterleaved, + size_t samples_per_channel, + size_t num_channels, + T* interleaved) { + for (size_t i = 0; i < num_channels; ++i) { + const T* channel = deinterleaved[i]; + size_t interleaved_idx = i; + for (size_t j = 0; j < samples_per_channel; ++j) { + interleaved[interleaved_idx] = channel[j]; + interleaved_idx += num_channels; + } + } +} + +// Copies audio from a single channel buffer pointed to by `mono` to each +// channel of `interleaved`. There must be sufficient space allocated in +// `interleaved` (`samples_per_channel` * `num_channels`). +template <typename T> +void UpmixMonoToInterleaved(const T* mono, + int num_frames, + int num_channels, + T* interleaved) { + int interleaved_idx = 0; + for (int i = 0; i < num_frames; ++i) { + for (int j = 0; j < num_channels; ++j) { + interleaved[interleaved_idx++] = mono[i]; + } + } +} + +template <typename T, typename Intermediate> +void DownmixToMono(const T* const* input_channels, + size_t num_frames, + int num_channels, + T* out) { + for (size_t i = 0; i < num_frames; ++i) { + Intermediate value = input_channels[0][i]; + for (int j = 1; j < num_channels; ++j) { + value += input_channels[j][i]; + } + out[i] = value / num_channels; + } +} + +// Downmixes an interleaved multichannel signal to a single channel by averaging +// all channels. +template <typename T, typename Intermediate> +void DownmixInterleavedToMonoImpl(const T* interleaved, + size_t num_frames, + int num_channels, + T* deinterleaved) { + RTC_DCHECK_GT(num_channels, 0); + RTC_DCHECK_GT(num_frames, 0); + + const T* const end = interleaved + num_frames * num_channels; + + while (interleaved < end) { + const T* const frame_end = interleaved + num_channels; + + Intermediate value = *interleaved++; + while (interleaved < frame_end) { + value += *interleaved++; + } + + *deinterleaved++ = value / num_channels; + } +} + +template <typename T> +void DownmixInterleavedToMono(const T* interleaved, + size_t num_frames, + int num_channels, + T* deinterleaved); + +template <> +void DownmixInterleavedToMono<int16_t>(const int16_t* interleaved, + size_t num_frames, + int num_channels, + int16_t* deinterleaved); + +} // namespace webrtc + +#endif // COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_ diff --git a/third_party/libwebrtc/common_audio/intrin.h b/third_party/libwebrtc/common_audio/intrin.h new file mode 100644 index 0000000000..f6ff7f218f --- /dev/null +++ b/third_party/libwebrtc/common_audio/intrin.h @@ -0,0 +1,8 @@ +#if defined (__SSE__) + #include <immintrin.h> + #if defined (__clang__) + #include <avxintrin.h> + #include <avx2intrin.h> + #include <fmaintrin.h> + #endif +#endif diff --git a/third_party/libwebrtc/common_audio/mocks/mock_smoothing_filter.h b/third_party/libwebrtc/common_audio/mocks/mock_smoothing_filter.h new file mode 100644 index 0000000000..9df49dd11a --- /dev/null +++ b/third_party/libwebrtc/common_audio/mocks/mock_smoothing_filter.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_AUDIO_MOCKS_MOCK_SMOOTHING_FILTER_H_ +#define COMMON_AUDIO_MOCKS_MOCK_SMOOTHING_FILTER_H_ + +#include "common_audio/smoothing_filter.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockSmoothingFilter : public SmoothingFilter { + public: + MOCK_METHOD(void, AddSample, (float), (override)); + MOCK_METHOD(absl::optional<float>, GetAverage, (), (override)); + MOCK_METHOD(bool, SetTimeConstantMs, (int), (override)); +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_MOCKS_MOCK_SMOOTHING_FILTER_H_ diff --git a/third_party/libwebrtc/common_audio/real_fourier.cc b/third_party/libwebrtc/common_audio/real_fourier.cc new file mode 100644 index 0000000000..7365844e8d --- /dev/null +++ b/third_party/libwebrtc/common_audio/real_fourier.cc @@ -0,0 +1,51 @@ +/* + * 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 "common_audio/real_fourier.h" + +#include "common_audio/real_fourier_ooura.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +using std::complex; + +const size_t RealFourier::kFftBufferAlignment = 32; + +std::unique_ptr<RealFourier> RealFourier::Create(int fft_order) { + return std::unique_ptr<RealFourier>(new RealFourierOoura(fft_order)); +} + +int RealFourier::FftOrder(size_t length) { + RTC_CHECK_GT(length, 0U); + return WebRtcSpl_GetSizeInBits(static_cast<uint32_t>(length - 1)); +} + +size_t RealFourier::FftLength(int order) { + RTC_CHECK_GE(order, 0); + return size_t{1} << order; +} + +size_t RealFourier::ComplexLength(int order) { + return FftLength(order) / 2 + 1; +} + +RealFourier::fft_real_scoper RealFourier::AllocRealBuffer(int count) { + return fft_real_scoper(static_cast<float*>( + AlignedMalloc(sizeof(float) * count, kFftBufferAlignment))); +} + +RealFourier::fft_cplx_scoper RealFourier::AllocCplxBuffer(int count) { + return fft_cplx_scoper(static_cast<complex<float>*>( + AlignedMalloc(sizeof(complex<float>) * count, kFftBufferAlignment))); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/real_fourier.h b/third_party/libwebrtc/common_audio/real_fourier.h new file mode 100644 index 0000000000..78a4fc6662 --- /dev/null +++ b/third_party/libwebrtc/common_audio/real_fourier.h @@ -0,0 +1,76 @@ +/* + * 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 COMMON_AUDIO_REAL_FOURIER_H_ +#define COMMON_AUDIO_REAL_FOURIER_H_ + +#include <stddef.h> + +#include <complex> +#include <memory> + +#include "rtc_base/memory/aligned_malloc.h" + +// Uniform interface class for the real DFT and its inverse, for power-of-2 +// input lengths. Also contains helper functions for buffer allocation, taking +// care of any memory alignment requirements the underlying library might have. + +namespace webrtc { + +class RealFourier { + public: + // Shorthand typenames for the scopers used by the buffer allocation helpers. + typedef std::unique_ptr<float[], AlignedFreeDeleter> fft_real_scoper; + typedef std::unique_ptr<std::complex<float>[], AlignedFreeDeleter> + fft_cplx_scoper; + + // The alignment required for all input and output buffers, in bytes. + static const size_t kFftBufferAlignment; + + // Construct a wrapper instance for the given input order, which must be + // between 1 and kMaxFftOrder, inclusively. + static std::unique_ptr<RealFourier> Create(int fft_order); + virtual ~RealFourier() {} + + // Helper to compute the smallest FFT order (a power of 2) which will contain + // the given input length. + static int FftOrder(size_t length); + + // Helper to compute the input length from the FFT order. + static size_t FftLength(int order); + + // Helper to compute the exact length, in complex floats, of the transform + // output (i.e. |2^order / 2 + 1|). + static size_t ComplexLength(int order); + + // Buffer allocation helpers. The buffers are large enough to hold `count` + // floats/complexes and suitably aligned for use by the implementation. + // The returned scopers are set up with proper deleters; the caller owns + // the allocated memory. + static fft_real_scoper AllocRealBuffer(int count); + static fft_cplx_scoper AllocCplxBuffer(int count); + + // Main forward transform interface. The output array need only be big + // enough for |2^order / 2 + 1| elements - the conjugate pairs are not + // returned. Input and output must be properly aligned (e.g. through + // AllocRealBuffer and AllocCplxBuffer) and input length must be + // |2^order| (same as given at construction time). + virtual void Forward(const float* src, std::complex<float>* dest) const = 0; + + // Inverse transform. Same input format as output above, conjugate pairs + // not needed. + virtual void Inverse(const std::complex<float>* src, float* dest) const = 0; + + virtual int order() const = 0; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_REAL_FOURIER_H_ diff --git a/third_party/libwebrtc/common_audio/real_fourier_ooura.cc b/third_party/libwebrtc/common_audio/real_fourier_ooura.cc new file mode 100644 index 0000000000..9acda5494c --- /dev/null +++ b/third_party/libwebrtc/common_audio/real_fourier_ooura.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2015 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 "common_audio/real_fourier_ooura.h" + +#include <algorithm> +#include <cmath> + +#include "common_audio/third_party/ooura/fft_size_256/fft4g.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +using std::complex; + +namespace { + +void Conjugate(complex<float>* array, size_t complex_length) { + std::for_each(array, array + complex_length, + [=](complex<float>& v) { v = std::conj(v); }); +} + +size_t ComputeWorkIpSize(size_t fft_length) { + return static_cast<size_t>( + 2 + std::ceil(std::sqrt(static_cast<float>(fft_length)))); +} + +} // namespace + +RealFourierOoura::RealFourierOoura(int fft_order) + : order_(fft_order), + length_(FftLength(order_)), + complex_length_(ComplexLength(order_)), + // Zero-initializing work_ip_ will cause rdft to initialize these work + // arrays on the first call. + work_ip_(new size_t[ComputeWorkIpSize(length_)]()), + work_w_(new float[complex_length_]()) { + RTC_CHECK_GE(fft_order, 1); +} + +RealFourierOoura::~RealFourierOoura() = default; + +void RealFourierOoura::Forward(const float* src, complex<float>* dest) const { + { + // This cast is well-defined since C++11. See "Non-static data members" at: + // http://en.cppreference.com/w/cpp/numeric/complex + auto* dest_float = reinterpret_cast<float*>(dest); + std::copy(src, src + length_, dest_float); + WebRtc_rdft(length_, 1, dest_float, work_ip_.get(), work_w_.get()); + } + + // Ooura places real[n/2] in imag[0]. + dest[complex_length_ - 1] = complex<float>(dest[0].imag(), 0.0f); + dest[0] = complex<float>(dest[0].real(), 0.0f); + // Ooura returns the conjugate of the usual Fourier definition. + Conjugate(dest, complex_length_); +} + +void RealFourierOoura::Inverse(const complex<float>* src, float* dest) const { + { + auto* dest_complex = reinterpret_cast<complex<float>*>(dest); + // The real output array is shorter than the input complex array by one + // complex element. + const size_t dest_complex_length = complex_length_ - 1; + std::copy(src, src + dest_complex_length, dest_complex); + // Restore Ooura's conjugate definition. + Conjugate(dest_complex, dest_complex_length); + // Restore real[n/2] to imag[0]. + dest_complex[0] = + complex<float>(dest_complex[0].real(), src[complex_length_ - 1].real()); + } + + WebRtc_rdft(length_, -1, dest, work_ip_.get(), work_w_.get()); + + // Ooura returns a scaled version. + const float scale = 2.0f / length_; + std::for_each(dest, dest + length_, [scale](float& v) { v *= scale; }); +} + +int RealFourierOoura::order() const { + return order_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/real_fourier_ooura.h b/third_party/libwebrtc/common_audio/real_fourier_ooura.h new file mode 100644 index 0000000000..ae85dfd0dd --- /dev/null +++ b/third_party/libwebrtc/common_audio/real_fourier_ooura.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2015 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 COMMON_AUDIO_REAL_FOURIER_OOURA_H_ +#define COMMON_AUDIO_REAL_FOURIER_OOURA_H_ + +#include <stddef.h> + +#include <complex> +#include <memory> + +#include "common_audio/real_fourier.h" + +namespace webrtc { + +class RealFourierOoura : public RealFourier { + public: + explicit RealFourierOoura(int fft_order); + ~RealFourierOoura() override; + + void Forward(const float* src, std::complex<float>* dest) const override; + void Inverse(const std::complex<float>* src, float* dest) const override; + + int order() const override; + + private: + const int order_; + const size_t length_; + const size_t complex_length_; + // These are work arrays for Ooura. The names are based on the comments in + // common_audio/third_party/ooura/fft_size_256/fft4g.cc. + const std::unique_ptr<size_t[]> work_ip_; + const std::unique_ptr<float[]> work_w_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_REAL_FOURIER_OOURA_H_ diff --git a/third_party/libwebrtc/common_audio/real_fourier_unittest.cc b/third_party/libwebrtc/common_audio/real_fourier_unittest.cc new file mode 100644 index 0000000000..eac4fce42e --- /dev/null +++ b/third_party/libwebrtc/common_audio/real_fourier_unittest.cc @@ -0,0 +1,102 @@ +/* + * 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 "common_audio/real_fourier.h" + +#include <stdlib.h> + +#include "common_audio/real_fourier_ooura.h" +#include "test/gtest.h" + +namespace webrtc { + +using std::complex; + +TEST(RealFourierStaticsTest, AllocatorAlignment) { + { + RealFourier::fft_real_scoper real; + real = RealFourier::AllocRealBuffer(3); + ASSERT_TRUE(real.get() != nullptr); + uintptr_t ptr_value = reinterpret_cast<uintptr_t>(real.get()); + EXPECT_EQ(0u, ptr_value % RealFourier::kFftBufferAlignment); + } + { + RealFourier::fft_cplx_scoper cplx; + cplx = RealFourier::AllocCplxBuffer(3); + ASSERT_TRUE(cplx.get() != nullptr); + uintptr_t ptr_value = reinterpret_cast<uintptr_t>(cplx.get()); + EXPECT_EQ(0u, ptr_value % RealFourier::kFftBufferAlignment); + } +} + +TEST(RealFourierStaticsTest, OrderComputation) { + EXPECT_EQ(4, RealFourier::FftOrder(13)); + EXPECT_EQ(5, RealFourier::FftOrder(32)); + EXPECT_EQ(1, RealFourier::FftOrder(2)); + EXPECT_EQ(0, RealFourier::FftOrder(1)); +} + +TEST(RealFourierStaticsTest, ComplexLengthComputation) { + EXPECT_EQ(2U, RealFourier::ComplexLength(1)); + EXPECT_EQ(3U, RealFourier::ComplexLength(2)); + EXPECT_EQ(5U, RealFourier::ComplexLength(3)); + EXPECT_EQ(9U, RealFourier::ComplexLength(4)); + EXPECT_EQ(17U, RealFourier::ComplexLength(5)); + EXPECT_EQ(65U, RealFourier::ComplexLength(7)); +} + +template <typename T> +class RealFourierTest : public ::testing::Test { + protected: + RealFourierTest() + : rf_(2), + real_buffer_(RealFourier::AllocRealBuffer(4)), + cplx_buffer_(RealFourier::AllocCplxBuffer(3)) {} + + ~RealFourierTest() {} + + T rf_; + const RealFourier::fft_real_scoper real_buffer_; + const RealFourier::fft_cplx_scoper cplx_buffer_; +}; + +using FftTypes = ::testing::Types<RealFourierOoura>; +TYPED_TEST_SUITE(RealFourierTest, FftTypes); + +TYPED_TEST(RealFourierTest, SimpleForwardTransform) { + this->real_buffer_[0] = 1.0f; + this->real_buffer_[1] = 2.0f; + this->real_buffer_[2] = 3.0f; + this->real_buffer_[3] = 4.0f; + + this->rf_.Forward(this->real_buffer_.get(), this->cplx_buffer_.get()); + + EXPECT_NEAR(this->cplx_buffer_[0].real(), 10.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[0].imag(), 0.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[1].real(), -2.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[1].imag(), 2.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[2].real(), -2.0f, 1e-8f); + EXPECT_NEAR(this->cplx_buffer_[2].imag(), 0.0f, 1e-8f); +} + +TYPED_TEST(RealFourierTest, SimpleBackwardTransform) { + this->cplx_buffer_[0] = complex<float>(10.0f, 0.0f); + this->cplx_buffer_[1] = complex<float>(-2.0f, 2.0f); + this->cplx_buffer_[2] = complex<float>(-2.0f, 0.0f); + + this->rf_.Inverse(this->cplx_buffer_.get(), this->real_buffer_.get()); + + EXPECT_NEAR(this->real_buffer_[0], 1.0f, 1e-8f); + EXPECT_NEAR(this->real_buffer_[1], 2.0f, 1e-8f); + EXPECT_NEAR(this->real_buffer_[2], 3.0f, 1e-8f); + EXPECT_NEAR(this->real_buffer_[3], 4.0f, 1e-8f); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/include/push_resampler.h b/third_party/libwebrtc/common_audio/resampler/include/push_resampler.h new file mode 100644 index 0000000000..3da67120f0 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/include/push_resampler.h @@ -0,0 +1,59 @@ +/* + * 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 COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_ +#define COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_ + +#include <memory> +#include <vector> + +namespace webrtc { + +class PushSincResampler; + +// Wraps PushSincResampler to provide stereo support. +// TODO(ajm): add support for an arbitrary number of channels. +template <typename T> +class PushResampler { + public: + PushResampler(); + virtual ~PushResampler(); + + // Must be called whenever the parameters change. Free to be called at any + // time as it is a no-op if parameters have not changed since the last call. + int InitializeIfNeeded(int src_sample_rate_hz, + int dst_sample_rate_hz, + size_t num_channels); + + // Returns the total number of samples provided in destination (e.g. 32 kHz, + // 2 channel audio gives 640 samples). + int Resample(const T* src, size_t src_length, T* dst, size_t dst_capacity); + + private: + int src_sample_rate_hz_; + int dst_sample_rate_hz_; + size_t num_channels_; + // Vector that is needed to provide the proper inputs and outputs to the + // interleave/de-interleave methods used in Resample. This needs to be + // heap-allocated on the state to support an arbitrary number of channels + // without doing run-time heap-allocations in the Resample method. + std::vector<T*> channel_data_array_; + + struct ChannelResampler { + std::unique_ptr<PushSincResampler> resampler; + std::vector<T> source; + std::vector<T> destination; + }; + + std::vector<ChannelResampler> channel_resamplers_; +}; +} // namespace webrtc + +#endif // COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_ diff --git a/third_party/libwebrtc/common_audio/resampler/include/resampler.h b/third_party/libwebrtc/common_audio/resampler/include/resampler.h new file mode 100644 index 0000000000..41940f9a12 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/include/resampler.h @@ -0,0 +1,99 @@ +/* + * 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. + */ + +/* + * A wrapper for resampling a numerous amount of sampling combinations. + */ + +#ifndef COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_ +#define COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_ + +#include <stddef.h> +#include <stdint.h> + +namespace webrtc { + +// All methods return 0 on success and -1 on failure. +class Resampler { + public: + Resampler(); + Resampler(int inFreq, int outFreq, size_t num_channels); + ~Resampler(); + + // Reset all states + int Reset(int inFreq, int outFreq, size_t num_channels); + + // Reset all states if any parameter has changed + int ResetIfNeeded(int inFreq, int outFreq, size_t num_channels); + + // Resample samplesIn to samplesOut. + int Push(const int16_t* samplesIn, + size_t lengthIn, + int16_t* samplesOut, + size_t maxLen, + size_t& outLen); // NOLINT: to avoid changing APIs + + private: + enum ResamplerMode { + kResamplerMode1To1, + kResamplerMode1To2, + kResamplerMode1To3, + kResamplerMode1To4, + kResamplerMode1To6, + kResamplerMode1To12, + kResamplerMode2To3, + kResamplerMode2To11, + kResamplerMode4To11, + kResamplerMode8To11, + kResamplerMode11To16, + kResamplerMode11To32, + kResamplerMode2To1, + kResamplerMode3To1, + kResamplerMode4To1, + kResamplerMode6To1, + kResamplerMode12To1, + kResamplerMode3To2, + kResamplerMode11To2, + kResamplerMode11To4, + kResamplerMode11To8 + }; + + // Computes the resampler mode for a given sampling frequency pair. + // Returns -1 for unsupported frequency pairs. + static int ComputeResamplerMode(int in_freq_hz, + int out_freq_hz, + ResamplerMode* mode); + + // Generic pointers since we don't know what states we'll need + void* state1_; + void* state2_; + void* state3_; + + // Storage if needed + int16_t* in_buffer_; + int16_t* out_buffer_; + size_t in_buffer_size_; + size_t out_buffer_size_; + size_t in_buffer_size_max_; + size_t out_buffer_size_max_; + + int my_in_frequency_khz_; + int my_out_frequency_khz_; + ResamplerMode my_mode_; + size_t num_channels_; + + // Extra instance for stereo + Resampler* helper_left_; + Resampler* helper_right_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_RESAMPLER_INCLUDE_RESAMPLER_H_ diff --git a/third_party/libwebrtc/common_audio/resampler/push_resampler.cc b/third_party/libwebrtc/common_audio/resampler/push_resampler.cc new file mode 100644 index 0000000000..810d778993 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/push_resampler.cc @@ -0,0 +1,123 @@ +/* + * 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 "common_audio/resampler/include/push_resampler.h" + +#include <stdint.h> +#include <string.h> + +#include <memory> + +#include "common_audio/include/audio_util.h" +#include "common_audio/resampler/push_sinc_resampler.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +template <typename T> +PushResampler<T>::PushResampler() + : src_sample_rate_hz_(0), dst_sample_rate_hz_(0), num_channels_(0) {} + +template <typename T> +PushResampler<T>::~PushResampler() {} + +template <typename T> +int PushResampler<T>::InitializeIfNeeded(int src_sample_rate_hz, + int dst_sample_rate_hz, + size_t num_channels) { + // These checks used to be factored out of this template function due to + // Windows debug build issues with clang. http://crbug.com/615050 + RTC_DCHECK_GT(src_sample_rate_hz, 0); + RTC_DCHECK_GT(dst_sample_rate_hz, 0); + RTC_DCHECK_GT(num_channels, 0); + + if (src_sample_rate_hz == src_sample_rate_hz_ && + dst_sample_rate_hz == dst_sample_rate_hz_ && + num_channels == num_channels_) { + // No-op if settings haven't changed. + return 0; + } + + if (src_sample_rate_hz <= 0 || dst_sample_rate_hz <= 0 || num_channels <= 0) { + return -1; + } + + src_sample_rate_hz_ = src_sample_rate_hz; + dst_sample_rate_hz_ = dst_sample_rate_hz; + num_channels_ = num_channels; + + const size_t src_size_10ms_mono = + static_cast<size_t>(src_sample_rate_hz / 100); + const size_t dst_size_10ms_mono = + static_cast<size_t>(dst_sample_rate_hz / 100); + channel_resamplers_.clear(); + for (size_t i = 0; i < num_channels; ++i) { + channel_resamplers_.push_back(ChannelResampler()); + auto channel_resampler = channel_resamplers_.rbegin(); + channel_resampler->resampler = std::make_unique<PushSincResampler>( + src_size_10ms_mono, dst_size_10ms_mono); + channel_resampler->source.resize(src_size_10ms_mono); + channel_resampler->destination.resize(dst_size_10ms_mono); + } + + channel_data_array_.resize(num_channels_); + + return 0; +} + +template <typename T> +int PushResampler<T>::Resample(const T* src, + size_t src_length, + T* dst, + size_t dst_capacity) { + // These checks used to be factored out of this template function due to + // Windows debug build issues with clang. http://crbug.com/615050 + const size_t src_size_10ms = (src_sample_rate_hz_ / 100) * num_channels_; + const size_t dst_size_10ms = (dst_sample_rate_hz_ / 100) * num_channels_; + RTC_DCHECK_EQ(src_length, src_size_10ms); + RTC_DCHECK_GE(dst_capacity, dst_size_10ms); + + if (src_sample_rate_hz_ == dst_sample_rate_hz_) { + // The old resampler provides this memcpy facility in the case of matching + // sample rates, so reproduce it here for the sinc resampler. + memcpy(dst, src, src_length * sizeof(T)); + return static_cast<int>(src_length); + } + + const size_t src_length_mono = src_length / num_channels_; + const size_t dst_capacity_mono = dst_capacity / num_channels_; + + for (size_t ch = 0; ch < num_channels_; ++ch) { + channel_data_array_[ch] = channel_resamplers_[ch].source.data(); + } + + Deinterleave(src, src_length_mono, num_channels_, channel_data_array_.data()); + + size_t dst_length_mono = 0; + + for (auto& resampler : channel_resamplers_) { + dst_length_mono = resampler.resampler->Resample( + resampler.source.data(), src_length_mono, resampler.destination.data(), + dst_capacity_mono); + } + + for (size_t ch = 0; ch < num_channels_; ++ch) { + channel_data_array_[ch] = channel_resamplers_[ch].destination.data(); + } + + Interleave(channel_data_array_.data(), dst_length_mono, num_channels_, dst); + return static_cast<int>(dst_length_mono * num_channels_); +} + +// Explictly generate required instantiations. +template class PushResampler<int16_t>; +template class PushResampler<float>; + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/push_resampler_unittest.cc b/third_party/libwebrtc/common_audio/resampler/push_resampler_unittest.cc new file mode 100644 index 0000000000..91f2233aad --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/push_resampler_unittest.cc @@ -0,0 +1,48 @@ +/* + * 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 "common_audio/resampler/include/push_resampler.h" + +#include "rtc_base/checks.h" // RTC_DCHECK_IS_ON +#include "test/gtest.h" +#include "test/testsupport/rtc_expect_death.h" + +// Quality testing of PushResampler is done in audio/remix_resample_unittest.cc. + +namespace webrtc { + +TEST(PushResamplerTest, VerifiesInputParameters) { + PushResampler<int16_t> resampler; + EXPECT_EQ(0, resampler.InitializeIfNeeded(16000, 16000, 1)); + EXPECT_EQ(0, resampler.InitializeIfNeeded(16000, 16000, 2)); + EXPECT_EQ(0, resampler.InitializeIfNeeded(16000, 16000, 8)); +} + +#if RTC_DCHECK_IS_ON && GTEST_HAS_DEATH_TEST && !defined(WEBRTC_ANDROID) +TEST(PushResamplerDeathTest, VerifiesBadInputParameters1) { + PushResampler<int16_t> resampler; + RTC_EXPECT_DEATH(resampler.InitializeIfNeeded(-1, 16000, 1), + "src_sample_rate_hz"); +} + +TEST(PushResamplerDeathTest, VerifiesBadInputParameters2) { + PushResampler<int16_t> resampler; + RTC_EXPECT_DEATH(resampler.InitializeIfNeeded(16000, -1, 1), + "dst_sample_rate_hz"); +} + +TEST(PushResamplerDeathTest, VerifiesBadInputParameters3) { + PushResampler<int16_t> resampler; + RTC_EXPECT_DEATH(resampler.InitializeIfNeeded(16000, 16000, 0), + "num_channels"); +} +#endif + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler.cc b/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler.cc new file mode 100644 index 0000000000..d4b7eed026 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler.cc @@ -0,0 +1,102 @@ +/* + * 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 "common_audio/resampler/push_sinc_resampler.h" + +#include <cstring> + +#include "common_audio/include/audio_util.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +PushSincResampler::PushSincResampler(size_t source_frames, + size_t destination_frames) + : resampler_(new SincResampler(source_frames * 1.0 / destination_frames, + source_frames, + this)), + source_ptr_(nullptr), + source_ptr_int_(nullptr), + destination_frames_(destination_frames), + first_pass_(true), + source_available_(0) {} + +PushSincResampler::~PushSincResampler() {} + +size_t PushSincResampler::Resample(const int16_t* source, + size_t source_length, + int16_t* destination, + size_t destination_capacity) { + if (!float_buffer_.get()) + float_buffer_.reset(new float[destination_frames_]); + + source_ptr_int_ = source; + // Pass nullptr as the float source to have Run() read from the int16 source. + Resample(nullptr, source_length, float_buffer_.get(), destination_frames_); + FloatS16ToS16(float_buffer_.get(), destination_frames_, destination); + source_ptr_int_ = nullptr; + return destination_frames_; +} + +size_t PushSincResampler::Resample(const float* source, + size_t source_length, + float* destination, + size_t destination_capacity) { + RTC_CHECK_EQ(source_length, resampler_->request_frames()); + RTC_CHECK_GE(destination_capacity, destination_frames_); + // Cache the source pointer. Calling Resample() will immediately trigger + // the Run() callback whereupon we provide the cached value. + source_ptr_ = source; + source_available_ = source_length; + + // On the first pass, we call Resample() twice. During the first call, we + // provide dummy input and discard the output. This is done to prime the + // SincResampler buffer with the correct delay (half the kernel size), thereby + // ensuring that all later Resample() calls will only result in one input + // request through Run(). + // + // If this wasn't done, SincResampler would call Run() twice on the first + // pass, and we'd have to introduce an entire `source_frames` of delay, rather + // than the minimum half kernel. + // + // It works out that ChunkSize() is exactly the amount of output we need to + // request in order to prime the buffer with a single Run() request for + // `source_frames`. + if (first_pass_) + resampler_->Resample(resampler_->ChunkSize(), destination); + + resampler_->Resample(destination_frames_, destination); + source_ptr_ = nullptr; + return destination_frames_; +} + +void PushSincResampler::Run(size_t frames, float* destination) { + // Ensure we are only asked for the available samples. This would fail if + // Run() was triggered more than once per Resample() call. + RTC_CHECK_EQ(source_available_, frames); + + if (first_pass_) { + // Provide dummy input on the first pass, the output of which will be + // discarded, as described in Resample(). + std::memset(destination, 0, frames * sizeof(*destination)); + first_pass_ = false; + return; + } + + if (source_ptr_) { + std::memcpy(destination, source_ptr_, frames * sizeof(*destination)); + } else { + for (size_t i = 0; i < frames; ++i) + destination[i] = static_cast<float>(source_ptr_int_[i]); + } + source_available_ -= frames; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler.h b/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler.h new file mode 100644 index 0000000000..7946ef8f82 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler.h @@ -0,0 +1,81 @@ +/* + * 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 COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_ +#define COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_ + +#include <stddef.h> +#include <stdint.h> + +#include <memory> + +#include "common_audio/resampler/sinc_resampler.h" + +namespace webrtc { + +// A thin wrapper over SincResampler to provide a push-based interface as +// required by WebRTC. SincResampler uses a pull-based interface, and will +// use SincResamplerCallback::Run() to request data upon a call to Resample(). +// These Run() calls will happen on the same thread Resample() is called on. +class PushSincResampler : public SincResamplerCallback { + public: + // Provide the size of the source and destination blocks in samples. These + // must correspond to the same time duration (typically 10 ms) as the sample + // ratio is inferred from them. + PushSincResampler(size_t source_frames, size_t destination_frames); + ~PushSincResampler() override; + + PushSincResampler(const PushSincResampler&) = delete; + PushSincResampler& operator=(const PushSincResampler&) = delete; + + // Perform the resampling. `source_frames` must always equal the + // `source_frames` provided at construction. `destination_capacity` must be + // at least as large as `destination_frames`. Returns the number of samples + // provided in destination (for convenience, since this will always be equal + // to `destination_frames`). + size_t Resample(const int16_t* source, + size_t source_frames, + int16_t* destination, + size_t destination_capacity); + size_t Resample(const float* source, + size_t source_frames, + float* destination, + size_t destination_capacity); + + // Delay due to the filter kernel. Essentially, the time after which an input + // sample will appear in the resampled output. + static float AlgorithmicDelaySeconds(int source_rate_hz) { + return 1.f / source_rate_hz * SincResampler::kKernelSize / 2; + } + + protected: + // Implements SincResamplerCallback. + void Run(size_t frames, float* destination) override; + + private: + friend class PushSincResamplerTest; + SincResampler* get_resampler_for_testing() { return resampler_.get(); } + + std::unique_ptr<SincResampler> resampler_; + std::unique_ptr<float[]> float_buffer_; + const float* source_ptr_; + const int16_t* source_ptr_int_; + const size_t destination_frames_; + + // True on the first call to Resample(), to prime the SincResampler buffer. + bool first_pass_; + + // Used to assert we are only requested for as much data as is available. + size_t source_available_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_ diff --git a/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler_unittest.cc b/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler_unittest.cc new file mode 100644 index 0000000000..8f82199d1d --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/push_sinc_resampler_unittest.cc @@ -0,0 +1,367 @@ +/* + * 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 "common_audio/resampler/push_sinc_resampler.h" + +#include <algorithm> +#include <cmath> +#include <cstring> +#include <memory> + +#include "common_audio/include/audio_util.h" +#include "common_audio/resampler/sinusoidal_linear_chirp_source.h" +#include "rtc_base/time_utils.h" +#include "test/gmock.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +// Almost all conversions have an RMS error of around -14 dbFS. +const double kResamplingRMSError = -14.42; + +// Used to convert errors to dbFS. +template <typename T> +T DBFS(T x) { + return 20 * std::log10(x); +} + +} // namespace + +class PushSincResamplerTest : public ::testing::TestWithParam< + ::testing::tuple<int, int, double, double>> { + public: + PushSincResamplerTest() + : input_rate_(::testing::get<0>(GetParam())), + output_rate_(::testing::get<1>(GetParam())), + rms_error_(::testing::get<2>(GetParam())), + low_freq_error_(::testing::get<3>(GetParam())) {} + + ~PushSincResamplerTest() override {} + + protected: + void ResampleBenchmarkTest(bool int_format); + void ResampleTest(bool int_format); + + int input_rate_; + int output_rate_; + double rms_error_; + double low_freq_error_; +}; + +class ZeroSource : public SincResamplerCallback { + public: + void Run(size_t frames, float* destination) override { + std::memset(destination, 0, sizeof(float) * frames); + } +}; + +void PushSincResamplerTest::ResampleBenchmarkTest(bool int_format) { + const size_t input_samples = static_cast<size_t>(input_rate_ / 100); + const size_t output_samples = static_cast<size_t>(output_rate_ / 100); + const int kResampleIterations = 500000; + + // Source for data to be resampled. + ZeroSource resampler_source; + + std::unique_ptr<float[]> resampled_destination(new float[output_samples]); + std::unique_ptr<float[]> source(new float[input_samples]); + std::unique_ptr<int16_t[]> source_int(new int16_t[input_samples]); + std::unique_ptr<int16_t[]> destination_int(new int16_t[output_samples]); + + resampler_source.Run(input_samples, source.get()); + for (size_t i = 0; i < input_samples; ++i) { + source_int[i] = static_cast<int16_t>(floor(32767 * source[i] + 0.5)); + } + + printf("Benchmarking %d iterations of %d Hz -> %d Hz:\n", kResampleIterations, + input_rate_, output_rate_); + const double io_ratio = input_rate_ / static_cast<double>(output_rate_); + SincResampler sinc_resampler(io_ratio, SincResampler::kDefaultRequestSize, + &resampler_source); + int64_t start = rtc::TimeNanos(); + for (int i = 0; i < kResampleIterations; ++i) { + sinc_resampler.Resample(output_samples, resampled_destination.get()); + } + double total_time_sinc_us = + (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec; + printf("SincResampler took %.2f us per frame.\n", + total_time_sinc_us / kResampleIterations); + + PushSincResampler resampler(input_samples, output_samples); + start = rtc::TimeNanos(); + if (int_format) { + for (int i = 0; i < kResampleIterations; ++i) { + EXPECT_EQ(output_samples, + resampler.Resample(source_int.get(), input_samples, + destination_int.get(), output_samples)); + } + } else { + for (int i = 0; i < kResampleIterations; ++i) { + EXPECT_EQ(output_samples, resampler.Resample(source.get(), input_samples, + resampled_destination.get(), + output_samples)); + } + } + double total_time_us = + (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec; + printf( + "PushSincResampler took %.2f us per frame; which is a %.1f%% overhead " + "on SincResampler.\n\n", + total_time_us / kResampleIterations, + (total_time_us - total_time_sinc_us) / total_time_sinc_us * 100); +} + +// Disabled because it takes too long to run routinely. Use for performance +// benchmarking when needed. +TEST_P(PushSincResamplerTest, DISABLED_BenchmarkInt) { + ResampleBenchmarkTest(true); +} + +TEST_P(PushSincResamplerTest, DISABLED_BenchmarkFloat) { + ResampleBenchmarkTest(false); +} + +// Tests resampling using a given input and output sample rate. +void PushSincResamplerTest::ResampleTest(bool int_format) { + // Make comparisons using one second of data. + static const double kTestDurationSecs = 1; + // 10 ms blocks. + const size_t kNumBlocks = static_cast<size_t>(kTestDurationSecs * 100); + const size_t input_block_size = static_cast<size_t>(input_rate_ / 100); + const size_t output_block_size = static_cast<size_t>(output_rate_ / 100); + const size_t input_samples = + static_cast<size_t>(kTestDurationSecs * input_rate_); + const size_t output_samples = + static_cast<size_t>(kTestDurationSecs * output_rate_); + + // Nyquist frequency for the input sampling rate. + const double input_nyquist_freq = 0.5 * input_rate_; + + // Source for data to be resampled. + SinusoidalLinearChirpSource resampler_source(input_rate_, input_samples, + input_nyquist_freq, 0); + + PushSincResampler resampler(input_block_size, output_block_size); + + // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to + // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. + std::unique_ptr<float[]> resampled_destination(new float[output_samples]); + std::unique_ptr<float[]> pure_destination(new float[output_samples]); + std::unique_ptr<float[]> source(new float[input_samples]); + std::unique_ptr<int16_t[]> source_int(new int16_t[input_block_size]); + std::unique_ptr<int16_t[]> destination_int(new int16_t[output_block_size]); + + // The sinc resampler has an implicit delay of approximately half the kernel + // size at the input sample rate. By moving to a push model, this delay + // becomes explicit and is managed by zero-stuffing in PushSincResampler. We + // deal with it in the test by delaying the "pure" source to match. It must be + // checked before the first call to Resample(), because ChunkSize() will + // change afterwards. + const size_t output_delay_samples = + output_block_size - resampler.get_resampler_for_testing()->ChunkSize(); + + // Generate resampled signal. + // With the PushSincResampler, we produce the signal block-by-10ms-block + // rather than in a single pass, to exercise how it will be used in WebRTC. + resampler_source.Run(input_samples, source.get()); + if (int_format) { + for (size_t i = 0; i < kNumBlocks; ++i) { + FloatToS16(&source[i * input_block_size], input_block_size, + source_int.get()); + EXPECT_EQ(output_block_size, + resampler.Resample(source_int.get(), input_block_size, + destination_int.get(), output_block_size)); + S16ToFloat(destination_int.get(), output_block_size, + &resampled_destination[i * output_block_size]); + } + } else { + for (size_t i = 0; i < kNumBlocks; ++i) { + EXPECT_EQ( + output_block_size, + resampler.Resample(&source[i * input_block_size], input_block_size, + &resampled_destination[i * output_block_size], + output_block_size)); + } + } + + // Generate pure signal. + SinusoidalLinearChirpSource pure_source( + output_rate_, output_samples, input_nyquist_freq, output_delay_samples); + pure_source.Run(output_samples, pure_destination.get()); + + // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which + // we refer to as low and high. + static const double kLowFrequencyNyquistRange = 0.7; + static const double kHighFrequencyNyquistRange = 0.9; + + // Calculate Root-Mean-Square-Error and maximum error for the resampling. + double sum_of_squares = 0; + double low_freq_max_error = 0; + double high_freq_max_error = 0; + int minimum_rate = std::min(input_rate_, output_rate_); + double low_frequency_range = kLowFrequencyNyquistRange * 0.5 * minimum_rate; + double high_frequency_range = kHighFrequencyNyquistRange * 0.5 * minimum_rate; + + for (size_t i = 0; i < output_samples; ++i) { + double error = fabs(resampled_destination[i] - pure_destination[i]); + + if (pure_source.Frequency(i) < low_frequency_range) { + if (error > low_freq_max_error) + low_freq_max_error = error; + } else if (pure_source.Frequency(i) < high_frequency_range) { + if (error > high_freq_max_error) + high_freq_max_error = error; + } + // TODO(dalecurtis): Sanity check frequencies > kHighFrequencyNyquistRange. + + sum_of_squares += error * error; + } + + double rms_error = sqrt(sum_of_squares / output_samples); + + rms_error = DBFS(rms_error); + // In order to keep the thresholds in this test identical to SincResamplerTest + // we must account for the quantization error introduced by truncating from + // float to int. This happens twice (once at input and once at output) and we + // allow for the maximum possible error (1 / 32767) for each step. + // + // The quantization error is insignificant in the RMS calculation so does not + // need to be accounted for there. + low_freq_max_error = DBFS(low_freq_max_error - 2.0 / 32767); + high_freq_max_error = DBFS(high_freq_max_error - 2.0 / 32767); + + EXPECT_LE(rms_error, rms_error_); + EXPECT_LE(low_freq_max_error, low_freq_error_); + + // All conversions currently have a high frequency error around -6 dbFS. + static const double kHighFrequencyMaxError = -6.01; + EXPECT_LE(high_freq_max_error, kHighFrequencyMaxError); +} + +TEST_P(PushSincResamplerTest, ResampleInt) { + ResampleTest(true); +} + +TEST_P(PushSincResamplerTest, ResampleFloat) { + ResampleTest(false); +} + +// Thresholds chosen arbitrarily based on what each resampling reported during +// testing. All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS. +INSTANTIATE_TEST_SUITE_P( + PushSincResamplerTest, + PushSincResamplerTest, + ::testing::Values( + // First run through the rates tested in SincResamplerTest. The + // thresholds are identical. + // + // We don't directly test rates which fail to provide an integer number + // of samples in a 10 ms block (22050 and 11025 Hz), they are replaced + // by nearby rates in order to simplify testing. + // + // The PushSincResampler is in practice sample rate agnostic and derives + // resampling ratios from the block size, which for WebRTC purposes are + // blocks of floor(sample_rate/100) samples. So the 22050 Hz case is + // treated identically to the 22000 Hz case. Direct tests of 22050 Hz + // have to account for the simulated clock drift induced by the + // resampler inferring an incorrect sample rate ratio, without testing + // anything new within the resampler itself. + + // To 22kHz + std::make_tuple(8000, 22000, kResamplingRMSError, -62.73), + std::make_tuple(11000, 22000, kResamplingRMSError, -74.17), + std::make_tuple(16000, 22000, kResamplingRMSError, -62.54), + std::make_tuple(22000, 22000, kResamplingRMSError, -73.53), + std::make_tuple(32000, 22000, kResamplingRMSError, -46.45), + std::make_tuple(44100, 22000, kResamplingRMSError, -28.34), + std::make_tuple(48000, 22000, -15.01, -25.56), + std::make_tuple(96000, 22000, -18.49, -13.30), + std::make_tuple(192000, 22000, -20.50, -9.20), + + // To 44.1kHz + ::testing::make_tuple(8000, 44100, kResamplingRMSError, -62.73), + ::testing::make_tuple(11000, 44100, kResamplingRMSError, -63.57), + ::testing::make_tuple(16000, 44100, kResamplingRMSError, -62.54), + ::testing::make_tuple(22000, 44100, kResamplingRMSError, -62.73), + ::testing::make_tuple(32000, 44100, kResamplingRMSError, -63.32), + ::testing::make_tuple(44100, 44100, kResamplingRMSError, -73.53), + ::testing::make_tuple(48000, 44100, -15.01, -64.04), + ::testing::make_tuple(96000, 44100, -18.49, -25.51), + ::testing::make_tuple(192000, 44100, -20.50, -13.31), + + // To 48kHz + ::testing::make_tuple(8000, 48000, kResamplingRMSError, -63.43), + ::testing::make_tuple(11000, 48000, kResamplingRMSError, -63.96), + ::testing::make_tuple(16000, 48000, kResamplingRMSError, -63.96), + ::testing::make_tuple(22000, 48000, kResamplingRMSError, -63.80), + ::testing::make_tuple(32000, 48000, kResamplingRMSError, -64.04), + ::testing::make_tuple(44100, 48000, kResamplingRMSError, -62.63), + ::testing::make_tuple(48000, 48000, kResamplingRMSError, -73.52), + ::testing::make_tuple(96000, 48000, -18.40, -28.44), + ::testing::make_tuple(192000, 48000, -20.43, -14.11), + + // To 96kHz + ::testing::make_tuple(8000, 96000, kResamplingRMSError, -63.19), + ::testing::make_tuple(11000, 96000, kResamplingRMSError, -63.89), + ::testing::make_tuple(16000, 96000, kResamplingRMSError, -63.39), + ::testing::make_tuple(22000, 96000, kResamplingRMSError, -63.39), + ::testing::make_tuple(32000, 96000, kResamplingRMSError, -63.95), + ::testing::make_tuple(44100, 96000, kResamplingRMSError, -62.63), + ::testing::make_tuple(48000, 96000, kResamplingRMSError, -73.52), + ::testing::make_tuple(96000, 96000, kResamplingRMSError, -73.52), + ::testing::make_tuple(192000, 96000, kResamplingRMSError, -28.41), + + // To 192kHz + ::testing::make_tuple(8000, 192000, kResamplingRMSError, -63.10), + ::testing::make_tuple(11000, 192000, kResamplingRMSError, -63.17), + ::testing::make_tuple(16000, 192000, kResamplingRMSError, -63.14), + ::testing::make_tuple(22000, 192000, kResamplingRMSError, -63.14), + ::testing::make_tuple(32000, 192000, kResamplingRMSError, -63.38), + ::testing::make_tuple(44100, 192000, kResamplingRMSError, -62.63), + ::testing::make_tuple(48000, 192000, kResamplingRMSError, -73.44), + ::testing::make_tuple(96000, 192000, kResamplingRMSError, -73.52), + ::testing::make_tuple(192000, 192000, kResamplingRMSError, -73.52), + + // Next run through some additional cases interesting for WebRTC. + // We skip some extreme downsampled cases (192 -> {8, 16}, 96 -> 8) + // because they violate `kHighFrequencyMaxError`, which is not + // unexpected. It's very unlikely that we'll see these conversions in + // practice anyway. + + // To 8 kHz + ::testing::make_tuple(8000, 8000, kResamplingRMSError, -75.50), + ::testing::make_tuple(16000, 8000, -18.56, -28.79), + ::testing::make_tuple(32000, 8000, -20.36, -14.13), + ::testing::make_tuple(44100, 8000, -21.00, -11.39), + ::testing::make_tuple(48000, 8000, -20.96, -11.04), + + // To 16 kHz + ::testing::make_tuple(8000, 16000, kResamplingRMSError, -70.30), + ::testing::make_tuple(11000, 16000, kResamplingRMSError, -72.31), + ::testing::make_tuple(16000, 16000, kResamplingRMSError, -75.51), + ::testing::make_tuple(22000, 16000, kResamplingRMSError, -52.08), + ::testing::make_tuple(32000, 16000, -18.48, -28.59), + ::testing::make_tuple(44100, 16000, -19.30, -19.67), + ::testing::make_tuple(48000, 16000, -19.81, -18.11), + ::testing::make_tuple(96000, 16000, -20.95, -10.9596), + + // To 32 kHz + ::testing::make_tuple(8000, 32000, kResamplingRMSError, -70.30), + ::testing::make_tuple(11000, 32000, kResamplingRMSError, -71.34), + ::testing::make_tuple(16000, 32000, kResamplingRMSError, -75.51), + ::testing::make_tuple(22000, 32000, kResamplingRMSError, -72.05), + ::testing::make_tuple(32000, 32000, kResamplingRMSError, -75.51), + ::testing::make_tuple(44100, 32000, -16.44, -51.0349), + ::testing::make_tuple(48000, 32000, -16.90, -43.9967), + ::testing::make_tuple(96000, 32000, -19.61, -18.04), + ::testing::make_tuple(192000, 32000, -21.02, -10.94))); + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/resampler.cc b/third_party/libwebrtc/common_audio/resampler/resampler.cc new file mode 100644 index 0000000000..0fdb249052 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/resampler.cc @@ -0,0 +1,923 @@ +/* + * 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. + */ + +/* + * A wrapper for resampling a numerous amount of sampling combinations. + */ + +#include "common_audio/resampler/include/resampler.h" + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "rtc_base/logging.h" + +namespace webrtc { + +Resampler::Resampler() + : state1_(nullptr), + state2_(nullptr), + state3_(nullptr), + in_buffer_(nullptr), + out_buffer_(nullptr), + in_buffer_size_(0), + out_buffer_size_(0), + in_buffer_size_max_(0), + out_buffer_size_max_(0), + my_in_frequency_khz_(0), + my_out_frequency_khz_(0), + my_mode_(kResamplerMode1To1), + num_channels_(0), + helper_left_(nullptr), + helper_right_(nullptr) {} + +Resampler::Resampler(int inFreq, int outFreq, size_t num_channels) + : Resampler() { + Reset(inFreq, outFreq, num_channels); +} + +Resampler::~Resampler() { + if (state1_) { + free(state1_); + } + if (state2_) { + free(state2_); + } + if (state3_) { + free(state3_); + } + if (in_buffer_) { + free(in_buffer_); + } + if (out_buffer_) { + free(out_buffer_); + } + if (helper_left_) { + delete helper_left_; + } + if (helper_right_) { + delete helper_right_; + } +} + +int Resampler::ResetIfNeeded(int inFreq, int outFreq, size_t num_channels) { + int tmpInFreq_kHz = inFreq / 1000; + int tmpOutFreq_kHz = outFreq / 1000; + + if ((tmpInFreq_kHz != my_in_frequency_khz_) || + (tmpOutFreq_kHz != my_out_frequency_khz_) || + (num_channels != num_channels_)) { + return Reset(inFreq, outFreq, num_channels); + } else { + return 0; + } +} + +int Resampler::Reset(int inFreq, int outFreq, size_t num_channels) { + if (num_channels != 1 && num_channels != 2) { + RTC_LOG(LS_WARNING) + << "Reset() called with unsupported channel count, num_channels = " + << num_channels; + return -1; + } + ResamplerMode mode; + if (ComputeResamplerMode(inFreq, outFreq, &mode) != 0) { + RTC_LOG(LS_WARNING) + << "Reset() called with unsupported sample rates, inFreq = " << inFreq + << ", outFreq = " << outFreq; + return -1; + } + // Reinitialize internal state for the frequencies and sample rates. + num_channels_ = num_channels; + my_mode_ = mode; + + if (state1_) { + free(state1_); + state1_ = nullptr; + } + if (state2_) { + free(state2_); + state2_ = nullptr; + } + if (state3_) { + free(state3_); + state3_ = nullptr; + } + if (in_buffer_) { + free(in_buffer_); + in_buffer_ = nullptr; + } + if (out_buffer_) { + free(out_buffer_); + out_buffer_ = nullptr; + } + if (helper_left_) { + delete helper_left_; + helper_left_ = nullptr; + } + if (helper_right_) { + delete helper_right_; + helper_right_ = nullptr; + } + + in_buffer_size_ = 0; + out_buffer_size_ = 0; + in_buffer_size_max_ = 0; + out_buffer_size_max_ = 0; + + // We need to track what domain we're in. + my_in_frequency_khz_ = inFreq / 1000; + my_out_frequency_khz_ = outFreq / 1000; + + if (num_channels_ == 2) { + // Create two mono resamplers. + helper_left_ = new Resampler(inFreq, outFreq, 1); + helper_right_ = new Resampler(inFreq, outFreq, 1); + } + + // Now create the states we need. + switch (my_mode_) { + case kResamplerMode1To1: + // No state needed; + break; + case kResamplerMode1To2: + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + break; + case kResamplerMode1To3: + state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz( + static_cast<WebRtcSpl_State16khzTo48khz*>(state1_)); + break; + case kResamplerMode1To4: + // 1:2 + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + // 2:4 + state2_ = malloc(8 * sizeof(int32_t)); + memset(state2_, 0, 8 * sizeof(int32_t)); + break; + case kResamplerMode1To6: + // 1:2 + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + // 2:6 + state2_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz( + static_cast<WebRtcSpl_State16khzTo48khz*>(state2_)); + break; + case kResamplerMode1To12: + // 1:2 + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + // 2:4 + state2_ = malloc(8 * sizeof(int32_t)); + memset(state2_, 0, 8 * sizeof(int32_t)); + // 4:12 + state3_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz( + static_cast<WebRtcSpl_State16khzTo48khz*>(state3_)); + break; + case kResamplerMode2To3: + // 2:6 + state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz)); + WebRtcSpl_ResetResample16khzTo48khz( + static_cast<WebRtcSpl_State16khzTo48khz*>(state1_)); + // 6:3 + state2_ = malloc(8 * sizeof(int32_t)); + memset(state2_, 0, 8 * sizeof(int32_t)); + break; + case kResamplerMode2To11: + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + + state2_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); + WebRtcSpl_ResetResample8khzTo22khz( + static_cast<WebRtcSpl_State8khzTo22khz*>(state2_)); + break; + case kResamplerMode4To11: + state1_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz)); + WebRtcSpl_ResetResample8khzTo22khz( + static_cast<WebRtcSpl_State8khzTo22khz*>(state1_)); + break; + case kResamplerMode8To11: + state1_ = malloc(sizeof(WebRtcSpl_State16khzTo22khz)); + WebRtcSpl_ResetResample16khzTo22khz( + static_cast<WebRtcSpl_State16khzTo22khz*>(state1_)); + break; + case kResamplerMode11To16: + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + + state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); + WebRtcSpl_ResetResample22khzTo16khz( + static_cast<WebRtcSpl_State22khzTo16khz*>(state2_)); + break; + case kResamplerMode11To32: + // 11 -> 22 + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + + // 22 -> 16 + state2_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); + WebRtcSpl_ResetResample22khzTo16khz( + static_cast<WebRtcSpl_State22khzTo16khz*>(state2_)); + + // 16 -> 32 + state3_ = malloc(8 * sizeof(int32_t)); + memset(state3_, 0, 8 * sizeof(int32_t)); + + break; + case kResamplerMode2To1: + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + break; + case kResamplerMode3To1: + state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz( + static_cast<WebRtcSpl_State48khzTo16khz*>(state1_)); + break; + case kResamplerMode4To1: + // 4:2 + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + // 2:1 + state2_ = malloc(8 * sizeof(int32_t)); + memset(state2_, 0, 8 * sizeof(int32_t)); + break; + case kResamplerMode6To1: + // 6:2 + state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz( + static_cast<WebRtcSpl_State48khzTo16khz*>(state1_)); + // 2:1 + state2_ = malloc(8 * sizeof(int32_t)); + memset(state2_, 0, 8 * sizeof(int32_t)); + break; + case kResamplerMode12To1: + // 12:4 + state1_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz( + static_cast<WebRtcSpl_State48khzTo16khz*>(state1_)); + // 4:2 + state2_ = malloc(8 * sizeof(int32_t)); + memset(state2_, 0, 8 * sizeof(int32_t)); + // 2:1 + state3_ = malloc(8 * sizeof(int32_t)); + memset(state3_, 0, 8 * sizeof(int32_t)); + break; + case kResamplerMode3To2: + // 3:6 + state1_ = malloc(8 * sizeof(int32_t)); + memset(state1_, 0, 8 * sizeof(int32_t)); + // 6:2 + state2_ = malloc(sizeof(WebRtcSpl_State48khzTo16khz)); + WebRtcSpl_ResetResample48khzTo16khz( + static_cast<WebRtcSpl_State48khzTo16khz*>(state2_)); + break; + case kResamplerMode11To2: + state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); + WebRtcSpl_ResetResample22khzTo8khz( + static_cast<WebRtcSpl_State22khzTo8khz*>(state1_)); + + state2_ = malloc(8 * sizeof(int32_t)); + memset(state2_, 0, 8 * sizeof(int32_t)); + + break; + case kResamplerMode11To4: + state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz)); + WebRtcSpl_ResetResample22khzTo8khz( + static_cast<WebRtcSpl_State22khzTo8khz*>(state1_)); + break; + case kResamplerMode11To8: + state1_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz)); + WebRtcSpl_ResetResample22khzTo16khz( + static_cast<WebRtcSpl_State22khzTo16khz*>(state1_)); + break; + } + + return 0; +} + +int Resampler::ComputeResamplerMode(int in_freq_hz, + int out_freq_hz, + ResamplerMode* mode) { + // Start with a math exercise, Euclid's algorithm to find the gcd: + int a = in_freq_hz; + int b = out_freq_hz; + int c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + // b is now the gcd; + + // Scale with GCD + const int reduced_in_freq = in_freq_hz / b; + const int reduced_out_freq = out_freq_hz / b; + + if (reduced_in_freq == reduced_out_freq) { + *mode = kResamplerMode1To1; + } else if (reduced_in_freq == 1) { + switch (reduced_out_freq) { + case 2: + *mode = kResamplerMode1To2; + break; + case 3: + *mode = kResamplerMode1To3; + break; + case 4: + *mode = kResamplerMode1To4; + break; + case 6: + *mode = kResamplerMode1To6; + break; + case 12: + *mode = kResamplerMode1To12; + break; + default: + return -1; + } + } else if (reduced_out_freq == 1) { + switch (reduced_in_freq) { + case 2: + *mode = kResamplerMode2To1; + break; + case 3: + *mode = kResamplerMode3To1; + break; + case 4: + *mode = kResamplerMode4To1; + break; + case 6: + *mode = kResamplerMode6To1; + break; + case 12: + *mode = kResamplerMode12To1; + break; + default: + return -1; + } + } else if ((reduced_in_freq == 2) && (reduced_out_freq == 3)) { + *mode = kResamplerMode2To3; + } else if ((reduced_in_freq == 2) && (reduced_out_freq == 11)) { + *mode = kResamplerMode2To11; + } else if ((reduced_in_freq == 4) && (reduced_out_freq == 11)) { + *mode = kResamplerMode4To11; + } else if ((reduced_in_freq == 8) && (reduced_out_freq == 11)) { + *mode = kResamplerMode8To11; + } else if ((reduced_in_freq == 3) && (reduced_out_freq == 2)) { + *mode = kResamplerMode3To2; + } else if ((reduced_in_freq == 11) && (reduced_out_freq == 2)) { + *mode = kResamplerMode11To2; + } else if ((reduced_in_freq == 11) && (reduced_out_freq == 4)) { + *mode = kResamplerMode11To4; + } else if ((reduced_in_freq == 11) && (reduced_out_freq == 16)) { + *mode = kResamplerMode11To16; + } else if ((reduced_in_freq == 11) && (reduced_out_freq == 32)) { + *mode = kResamplerMode11To32; + } else if ((reduced_in_freq == 11) && (reduced_out_freq == 8)) { + *mode = kResamplerMode11To8; + } else { + return -1; + } + return 0; +} + +// Synchronous resampling, all output samples are written to samplesOut +int Resampler::Push(const int16_t* samplesIn, + size_t lengthIn, + int16_t* samplesOut, + size_t maxLen, + size_t& outLen) { + if (num_channels_ == 2) { + // Split up the signal and call the helper object for each channel + int16_t* left = + static_cast<int16_t*>(malloc(lengthIn * sizeof(int16_t) / 2)); + int16_t* right = + static_cast<int16_t*>(malloc(lengthIn * sizeof(int16_t) / 2)); + int16_t* out_left = + static_cast<int16_t*>(malloc(maxLen / 2 * sizeof(int16_t))); + int16_t* out_right = + static_cast<int16_t*>(malloc(maxLen / 2 * sizeof(int16_t))); + int res = 0; + for (size_t i = 0; i < lengthIn; i += 2) { + left[i >> 1] = samplesIn[i]; + right[i >> 1] = samplesIn[i + 1]; + } + + // It's OK to overwrite the local parameter, since it's just a copy + lengthIn = lengthIn / 2; + + size_t actualOutLen_left = 0; + size_t actualOutLen_right = 0; + // Do resampling for right channel + res |= helper_left_->Push(left, lengthIn, out_left, maxLen / 2, + actualOutLen_left); + res |= helper_right_->Push(right, lengthIn, out_right, maxLen / 2, + actualOutLen_right); + if (res || (actualOutLen_left != actualOutLen_right)) { + free(left); + free(right); + free(out_left); + free(out_right); + return -1; + } + + // Reassemble the signal + for (size_t i = 0; i < actualOutLen_left; i++) { + samplesOut[i * 2] = out_left[i]; + samplesOut[i * 2 + 1] = out_right[i]; + } + outLen = 2 * actualOutLen_left; + + free(left); + free(right); + free(out_left); + free(out_right); + + return 0; + } + + // Containers for temp samples + int16_t* tmp; + int16_t* tmp_2; + // tmp data for resampling routines + int32_t* tmp_mem; + + switch (my_mode_) { + case kResamplerMode1To1: + memcpy(samplesOut, samplesIn, lengthIn * sizeof(int16_t)); + outLen = lengthIn; + break; + case kResamplerMode1To2: + if (maxLen < (lengthIn * 2)) { + return -1; + } + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, + static_cast<int32_t*>(state1_)); + outLen = lengthIn * 2; + return 0; + case kResamplerMode1To3: + + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 160) != 0) { + return -1; + } + if (maxLen < (lengthIn * 3)) { + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t))); + + for (size_t i = 0; i < lengthIn; i += 160) { + WebRtcSpl_Resample16khzTo48khz( + samplesIn + i, samplesOut + i * 3, + static_cast<WebRtcSpl_State16khzTo48khz*>(state1_), tmp_mem); + } + outLen = lengthIn * 3; + free(tmp_mem); + return 0; + case kResamplerMode1To4: + if (maxLen < (lengthIn * 4)) { + return -1; + } + + tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 2 * lengthIn)); + // 1:2 + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, + static_cast<int32_t*>(state1_)); + // 2:4 + WebRtcSpl_UpsampleBy2(tmp, lengthIn * 2, samplesOut, + static_cast<int32_t*>(state2_)); + outLen = lengthIn * 4; + free(tmp); + return 0; + case kResamplerMode1To6: + // We can only handle blocks of 80 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 80) != 0) { + return -1; + } + if (maxLen < (lengthIn * 6)) { + return -1; + } + + // 1:2 + + tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t))); + tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 2 * lengthIn)); + + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, + static_cast<int32_t*>(state1_)); + outLen = lengthIn * 2; + + for (size_t i = 0; i < outLen; i += 160) { + WebRtcSpl_Resample16khzTo48khz( + tmp + i, samplesOut + i * 3, + static_cast<WebRtcSpl_State16khzTo48khz*>(state2_), tmp_mem); + } + outLen = outLen * 3; + free(tmp_mem); + free(tmp); + + return 0; + case kResamplerMode1To12: + // We can only handle blocks of 40 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 40) != 0) { + return -1; + } + if (maxLen < (lengthIn * 12)) { + return -1; + } + + tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t))); + tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 4 * lengthIn)); + // 1:2 + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, + static_cast<int32_t*>(state1_)); + outLen = lengthIn * 2; + // 2:4 + WebRtcSpl_UpsampleBy2(samplesOut, outLen, tmp, + static_cast<int32_t*>(state2_)); + outLen = outLen * 2; + // 4:12 + for (size_t i = 0; i < outLen; i += 160) { + // WebRtcSpl_Resample16khzTo48khz() takes a block of 160 samples + // as input and outputs a resampled block of 480 samples. The + // data is now actually in 32 kHz sampling rate, despite the + // function name, and with a resampling factor of three becomes + // 96 kHz. + WebRtcSpl_Resample16khzTo48khz( + tmp + i, samplesOut + i * 3, + static_cast<WebRtcSpl_State16khzTo48khz*>(state3_), tmp_mem); + } + outLen = outLen * 3; + free(tmp_mem); + free(tmp); + + return 0; + case kResamplerMode2To3: + if (maxLen < (lengthIn * 3 / 2)) { + return -1; + } + // 2:6 + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 160) != 0) { + return -1; + } + tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 3)); + tmp_mem = static_cast<int32_t*>(malloc(336 * sizeof(int32_t))); + for (size_t i = 0; i < lengthIn; i += 160) { + WebRtcSpl_Resample16khzTo48khz( + samplesIn + i, tmp + i * 3, + static_cast<WebRtcSpl_State16khzTo48khz*>(state1_), tmp_mem); + } + lengthIn = lengthIn * 3; + // 6:3 + WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, + static_cast<int32_t*>(state2_)); + outLen = lengthIn / 2; + free(tmp); + free(tmp_mem); + return 0; + case kResamplerMode2To11: + + // We can only handle blocks of 80 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 80) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 11) / 2)) { + return -1; + } + tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * 2 * lengthIn)); + // 1:2 + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, + static_cast<int32_t*>(state1_)); + lengthIn *= 2; + + tmp_mem = static_cast<int32_t*>(malloc(98 * sizeof(int32_t))); + + for (size_t i = 0; i < lengthIn; i += 80) { + WebRtcSpl_Resample8khzTo22khz( + tmp + i, samplesOut + (i * 11) / 4, + static_cast<WebRtcSpl_State8khzTo22khz*>(state2_), tmp_mem); + } + outLen = (lengthIn * 11) / 4; + free(tmp_mem); + free(tmp); + return 0; + case kResamplerMode4To11: + + // We can only handle blocks of 80 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 80) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 11) / 4)) { + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(98 * sizeof(int32_t))); + + for (size_t i = 0; i < lengthIn; i += 80) { + WebRtcSpl_Resample8khzTo22khz( + samplesIn + i, samplesOut + (i * 11) / 4, + static_cast<WebRtcSpl_State8khzTo22khz*>(state1_), tmp_mem); + } + outLen = (lengthIn * 11) / 4; + free(tmp_mem); + return 0; + case kResamplerMode8To11: + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 160) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 11) / 8)) { + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(88 * sizeof(int32_t))); + + for (size_t i = 0; i < lengthIn; i += 160) { + WebRtcSpl_Resample16khzTo22khz( + samplesIn + i, samplesOut + (i * 11) / 8, + static_cast<WebRtcSpl_State16khzTo22khz*>(state1_), tmp_mem); + } + outLen = (lengthIn * 11) / 8; + free(tmp_mem); + return 0; + + case kResamplerMode11To16: + // We can only handle blocks of 110 samples + if ((lengthIn % 110) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 16) / 11)) { + return -1; + } + + tmp_mem = static_cast<int32_t*>(malloc(104 * sizeof(int32_t))); + tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn * 2))); + + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, + static_cast<int32_t*>(state1_)); + + for (size_t i = 0; i < (lengthIn * 2); i += 220) { + WebRtcSpl_Resample22khzTo16khz( + tmp + i, samplesOut + (i / 220) * 160, + static_cast<WebRtcSpl_State22khzTo16khz*>(state2_), tmp_mem); + } + + outLen = (lengthIn * 16) / 11; + + free(tmp_mem); + free(tmp); + return 0; + + case kResamplerMode11To32: + + // We can only handle blocks of 110 samples + if ((lengthIn % 110) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 32) / 11)) { + return -1; + } + + tmp_mem = static_cast<int32_t*>(malloc(104 * sizeof(int32_t))); + tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn * 2))); + + // 11 -> 22 kHz in samplesOut + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, + static_cast<int32_t*>(state1_)); + + // 22 -> 16 in tmp + for (size_t i = 0; i < (lengthIn * 2); i += 220) { + WebRtcSpl_Resample22khzTo16khz( + samplesOut + i, tmp + (i / 220) * 160, + static_cast<WebRtcSpl_State22khzTo16khz*>(state2_), tmp_mem); + } + + // 16 -> 32 in samplesOut + WebRtcSpl_UpsampleBy2(tmp, (lengthIn * 16) / 11, samplesOut, + static_cast<int32_t*>(state3_)); + + outLen = (lengthIn * 32) / 11; + + free(tmp_mem); + free(tmp); + return 0; + + case kResamplerMode2To1: + if (maxLen < (lengthIn / 2)) { + return -1; + } + WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, samplesOut, + static_cast<int32_t*>(state1_)); + outLen = lengthIn / 2; + return 0; + case kResamplerMode3To1: + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) { + return -1; + } + if (maxLen < (lengthIn / 3)) { + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t))); + + for (size_t i = 0; i < lengthIn; i += 480) { + WebRtcSpl_Resample48khzTo16khz( + samplesIn + i, samplesOut + i / 3, + static_cast<WebRtcSpl_State48khzTo16khz*>(state1_), tmp_mem); + } + outLen = lengthIn / 3; + free(tmp_mem); + return 0; + case kResamplerMode4To1: + if (maxLen < (lengthIn / 4)) { + return -1; + } + tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn / 2)); + // 4:2 + WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, tmp, + static_cast<int32_t*>(state1_)); + // 2:1 + WebRtcSpl_DownsampleBy2(tmp, lengthIn / 2, samplesOut, + static_cast<int32_t*>(state2_)); + outLen = lengthIn / 4; + free(tmp); + return 0; + + case kResamplerMode6To1: + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) { + return -1; + } + if (maxLen < (lengthIn / 6)) { + return -1; + } + + tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t))); + tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn) / 3)); + + for (size_t i = 0; i < lengthIn; i += 480) { + WebRtcSpl_Resample48khzTo16khz( + samplesIn + i, tmp + i / 3, + static_cast<WebRtcSpl_State48khzTo16khz*>(state1_), tmp_mem); + } + outLen = lengthIn / 3; + free(tmp_mem); + WebRtcSpl_DownsampleBy2(tmp, outLen, samplesOut, + static_cast<int32_t*>(state2_)); + free(tmp); + outLen = outLen / 2; + return 0; + case kResamplerMode12To1: + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) { + return -1; + } + if (maxLen < (lengthIn / 12)) { + return -1; + } + + tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t))); + tmp = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn) / 3)); + tmp_2 = static_cast<int16_t*>(malloc((sizeof(int16_t) * lengthIn) / 6)); + // 12:4 + for (size_t i = 0; i < lengthIn; i += 480) { + // WebRtcSpl_Resample48khzTo16khz() takes a block of 480 samples + // as input and outputs a resampled block of 160 samples. The + // data is now actually in 96 kHz sampling rate, despite the + // function name, and with a resampling factor of 1/3 becomes + // 32 kHz. + WebRtcSpl_Resample48khzTo16khz( + samplesIn + i, tmp + i / 3, + static_cast<WebRtcSpl_State48khzTo16khz*>(state1_), tmp_mem); + } + outLen = lengthIn / 3; + free(tmp_mem); + // 4:2 + WebRtcSpl_DownsampleBy2(tmp, outLen, tmp_2, + static_cast<int32_t*>(state2_)); + outLen = outLen / 2; + free(tmp); + // 2:1 + WebRtcSpl_DownsampleBy2(tmp_2, outLen, samplesOut, + static_cast<int32_t*>(state3_)); + free(tmp_2); + outLen = outLen / 2; + return 0; + case kResamplerMode3To2: + if (maxLen < (lengthIn * 2 / 3)) { + return -1; + } + // 3:6 + tmp = static_cast<int16_t*>(malloc(sizeof(int16_t) * lengthIn * 2)); + WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, + static_cast<int32_t*>(state1_)); + lengthIn *= 2; + // 6:2 + // We can only handle blocks of 480 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 480) != 0) { + free(tmp); + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(496 * sizeof(int32_t))); + for (size_t i = 0; i < lengthIn; i += 480) { + WebRtcSpl_Resample48khzTo16khz( + tmp + i, samplesOut + i / 3, + static_cast<WebRtcSpl_State48khzTo16khz*>(state2_), tmp_mem); + } + outLen = lengthIn / 3; + free(tmp); + free(tmp_mem); + return 0; + case kResamplerMode11To2: + // We can only handle blocks of 220 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 220) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 2) / 11)) { + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(126 * sizeof(int32_t))); + tmp = + static_cast<int16_t*>(malloc((lengthIn * 4) / 11 * sizeof(int16_t))); + + for (size_t i = 0; i < lengthIn; i += 220) { + WebRtcSpl_Resample22khzTo8khz( + samplesIn + i, tmp + (i * 4) / 11, + static_cast<WebRtcSpl_State22khzTo8khz*>(state1_), tmp_mem); + } + lengthIn = (lengthIn * 4) / 11; + + WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, + static_cast<int32_t*>(state2_)); + outLen = lengthIn / 2; + + free(tmp_mem); + free(tmp); + return 0; + case kResamplerMode11To4: + // We can only handle blocks of 220 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 220) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 4) / 11)) { + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(126 * sizeof(int32_t))); + + for (size_t i = 0; i < lengthIn; i += 220) { + WebRtcSpl_Resample22khzTo8khz( + samplesIn + i, samplesOut + (i * 4) / 11, + static_cast<WebRtcSpl_State22khzTo8khz*>(state1_), tmp_mem); + } + outLen = (lengthIn * 4) / 11; + free(tmp_mem); + return 0; + case kResamplerMode11To8: + // We can only handle blocks of 160 samples + // Can be fixed, but I don't think it's needed + if ((lengthIn % 220) != 0) { + return -1; + } + if (maxLen < ((lengthIn * 8) / 11)) { + return -1; + } + tmp_mem = static_cast<int32_t*>(malloc(104 * sizeof(int32_t))); + + for (size_t i = 0; i < lengthIn; i += 220) { + WebRtcSpl_Resample22khzTo16khz( + samplesIn + i, samplesOut + (i * 8) / 11, + static_cast<WebRtcSpl_State22khzTo16khz*>(state1_), tmp_mem); + } + outLen = (lengthIn * 8) / 11; + free(tmp_mem); + return 0; + } + return 0; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/resampler_unittest.cc b/third_party/libwebrtc/common_audio/resampler/resampler_unittest.cc new file mode 100644 index 0000000000..1b90d3e30b --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/resampler_unittest.cc @@ -0,0 +1,168 @@ +/* + * 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. + */ + +#include "common_audio/resampler/include/resampler.h" + +#include <array> + +#include "rtc_base/strings/string_builder.h" +#include "test/gtest.h" + +// TODO(andrew): this is a work-in-progress. Many more tests are needed. + +namespace webrtc { +namespace { + +const int kNumChannels[] = {1, 2}; +const size_t kNumChannelsSize = sizeof(kNumChannels) / sizeof(*kNumChannels); + +// Rates we must support. +const int kMaxRate = 96000; +const int kRates[] = {8000, 16000, 32000, 44000, 48000, kMaxRate}; +const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates); +const int kMaxChannels = 2; +const size_t kDataSize = static_cast<size_t>(kMaxChannels * kMaxRate / 100); + +// TODO(andrew): should we be supporting these combinations? +bool ValidRates(int in_rate, int out_rate) { + // Not the most compact notation, for clarity. + if ((in_rate == 44000 && (out_rate == 48000 || out_rate == 96000)) || + (out_rate == 44000 && (in_rate == 48000 || in_rate == 96000))) { + return false; + } + + return true; +} + +class ResamplerTest : public ::testing::Test { + protected: + ResamplerTest(); + void SetUp() override; + void TearDown() override; + + void ResetIfNeededAndPush(int in_rate, int out_rate, int num_channels); + + Resampler rs_; + int16_t data_in_[kDataSize]; + int16_t data_out_[kDataSize]; +}; + +ResamplerTest::ResamplerTest() {} + +void ResamplerTest::SetUp() { + // Initialize input data with anything. The tests are content independent. + memset(data_in_, 1, sizeof(data_in_)); +} + +void ResamplerTest::TearDown() {} + +void ResamplerTest::ResetIfNeededAndPush(int in_rate, + int out_rate, + int num_channels) { + rtc::StringBuilder ss; + ss << "Input rate: " << in_rate << ", output rate: " << out_rate + << ", channel count: " << num_channels; + SCOPED_TRACE(ss.str()); + + if (ValidRates(in_rate, out_rate)) { + size_t in_length = static_cast<size_t>(in_rate / 100); + size_t out_length = 0; + EXPECT_EQ(0, rs_.ResetIfNeeded(in_rate, out_rate, num_channels)); + EXPECT_EQ(0, + rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); + EXPECT_EQ(static_cast<size_t>(out_rate / 100), out_length); + } else { + EXPECT_EQ(-1, rs_.ResetIfNeeded(in_rate, out_rate, num_channels)); + } +} + +TEST_F(ResamplerTest, Reset) { + // The only failure mode for the constructor is if Reset() fails. For the + // time being then (until an Init function is added), we rely on Reset() + // to test the constructor. + + // Check that all required combinations are supported. + for (size_t i = 0; i < kRatesSize; ++i) { + for (size_t j = 0; j < kRatesSize; ++j) { + for (size_t k = 0; k < kNumChannelsSize; ++k) { + rtc::StringBuilder ss; + ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j] + << ", channels: " << kNumChannels[k]; + SCOPED_TRACE(ss.str()); + if (ValidRates(kRates[i], kRates[j])) + EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kNumChannels[k])); + else + EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kNumChannels[k])); + } + } + } +} + +// TODO(tlegrand): Replace code inside the two tests below with a function +// with number of channels and ResamplerType as input. +TEST_F(ResamplerTest, Mono) { + const int kChannels = 1; + for (size_t i = 0; i < kRatesSize; ++i) { + for (size_t j = 0; j < kRatesSize; ++j) { + rtc::StringBuilder ss; + ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j]; + SCOPED_TRACE(ss.str()); + + if (ValidRates(kRates[i], kRates[j])) { + size_t in_length = static_cast<size_t>(kRates[i] / 100); + size_t out_length = 0; + EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels)); + EXPECT_EQ( + 0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); + EXPECT_EQ(static_cast<size_t>(kRates[j] / 100), out_length); + } else { + EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels)); + } + } + } +} + +TEST_F(ResamplerTest, Stereo) { + const int kChannels = 2; + for (size_t i = 0; i < kRatesSize; ++i) { + for (size_t j = 0; j < kRatesSize; ++j) { + rtc::StringBuilder ss; + ss << "Input rate: " << kRates[i] << ", output rate: " << kRates[j]; + SCOPED_TRACE(ss.str()); + + if (ValidRates(kRates[i], kRates[j])) { + size_t in_length = static_cast<size_t>(kChannels * kRates[i] / 100); + size_t out_length = 0; + EXPECT_EQ(0, rs_.Reset(kRates[i], kRates[j], kChannels)); + EXPECT_EQ( + 0, rs_.Push(data_in_, in_length, data_out_, kDataSize, out_length)); + EXPECT_EQ(static_cast<size_t>(kChannels * kRates[j] / 100), out_length); + } else { + EXPECT_EQ(-1, rs_.Reset(kRates[i], kRates[j], kChannels)); + } + } + } +} + +// Try multiple resets between a few supported and unsupported rates. +TEST_F(ResamplerTest, MultipleResets) { + constexpr size_t kNumChanges = 5; + constexpr std::array<int, kNumChanges> kInRates = { + {8000, 44000, 44000, 32000, 32000}}; + constexpr std::array<int, kNumChanges> kOutRates = { + {16000, 48000, 48000, 16000, 16000}}; + constexpr std::array<int, kNumChanges> kNumChannels = {{2, 2, 2, 2, 1}}; + for (size_t i = 0; i < kNumChanges; ++i) { + ResetIfNeededAndPush(kInRates[i], kOutRates[i], kNumChannels[i]); + } +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/sinc_resampler.cc b/third_party/libwebrtc/common_audio/resampler/sinc_resampler.cc new file mode 100644 index 0000000000..fac11aa362 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinc_resampler.cc @@ -0,0 +1,366 @@ +/* + * 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. + */ + +// Modified from the Chromium original: +// src/media/base/sinc_resampler.cc + +// Initial input buffer layout, dividing into regions r0_ to r4_ (note: r0_, r3_ +// and r4_ will move after the first load): +// +// |----------------|-----------------------------------------|----------------| +// +// request_frames_ +// <---------------------------------------------------------> +// r0_ (during first load) +// +// kKernelSize / 2 kKernelSize / 2 kKernelSize / 2 kKernelSize / 2 +// <---------------> <---------------> <---------------> <---------------> +// r1_ r2_ r3_ r4_ +// +// block_size_ == r4_ - r2_ +// <---------------------------------------> +// +// request_frames_ +// <------------------ ... -----------------> +// r0_ (during second load) +// +// On the second request r0_ slides to the right by kKernelSize / 2 and r3_, r4_ +// and block_size_ are reinitialized via step (3) in the algorithm below. +// +// These new regions remain constant until a Flush() occurs. While complicated, +// this allows us to reduce jitter by always requesting the same amount from the +// provided callback. +// +// The algorithm: +// +// 1) Allocate input_buffer of size: request_frames_ + kKernelSize; this ensures +// there's enough room to read request_frames_ from the callback into region +// r0_ (which will move between the first and subsequent passes). +// +// 2) Let r1_, r2_ each represent half the kernel centered around r0_: +// +// r0_ = input_buffer_ + kKernelSize / 2 +// r1_ = input_buffer_ +// r2_ = r0_ +// +// r0_ is always request_frames_ in size. r1_, r2_ are kKernelSize / 2 in +// size. r1_ must be zero initialized to avoid convolution with garbage (see +// step (5) for why). +// +// 3) Let r3_, r4_ each represent half the kernel right aligned with the end of +// r0_ and choose block_size_ as the distance in frames between r4_ and r2_: +// +// r3_ = r0_ + request_frames_ - kKernelSize +// r4_ = r0_ + request_frames_ - kKernelSize / 2 +// block_size_ = r4_ - r2_ = request_frames_ - kKernelSize / 2 +// +// 4) Consume request_frames_ frames into r0_. +// +// 5) Position kernel centered at start of r2_ and generate output frames until +// the kernel is centered at the start of r4_ or we've finished generating +// all the output frames. +// +// 6) Wrap left over data from the r3_ to r1_ and r4_ to r2_. +// +// 7) If we're on the second load, in order to avoid overwriting the frames we +// just wrapped from r4_ we need to slide r0_ to the right by the size of +// r4_, which is kKernelSize / 2: +// +// r0_ = r0_ + kKernelSize / 2 = input_buffer_ + kKernelSize +// +// r3_, r4_, and block_size_ then need to be reinitialized, so goto (3). +// +// 8) Else, if we're not on the second load, goto (4). +// +// Note: we're glossing over how the sub-sample handling works with +// `virtual_source_idx_`, etc. + +// MSVC++ requires this to be set before any other includes to get M_PI. +#define _USE_MATH_DEFINES + +#include "common_audio/resampler/sinc_resampler.h" + +#include <math.h> +#include <stdint.h> +#include <string.h> + +#include <limits> + +#include "rtc_base/checks.h" +#include "rtc_base/system/arch.h" +#include "system_wrappers/include/cpu_features_wrapper.h" // kSSE2, WebRtc_G... + +namespace webrtc { + +namespace { + +double SincScaleFactor(double io_ratio) { + // `sinc_scale_factor` is basically the normalized cutoff frequency of the + // low-pass filter. + double sinc_scale_factor = io_ratio > 1.0 ? 1.0 / io_ratio : 1.0; + + // The sinc function is an idealized brick-wall filter, but since we're + // windowing it the transition from pass to stop does not happen right away. + // So we should adjust the low pass filter cutoff slightly downward to avoid + // some aliasing at the very high-end. + // TODO(crogers): this value is empirical and to be more exact should vary + // depending on kKernelSize. + sinc_scale_factor *= 0.9; + + return sinc_scale_factor; +} + +} // namespace + +const size_t SincResampler::kKernelSize; + +// If we know the minimum architecture at compile time, avoid CPU detection. +void SincResampler::InitializeCPUSpecificFeatures() { +#if defined(WEBRTC_HAS_NEON) + convolve_proc_ = Convolve_NEON; +#elif defined(WEBRTC_ARCH_X86_FAMILY) + // Using AVX2 instead of SSE2 when AVX2 supported. + if (GetCPUInfo(kAVX2)) + convolve_proc_ = Convolve_AVX2; + else if (GetCPUInfo(kSSE2)) + convolve_proc_ = Convolve_SSE; + else + convolve_proc_ = Convolve_C; +#else + // Unknown architecture. + convolve_proc_ = Convolve_C; +#endif +} + +SincResampler::SincResampler(double io_sample_rate_ratio, + size_t request_frames, + SincResamplerCallback* read_cb) + : io_sample_rate_ratio_(io_sample_rate_ratio), + read_cb_(read_cb), + request_frames_(request_frames), + input_buffer_size_(request_frames_ + kKernelSize), + // Create input buffers with a 32-byte alignment for SIMD optimizations. + kernel_storage_(static_cast<float*>( + AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))), + kernel_pre_sinc_storage_(static_cast<float*>( + AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))), + kernel_window_storage_(static_cast<float*>( + AlignedMalloc(sizeof(float) * kKernelStorageSize, 32))), + input_buffer_(static_cast<float*>( + AlignedMalloc(sizeof(float) * input_buffer_size_, 32))), + convolve_proc_(nullptr), + r1_(input_buffer_.get()), + r2_(input_buffer_.get() + kKernelSize / 2) { + InitializeCPUSpecificFeatures(); + RTC_DCHECK(convolve_proc_); + RTC_DCHECK_GT(request_frames_, 0); + Flush(); + RTC_DCHECK_GT(block_size_, kKernelSize); + + memset(kernel_storage_.get(), 0, + sizeof(*kernel_storage_.get()) * kKernelStorageSize); + memset(kernel_pre_sinc_storage_.get(), 0, + sizeof(*kernel_pre_sinc_storage_.get()) * kKernelStorageSize); + memset(kernel_window_storage_.get(), 0, + sizeof(*kernel_window_storage_.get()) * kKernelStorageSize); + + InitializeKernel(); +} + +SincResampler::~SincResampler() {} + +void SincResampler::UpdateRegions(bool second_load) { + // Setup various region pointers in the buffer (see diagram above). If we're + // on the second load we need to slide r0_ to the right by kKernelSize / 2. + r0_ = input_buffer_.get() + (second_load ? kKernelSize : kKernelSize / 2); + r3_ = r0_ + request_frames_ - kKernelSize; + r4_ = r0_ + request_frames_ - kKernelSize / 2; + block_size_ = r4_ - r2_; + + // r1_ at the beginning of the buffer. + RTC_DCHECK_EQ(r1_, input_buffer_.get()); + // r1_ left of r2_, r4_ left of r3_ and size correct. + RTC_DCHECK_EQ(r2_ - r1_, r4_ - r3_); + // r2_ left of r3. + RTC_DCHECK_LT(r2_, r3_); +} + +void SincResampler::InitializeKernel() { + // Blackman window parameters. + static const double kAlpha = 0.16; + static const double kA0 = 0.5 * (1.0 - kAlpha); + static const double kA1 = 0.5; + static const double kA2 = 0.5 * kAlpha; + + // Generates a set of windowed sinc() kernels. + // We generate a range of sub-sample offsets from 0.0 to 1.0. + const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_); + for (size_t offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) { + const float subsample_offset = + static_cast<float>(offset_idx) / kKernelOffsetCount; + + for (size_t i = 0; i < kKernelSize; ++i) { + const size_t idx = i + offset_idx * kKernelSize; + const float pre_sinc = static_cast<float>( + M_PI * (static_cast<int>(i) - static_cast<int>(kKernelSize / 2) - + subsample_offset)); + kernel_pre_sinc_storage_[idx] = pre_sinc; + + // Compute Blackman window, matching the offset of the sinc(). + const float x = (i - subsample_offset) / kKernelSize; + const float window = static_cast<float>(kA0 - kA1 * cos(2.0 * M_PI * x) + + kA2 * cos(4.0 * M_PI * x)); + kernel_window_storage_[idx] = window; + + // Compute the sinc with offset, then window the sinc() function and store + // at the correct offset. + kernel_storage_[idx] = static_cast<float>( + window * ((pre_sinc == 0) + ? sinc_scale_factor + : (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); + } + } +} + +void SincResampler::SetRatio(double io_sample_rate_ratio) { + if (fabs(io_sample_rate_ratio_ - io_sample_rate_ratio) < + std::numeric_limits<double>::epsilon()) { + return; + } + + io_sample_rate_ratio_ = io_sample_rate_ratio; + + // Optimize reinitialization by reusing values which are independent of + // `sinc_scale_factor`. Provides a 3x speedup. + const double sinc_scale_factor = SincScaleFactor(io_sample_rate_ratio_); + for (size_t offset_idx = 0; offset_idx <= kKernelOffsetCount; ++offset_idx) { + for (size_t i = 0; i < kKernelSize; ++i) { + const size_t idx = i + offset_idx * kKernelSize; + const float window = kernel_window_storage_[idx]; + const float pre_sinc = kernel_pre_sinc_storage_[idx]; + + kernel_storage_[idx] = static_cast<float>( + window * ((pre_sinc == 0) + ? sinc_scale_factor + : (sin(sinc_scale_factor * pre_sinc) / pre_sinc))); + } + } +} + +void SincResampler::Resample(size_t frames, float* destination) { + size_t remaining_frames = frames; + + // Step (1) -- Prime the input buffer at the start of the input stream. + if (!buffer_primed_ && remaining_frames) { + read_cb_->Run(request_frames_, r0_); + buffer_primed_ = true; + } + + // Step (2) -- Resample! const what we can outside of the loop for speed. It + // actually has an impact on ARM performance. See inner loop comment below. + const double current_io_ratio = io_sample_rate_ratio_; + const float* const kernel_ptr = kernel_storage_.get(); + while (remaining_frames) { + // `i` may be negative if the last Resample() call ended on an iteration + // that put `virtual_source_idx_` over the limit. + // + // Note: The loop construct here can severely impact performance on ARM + // or when built with clang. See https://codereview.chromium.org/18566009/ + for (int i = static_cast<int>( + ceil((block_size_ - virtual_source_idx_) / current_io_ratio)); + i > 0; --i) { + RTC_DCHECK_LT(virtual_source_idx_, block_size_); + + // `virtual_source_idx_` lies in between two kernel offsets so figure out + // what they are. + const int source_idx = static_cast<int>(virtual_source_idx_); + const double subsample_remainder = virtual_source_idx_ - source_idx; + + const double virtual_offset_idx = + subsample_remainder * kKernelOffsetCount; + const int offset_idx = static_cast<int>(virtual_offset_idx); + + // We'll compute "convolutions" for the two kernels which straddle + // `virtual_source_idx_`. + const float* const k1 = kernel_ptr + offset_idx * kKernelSize; + const float* const k2 = k1 + kKernelSize; + + // Ensure `k1`, `k2` are 32-byte aligned for SIMD usage. Should always be + // true so long as kKernelSize is a multiple of 32. + RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k1) % 32); + RTC_DCHECK_EQ(0, reinterpret_cast<uintptr_t>(k2) % 32); + + // Initialize input pointer based on quantized `virtual_source_idx_`. + const float* const input_ptr = r1_ + source_idx; + + // Figure out how much to weight each kernel's "convolution". + const double kernel_interpolation_factor = + virtual_offset_idx - offset_idx; + *destination++ = + convolve_proc_(input_ptr, k1, k2, kernel_interpolation_factor); + + // Advance the virtual index. + virtual_source_idx_ += current_io_ratio; + + if (!--remaining_frames) + return; + } + + // Wrap back around to the start. + virtual_source_idx_ -= block_size_; + + // Step (3) -- Copy r3_, r4_ to r1_, r2_. + // This wraps the last input frames back to the start of the buffer. + memcpy(r1_, r3_, sizeof(*input_buffer_.get()) * kKernelSize); + + // Step (4) -- Reinitialize regions if necessary. + if (r0_ == r2_) + UpdateRegions(true); + + // Step (5) -- Refresh the buffer with more input. + read_cb_->Run(request_frames_, r0_); + } +} + +#undef CONVOLVE_FUNC + +size_t SincResampler::ChunkSize() const { + return static_cast<size_t>(block_size_ / io_sample_rate_ratio_); +} + +void SincResampler::Flush() { + virtual_source_idx_ = 0; + buffer_primed_ = false; + memset(input_buffer_.get(), 0, + sizeof(*input_buffer_.get()) * input_buffer_size_); + UpdateRegions(false); +} + +float SincResampler::Convolve_C(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor) { + float sum1 = 0; + float sum2 = 0; + + // Generate a single output sample. Unrolling this loop hurt performance in + // local testing. + size_t n = kKernelSize; + while (n--) { + sum1 += *input_ptr * *k1++; + sum2 += *input_ptr++ * *k2++; + } + + // Linearly interpolate the two "convolutions". + return static_cast<float>((1.0 - kernel_interpolation_factor) * sum1 + + kernel_interpolation_factor * sum2); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/sinc_resampler.h b/third_party/libwebrtc/common_audio/resampler/sinc_resampler.h new file mode 100644 index 0000000000..b89bba7ab4 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinc_resampler.h @@ -0,0 +1,181 @@ +/* + * 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. + */ + +// Modified from the Chromium original here: +// src/media/base/sinc_resampler.h + +#ifndef COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ +#define COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ + +#include <stddef.h> + +#include <memory> + +#include "rtc_base/gtest_prod_util.h" +#include "rtc_base/memory/aligned_malloc.h" +#include "rtc_base/system/arch.h" + +namespace webrtc { + +// Callback class for providing more data into the resampler. Expects `frames` +// of data to be rendered into `destination`; zero padded if not enough frames +// are available to satisfy the request. +class SincResamplerCallback { + public: + virtual ~SincResamplerCallback() {} + virtual void Run(size_t frames, float* destination) = 0; +}; + +// SincResampler is a high-quality single-channel sample-rate converter. +class SincResampler { + public: + // The kernel size can be adjusted for quality (higher is better) at the + // expense of performance. Must be a multiple of 32. + // TODO(dalecurtis): Test performance to see if we can jack this up to 64+. + static const size_t kKernelSize = 32; + + // Default request size. Affects how often and for how much SincResampler + // calls back for input. Must be greater than kKernelSize. + static const size_t kDefaultRequestSize = 512; + + // The kernel offset count is used for interpolation and is the number of + // sub-sample kernel shifts. Can be adjusted for quality (higher is better) + // at the expense of allocating more memory. + static const size_t kKernelOffsetCount = 32; + static const size_t kKernelStorageSize = + kKernelSize * (kKernelOffsetCount + 1); + + // Constructs a SincResampler with the specified `read_cb`, which is used to + // acquire audio data for resampling. `io_sample_rate_ratio` is the ratio + // of input / output sample rates. `request_frames` controls the size in + // frames of the buffer requested by each `read_cb` call. The value must be + // greater than kKernelSize. Specify kDefaultRequestSize if there are no + // request size constraints. + SincResampler(double io_sample_rate_ratio, + size_t request_frames, + SincResamplerCallback* read_cb); + virtual ~SincResampler(); + + SincResampler(const SincResampler&) = delete; + SincResampler& operator=(const SincResampler&) = delete; + + // Resample `frames` of data from `read_cb_` into `destination`. + void Resample(size_t frames, float* destination); + + // The maximum size in frames that guarantees Resample() will only make a + // single call to `read_cb_` for more data. + size_t ChunkSize() const; + + size_t request_frames() const { return request_frames_; } + + // Flush all buffered data and reset internal indices. Not thread safe, do + // not call while Resample() is in progress. + void Flush(); + + // Update `io_sample_rate_ratio_`. SetRatio() will cause a reconstruction of + // the kernels used for resampling. Not thread safe, do not call while + // Resample() is in progress. + // + // TODO(ajm): Use this in PushSincResampler rather than reconstructing + // SincResampler. We would also need a way to update `request_frames_`. + void SetRatio(double io_sample_rate_ratio); + + float* get_kernel_for_testing() { return kernel_storage_.get(); } + + private: + FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, Convolve); + FRIEND_TEST_ALL_PREFIXES(SincResamplerTest, ConvolveBenchmark); + + void InitializeKernel(); + void UpdateRegions(bool second_load); + + // Selects runtime specific CPU features like SSE. Must be called before + // using SincResampler. + // TODO(ajm): Currently managed by the class internally. See the note with + // `convolve_proc_` below. + void InitializeCPUSpecificFeatures(); + + // Compute convolution of `k1` and `k2` over `input_ptr`, resultant sums are + // linearly interpolated using `kernel_interpolation_factor`. On x86 and ARM + // the underlying implementation is chosen at run time. + static float Convolve_C(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor); +#if defined(WEBRTC_ARCH_X86_FAMILY) + static float Convolve_SSE(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor); + static float Convolve_AVX2(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor); +#elif defined(WEBRTC_HAS_NEON) + static float Convolve_NEON(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor); +#endif + + // The ratio of input / output sample rates. + double io_sample_rate_ratio_; + + // An index on the source input buffer with sub-sample precision. It must be + // double precision to avoid drift. + double virtual_source_idx_; + + // The buffer is primed once at the very beginning of processing. + bool buffer_primed_; + + // Source of data for resampling. + SincResamplerCallback* read_cb_; + + // The size (in samples) to request from each `read_cb_` execution. + const size_t request_frames_; + + // The number of source frames processed per pass. + size_t block_size_; + + // The size (in samples) of the internal buffer used by the resampler. + const size_t input_buffer_size_; + + // Contains kKernelOffsetCount kernels back-to-back, each of size kKernelSize. + // The kernel offsets are sub-sample shifts of a windowed sinc shifted from + // 0.0 to 1.0 sample. + std::unique_ptr<float[], AlignedFreeDeleter> kernel_storage_; + std::unique_ptr<float[], AlignedFreeDeleter> kernel_pre_sinc_storage_; + std::unique_ptr<float[], AlignedFreeDeleter> kernel_window_storage_; + + // Data from the source is copied into this buffer for each processing pass. + std::unique_ptr<float[], AlignedFreeDeleter> input_buffer_; + +// Stores the runtime selection of which Convolve function to use. +// TODO(ajm): Move to using a global static which must only be initialized +// once by the user. We're not doing this initially, because we don't have +// e.g. a LazyInstance helper in webrtc. + typedef float (*ConvolveProc)(const float*, + const float*, + const float*, + double); + ConvolveProc convolve_proc_; + + // Pointers to the various regions inside `input_buffer_`. See the diagram at + // the top of the .cc file for more information. + float* r0_; + float* const r1_; + float* const r2_; + float* r3_; + float* r4_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_ diff --git a/third_party/libwebrtc/common_audio/resampler/sinc_resampler_avx2.cc b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_avx2.cc new file mode 100644 index 0000000000..d945a10be2 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_avx2.cc @@ -0,0 +1,66 @@ +/* + * 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. + */ + +#include <immintrin.h> +#include <stddef.h> +#include <stdint.h> +#include <xmmintrin.h> + +#include "common_audio/resampler/sinc_resampler.h" + +namespace webrtc { + +float SincResampler::Convolve_AVX2(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor) { + __m256 m_input; + __m256 m_sums1 = _mm256_setzero_ps(); + __m256 m_sums2 = _mm256_setzero_ps(); + + // Based on `input_ptr` alignment, we need to use loadu or load. Unrolling + // these loops has not been tested or benchmarked. + bool aligned_input = (reinterpret_cast<uintptr_t>(input_ptr) & 0x1F) == 0; + if (!aligned_input) { + for (size_t i = 0; i < kKernelSize; i += 8) { + m_input = _mm256_loadu_ps(input_ptr + i); + m_sums1 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k1 + i), m_sums1); + m_sums2 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k2 + i), m_sums2); + } + } else { + for (size_t i = 0; i < kKernelSize; i += 8) { + m_input = _mm256_load_ps(input_ptr + i); + m_sums1 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k1 + i), m_sums1); + m_sums2 = _mm256_fmadd_ps(m_input, _mm256_load_ps(k2 + i), m_sums2); + } + } + + // Linearly interpolate the two "convolutions". + __m128 m128_sums1 = _mm_add_ps(_mm256_extractf128_ps(m_sums1, 0), + _mm256_extractf128_ps(m_sums1, 1)); + __m128 m128_sums2 = _mm_add_ps(_mm256_extractf128_ps(m_sums2, 0), + _mm256_extractf128_ps(m_sums2, 1)); + m128_sums1 = _mm_mul_ps( + m128_sums1, + _mm_set_ps1(static_cast<float>(1.0 - kernel_interpolation_factor))); + m128_sums2 = _mm_mul_ps( + m128_sums2, _mm_set_ps1(static_cast<float>(kernel_interpolation_factor))); + m128_sums1 = _mm_add_ps(m128_sums1, m128_sums2); + + // Sum components together. + float result; + m128_sums2 = _mm_add_ps(_mm_movehl_ps(m128_sums1, m128_sums1), m128_sums1); + _mm_store_ss(&result, _mm_add_ss(m128_sums2, + _mm_shuffle_ps(m128_sums2, m128_sums2, 1))); + + return result; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/sinc_resampler_neon.cc b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_neon.cc new file mode 100644 index 0000000000..9ee918bca3 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_neon.cc @@ -0,0 +1,48 @@ +/* + * 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. + */ + +// Modified from the Chromium original: +// src/media/base/sinc_resampler.cc + +#include <arm_neon.h> + +#include "common_audio/resampler/sinc_resampler.h" + +namespace webrtc { + +float SincResampler::Convolve_NEON(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor) { + float32x4_t m_input; + float32x4_t m_sums1 = vmovq_n_f32(0); + float32x4_t m_sums2 = vmovq_n_f32(0); + + const float* upper = input_ptr + kKernelSize; + for (; input_ptr < upper;) { + m_input = vld1q_f32(input_ptr); + input_ptr += 4; + m_sums1 = vmlaq_f32(m_sums1, m_input, vld1q_f32(k1)); + k1 += 4; + m_sums2 = vmlaq_f32(m_sums2, m_input, vld1q_f32(k2)); + k2 += 4; + } + + // Linearly interpolate the two "convolutions". + m_sums1 = vmlaq_f32( + vmulq_f32(m_sums1, vmovq_n_f32(1.0 - kernel_interpolation_factor)), + m_sums2, vmovq_n_f32(kernel_interpolation_factor)); + + // Sum components together. + float32x2_t m_half = vadd_f32(vget_high_f32(m_sums1), vget_low_f32(m_sums1)); + return vget_lane_f32(vpadd_f32(m_half, m_half), 0); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/sinc_resampler_sse.cc b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_sse.cc new file mode 100644 index 0000000000..30a8d1b2d9 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_sse.cc @@ -0,0 +1,63 @@ +/* + * 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. + */ + +// Modified from the Chromium original: +// src/media/base/simd/sinc_resampler_sse.cc + +#include <stddef.h> +#include <stdint.h> +#include <xmmintrin.h> + +#include "common_audio/resampler/sinc_resampler.h" + +namespace webrtc { + +float SincResampler::Convolve_SSE(const float* input_ptr, + const float* k1, + const float* k2, + double kernel_interpolation_factor) { + __m128 m_input; + __m128 m_sums1 = _mm_setzero_ps(); + __m128 m_sums2 = _mm_setzero_ps(); + + // Based on `input_ptr` alignment, we need to use loadu or load. Unrolling + // these loops hurt performance in local testing. + if (reinterpret_cast<uintptr_t>(input_ptr) & 0x0F) { + for (size_t i = 0; i < kKernelSize; i += 4) { + m_input = _mm_loadu_ps(input_ptr + i); + m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); + m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); + } + } else { + for (size_t i = 0; i < kKernelSize; i += 4) { + m_input = _mm_load_ps(input_ptr + i); + m_sums1 = _mm_add_ps(m_sums1, _mm_mul_ps(m_input, _mm_load_ps(k1 + i))); + m_sums2 = _mm_add_ps(m_sums2, _mm_mul_ps(m_input, _mm_load_ps(k2 + i))); + } + } + + // Linearly interpolate the two "convolutions". + m_sums1 = _mm_mul_ps( + m_sums1, + _mm_set_ps1(static_cast<float>(1.0 - kernel_interpolation_factor))); + m_sums2 = _mm_mul_ps( + m_sums2, _mm_set_ps1(static_cast<float>(kernel_interpolation_factor))); + m_sums1 = _mm_add_ps(m_sums1, m_sums2); + + // Sum components together. + float result; + m_sums2 = _mm_add_ps(_mm_movehl_ps(m_sums1, m_sums1), m_sums1); + _mm_store_ss(&result, + _mm_add_ss(m_sums2, _mm_shuffle_ps(m_sums2, m_sums2, 1))); + + return result; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/sinc_resampler_unittest.cc b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_unittest.cc new file mode 100644 index 0000000000..b267c89c8b --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinc_resampler_unittest.cc @@ -0,0 +1,393 @@ +/* + * 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. + */ + +// Modified from the Chromium original: +// src/media/base/sinc_resampler_unittest.cc + +// MSVC++ requires this to be set before any other includes to get M_PI. +#define _USE_MATH_DEFINES + +#include "common_audio/resampler/sinc_resampler.h" + +#include <math.h> + +#include <algorithm> +#include <memory> +#include <tuple> + +#include "common_audio/resampler/sinusoidal_linear_chirp_source.h" +#include "rtc_base/system/arch.h" +#include "rtc_base/time_utils.h" +#include "system_wrappers/include/cpu_features_wrapper.h" +#include "test/gmock.h" +#include "test/gtest.h" + +using ::testing::_; + +namespace webrtc { + +static const double kSampleRateRatio = 192000.0 / 44100.0; +static const double kKernelInterpolationFactor = 0.5; + +// Helper class to ensure ChunkedResample() functions properly. +class MockSource : public SincResamplerCallback { + public: + MOCK_METHOD(void, Run, (size_t frames, float* destination), (override)); +}; + +ACTION(ClearBuffer) { + memset(arg1, 0, arg0 * sizeof(float)); +} + +ACTION(FillBuffer) { + // Value chosen arbitrarily such that SincResampler resamples it to something + // easily representable on all platforms; e.g., using kSampleRateRatio this + // becomes 1.81219. + memset(arg1, 64, arg0 * sizeof(float)); +} + +// Test requesting multiples of ChunkSize() frames results in the proper number +// of callbacks. +TEST(SincResamplerTest, ChunkedResample) { + MockSource mock_source; + + // Choose a high ratio of input to output samples which will result in quick + // exhaustion of SincResampler's internal buffers. + SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, + &mock_source); + + static const int kChunks = 2; + size_t max_chunk_size = resampler.ChunkSize() * kChunks; + std::unique_ptr<float[]> resampled_destination(new float[max_chunk_size]); + + // Verify requesting ChunkSize() frames causes a single callback. + EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(ClearBuffer()); + resampler.Resample(resampler.ChunkSize(), resampled_destination.get()); + + // Verify requesting kChunks * ChunkSize() frames causes kChunks callbacks. + ::testing::Mock::VerifyAndClear(&mock_source); + EXPECT_CALL(mock_source, Run(_, _)) + .Times(kChunks) + .WillRepeatedly(ClearBuffer()); + resampler.Resample(max_chunk_size, resampled_destination.get()); +} + +// Test flush resets the internal state properly. +TEST(SincResamplerTest, Flush) { + MockSource mock_source; + SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, + &mock_source); + std::unique_ptr<float[]> resampled_destination( + new float[resampler.ChunkSize()]); + + // Fill the resampler with junk data. + EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(FillBuffer()); + resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get()); + ASSERT_NE(resampled_destination[0], 0); + + // Flush and request more data, which should all be zeros now. + resampler.Flush(); + ::testing::Mock::VerifyAndClear(&mock_source); + EXPECT_CALL(mock_source, Run(_, _)).Times(1).WillOnce(ClearBuffer()); + resampler.Resample(resampler.ChunkSize() / 2, resampled_destination.get()); + for (size_t i = 0; i < resampler.ChunkSize() / 2; ++i) + ASSERT_FLOAT_EQ(resampled_destination[i], 0); +} + +// Test flush resets the internal state properly. +TEST(SincResamplerTest, DISABLED_SetRatioBench) { + MockSource mock_source; + SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, + &mock_source); + + int64_t start = rtc::TimeNanos(); + for (int i = 1; i < 10000; ++i) + resampler.SetRatio(1.0 / i); + double total_time_c_us = + (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec; + printf("SetRatio() took %.2fms.\n", total_time_c_us / 1000); +} + +// Ensure various optimized Convolve() methods return the same value. Only run +// this test if other optimized methods exist, otherwise the default Convolve() +// will be tested by the parameterized SincResampler tests below. +TEST(SincResamplerTest, Convolve) { +#if defined(WEBRTC_ARCH_X86_FAMILY) + ASSERT_TRUE(GetCPUInfo(kSSE2)); +#elif defined(WEBRTC_ARCH_ARM_V7) + ASSERT_TRUE(GetCPUFeaturesARM() & kCPUFeatureNEON); +#endif + + // Initialize a dummy resampler. + MockSource mock_source; + SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, + &mock_source); + + // The optimized Convolve methods are slightly more precise than Convolve_C(), + // so comparison must be done using an epsilon. + static const double kEpsilon = 0.00000005; + + // Use a kernel from SincResampler as input and kernel data, this has the + // benefit of already being properly sized and aligned for Convolve_SSE(). + double result = resampler.Convolve_C( + resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), + resampler.kernel_storage_.get(), kKernelInterpolationFactor); + double result2 = resampler.convolve_proc_( + resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), + resampler.kernel_storage_.get(), kKernelInterpolationFactor); + EXPECT_NEAR(result2, result, kEpsilon); + + // Test Convolve() w/ unaligned input pointer. + result = resampler.Convolve_C( + resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(), + resampler.kernel_storage_.get(), kKernelInterpolationFactor); + result2 = resampler.convolve_proc_( + resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(), + resampler.kernel_storage_.get(), kKernelInterpolationFactor); + EXPECT_NEAR(result2, result, kEpsilon); +} + +// Benchmark for the various Convolve() methods. Make sure to build with +// branding=Chrome so that RTC_DCHECKs are compiled out when benchmarking. +// Original benchmarks were run with --convolve-iterations=50000000. +TEST(SincResamplerTest, ConvolveBenchmark) { + // Initialize a dummy resampler. + MockSource mock_source; + SincResampler resampler(kSampleRateRatio, SincResampler::kDefaultRequestSize, + &mock_source); + + // Retrieve benchmark iterations from command line. + // TODO(ajm): Reintroduce this as a command line option. + const int kConvolveIterations = 1000000; + + printf("Benchmarking %d iterations:\n", kConvolveIterations); + + // Benchmark Convolve_C(). + int64_t start = rtc::TimeNanos(); + for (int i = 0; i < kConvolveIterations; ++i) { + resampler.Convolve_C( + resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), + resampler.kernel_storage_.get(), kKernelInterpolationFactor); + } + double total_time_c_us = + (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec; + printf("Convolve_C took %.2fms.\n", total_time_c_us / 1000); + +#if defined(WEBRTC_ARCH_X86_FAMILY) + ASSERT_TRUE(GetCPUInfo(kSSE2)); +#elif defined(WEBRTC_ARCH_ARM_V7) + ASSERT_TRUE(GetCPUFeaturesARM() & kCPUFeatureNEON); +#endif + + // Benchmark with unaligned input pointer. + start = rtc::TimeNanos(); + for (int j = 0; j < kConvolveIterations; ++j) { + resampler.convolve_proc_( + resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(), + resampler.kernel_storage_.get(), kKernelInterpolationFactor); + } + double total_time_optimized_unaligned_us = + (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec; + printf( + "convolve_proc_(unaligned) took %.2fms; which is %.2fx " + "faster than Convolve_C.\n", + total_time_optimized_unaligned_us / 1000, + total_time_c_us / total_time_optimized_unaligned_us); + + // Benchmark with aligned input pointer. + start = rtc::TimeNanos(); + for (int j = 0; j < kConvolveIterations; ++j) { + resampler.convolve_proc_( + resampler.kernel_storage_.get(), resampler.kernel_storage_.get(), + resampler.kernel_storage_.get(), kKernelInterpolationFactor); + } + double total_time_optimized_aligned_us = + (rtc::TimeNanos() - start) / rtc::kNumNanosecsPerMicrosec; + printf( + "convolve_proc_ (aligned) took %.2fms; which is %.2fx " + "faster than Convolve_C and %.2fx faster than " + "convolve_proc_ (unaligned).\n", + total_time_optimized_aligned_us / 1000, + total_time_c_us / total_time_optimized_aligned_us, + total_time_optimized_unaligned_us / total_time_optimized_aligned_us); +} + +typedef std::tuple<int, int, double, double> SincResamplerTestData; +class SincResamplerTest + : public ::testing::TestWithParam<SincResamplerTestData> { + public: + SincResamplerTest() + : input_rate_(std::get<0>(GetParam())), + output_rate_(std::get<1>(GetParam())), + rms_error_(std::get<2>(GetParam())), + low_freq_error_(std::get<3>(GetParam())) {} + + virtual ~SincResamplerTest() {} + + protected: + int input_rate_; + int output_rate_; + double rms_error_; + double low_freq_error_; +}; + +// Tests resampling using a given input and output sample rate. +TEST_P(SincResamplerTest, Resample) { + // Make comparisons using one second of data. + static const double kTestDurationSecs = 1; + const size_t input_samples = + static_cast<size_t>(kTestDurationSecs * input_rate_); + const size_t output_samples = + static_cast<size_t>(kTestDurationSecs * output_rate_); + + // Nyquist frequency for the input sampling rate. + const double input_nyquist_freq = 0.5 * input_rate_; + + // Source for data to be resampled. + SinusoidalLinearChirpSource resampler_source(input_rate_, input_samples, + input_nyquist_freq, 0); + + const double io_ratio = input_rate_ / static_cast<double>(output_rate_); + SincResampler resampler(io_ratio, SincResampler::kDefaultRequestSize, + &resampler_source); + + // Force an update to the sample rate ratio to ensure dynamic sample rate + // changes are working correctly. + std::unique_ptr<float[]> kernel(new float[SincResampler::kKernelStorageSize]); + memcpy(kernel.get(), resampler.get_kernel_for_testing(), + SincResampler::kKernelStorageSize); + resampler.SetRatio(M_PI); + ASSERT_NE(0, memcmp(kernel.get(), resampler.get_kernel_for_testing(), + SincResampler::kKernelStorageSize)); + resampler.SetRatio(io_ratio); + ASSERT_EQ(0, memcmp(kernel.get(), resampler.get_kernel_for_testing(), + SincResampler::kKernelStorageSize)); + + // TODO(dalecurtis): If we switch to AVX/SSE optimization, we'll need to + // allocate these on 32-byte boundaries and ensure they're sized % 32 bytes. + std::unique_ptr<float[]> resampled_destination(new float[output_samples]); + std::unique_ptr<float[]> pure_destination(new float[output_samples]); + + // Generate resampled signal. + resampler.Resample(output_samples, resampled_destination.get()); + + // Generate pure signal. + SinusoidalLinearChirpSource pure_source(output_rate_, output_samples, + input_nyquist_freq, 0); + pure_source.Run(output_samples, pure_destination.get()); + + // Range of the Nyquist frequency (0.5 * min(input rate, output_rate)) which + // we refer to as low and high. + static const double kLowFrequencyNyquistRange = 0.7; + static const double kHighFrequencyNyquistRange = 0.9; + + // Calculate Root-Mean-Square-Error and maximum error for the resampling. + double sum_of_squares = 0; + double low_freq_max_error = 0; + double high_freq_max_error = 0; + int minimum_rate = std::min(input_rate_, output_rate_); + double low_frequency_range = kLowFrequencyNyquistRange * 0.5 * minimum_rate; + double high_frequency_range = kHighFrequencyNyquistRange * 0.5 * minimum_rate; + for (size_t i = 0; i < output_samples; ++i) { + double error = fabs(resampled_destination[i] - pure_destination[i]); + + if (pure_source.Frequency(i) < low_frequency_range) { + if (error > low_freq_max_error) + low_freq_max_error = error; + } else if (pure_source.Frequency(i) < high_frequency_range) { + if (error > high_freq_max_error) + high_freq_max_error = error; + } + // TODO(dalecurtis): Sanity check frequencies > kHighFrequencyNyquistRange. + + sum_of_squares += error * error; + } + + double rms_error = sqrt(sum_of_squares / output_samples); + +// Convert each error to dbFS. +#define DBFS(x) 20 * log10(x) + rms_error = DBFS(rms_error); + low_freq_max_error = DBFS(low_freq_max_error); + high_freq_max_error = DBFS(high_freq_max_error); + + EXPECT_LE(rms_error, rms_error_); + EXPECT_LE(low_freq_max_error, low_freq_error_); + + // All conversions currently have a high frequency error around -6 dbFS. + static const double kHighFrequencyMaxError = -6.02; + EXPECT_LE(high_freq_max_error, kHighFrequencyMaxError); +} + +// Almost all conversions have an RMS error of around -14 dbFS. +static const double kResamplingRMSError = -14.58; + +// Thresholds chosen arbitrarily based on what each resampling reported during +// testing. All thresholds are in dbFS, http://en.wikipedia.org/wiki/DBFS. +INSTANTIATE_TEST_SUITE_P( + SincResamplerTest, + SincResamplerTest, + ::testing::Values( + // To 22.05kHz + std::make_tuple(8000, 22050, kResamplingRMSError, -62.73), + std::make_tuple(11025, 22050, kResamplingRMSError, -72.19), + std::make_tuple(16000, 22050, kResamplingRMSError, -62.54), + std::make_tuple(22050, 22050, kResamplingRMSError, -73.53), + std::make_tuple(32000, 22050, kResamplingRMSError, -46.45), + std::make_tuple(44100, 22050, kResamplingRMSError, -28.49), + std::make_tuple(48000, 22050, -15.01, -25.56), + std::make_tuple(96000, 22050, -18.49, -13.42), + std::make_tuple(192000, 22050, -20.50, -9.23), + + // To 44.1kHz + std::make_tuple(8000, 44100, kResamplingRMSError, -62.73), + std::make_tuple(11025, 44100, kResamplingRMSError, -72.19), + std::make_tuple(16000, 44100, kResamplingRMSError, -62.54), + std::make_tuple(22050, 44100, kResamplingRMSError, -73.53), + std::make_tuple(32000, 44100, kResamplingRMSError, -63.32), + std::make_tuple(44100, 44100, kResamplingRMSError, -73.52), + std::make_tuple(48000, 44100, -15.01, -64.04), + std::make_tuple(96000, 44100, -18.49, -25.51), + std::make_tuple(192000, 44100, -20.50, -13.31), + + // To 48kHz + std::make_tuple(8000, 48000, kResamplingRMSError, -63.43), + std::make_tuple(11025, 48000, kResamplingRMSError, -62.61), + std::make_tuple(16000, 48000, kResamplingRMSError, -63.95), + std::make_tuple(22050, 48000, kResamplingRMSError, -62.42), + std::make_tuple(32000, 48000, kResamplingRMSError, -64.04), + std::make_tuple(44100, 48000, kResamplingRMSError, -62.63), + std::make_tuple(48000, 48000, kResamplingRMSError, -73.52), + std::make_tuple(96000, 48000, -18.40, -28.44), + std::make_tuple(192000, 48000, -20.43, -14.11), + + // To 96kHz + std::make_tuple(8000, 96000, kResamplingRMSError, -63.19), + std::make_tuple(11025, 96000, kResamplingRMSError, -62.61), + std::make_tuple(16000, 96000, kResamplingRMSError, -63.39), + std::make_tuple(22050, 96000, kResamplingRMSError, -62.42), + std::make_tuple(32000, 96000, kResamplingRMSError, -63.95), + std::make_tuple(44100, 96000, kResamplingRMSError, -62.63), + std::make_tuple(48000, 96000, kResamplingRMSError, -73.52), + std::make_tuple(96000, 96000, kResamplingRMSError, -73.52), + std::make_tuple(192000, 96000, kResamplingRMSError, -28.41), + + // To 192kHz + std::make_tuple(8000, 192000, kResamplingRMSError, -63.10), + std::make_tuple(11025, 192000, kResamplingRMSError, -62.61), + std::make_tuple(16000, 192000, kResamplingRMSError, -63.14), + std::make_tuple(22050, 192000, kResamplingRMSError, -62.42), + std::make_tuple(32000, 192000, kResamplingRMSError, -63.38), + std::make_tuple(44100, 192000, kResamplingRMSError, -62.63), + std::make_tuple(48000, 192000, kResamplingRMSError, -73.44), + std::make_tuple(96000, 192000, kResamplingRMSError, -73.52), + std::make_tuple(192000, 192000, kResamplingRMSError, -73.52))); + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc b/third_party/libwebrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc new file mode 100644 index 0000000000..2afdd1be47 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc @@ -0,0 +1,57 @@ +/* + * 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. + */ + +// MSVC++ requires this to be set before any other includes to get M_PI. +#define _USE_MATH_DEFINES + +#include "common_audio/resampler/sinusoidal_linear_chirp_source.h" + +#include <math.h> + +namespace webrtc { + +SinusoidalLinearChirpSource::SinusoidalLinearChirpSource(int sample_rate, + size_t samples, + double max_frequency, + double delay_samples) + : sample_rate_(sample_rate), + total_samples_(samples), + max_frequency_(max_frequency), + current_index_(0), + delay_samples_(delay_samples) { + // Chirp rate. + double duration = static_cast<double>(total_samples_) / sample_rate_; + k_ = (max_frequency_ - kMinFrequency) / duration; +} + +void SinusoidalLinearChirpSource::Run(size_t frames, float* destination) { + for (size_t i = 0; i < frames; ++i, ++current_index_) { + // Filter out frequencies higher than Nyquist. + if (Frequency(current_index_) > 0.5 * sample_rate_) { + destination[i] = 0; + } else { + // Calculate time in seconds. + if (current_index_ < delay_samples_) { + destination[i] = 0; + } else { + // Sinusoidal linear chirp. + double t = (current_index_ - delay_samples_) / sample_rate_; + destination[i] = sin(2 * M_PI * (kMinFrequency * t + (k_ / 2) * t * t)); + } + } + } +} + +double SinusoidalLinearChirpSource::Frequency(size_t position) { + return kMinFrequency + (position - delay_samples_) * + (max_frequency_ - kMinFrequency) / total_samples_; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h b/third_party/libwebrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h new file mode 100644 index 0000000000..ccd11bbd61 --- /dev/null +++ b/third_party/libwebrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h @@ -0,0 +1,56 @@ +/* + * 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. + */ + +// Modified from the Chromium original here: +// src/media/base/sinc_resampler_unittest.cc + +#ifndef COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ +#define COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ + +#include "common_audio/resampler/sinc_resampler.h" + +namespace webrtc { + +// Fake audio source for testing the resampler. Generates a sinusoidal linear +// chirp (http://en.wikipedia.org/wiki/Chirp) which can be tuned to stress the +// resampler for the specific sample rate conversion being used. +class SinusoidalLinearChirpSource : public SincResamplerCallback { + public: + // `delay_samples` can be used to insert a fractional sample delay into the + // source. It will produce zeros until non-negative time is reached. + SinusoidalLinearChirpSource(int sample_rate, + size_t samples, + double max_frequency, + double delay_samples); + + ~SinusoidalLinearChirpSource() override {} + + SinusoidalLinearChirpSource(const SinusoidalLinearChirpSource&) = delete; + SinusoidalLinearChirpSource& operator=(const SinusoidalLinearChirpSource&) = + delete; + + void Run(size_t frames, float* destination) override; + + double Frequency(size_t position); + + private: + static constexpr int kMinFrequency = 5; + + int sample_rate_; + size_t total_samples_; + double max_frequency_; + double k_; + size_t current_index_; + double delay_samples_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_ diff --git a/third_party/libwebrtc/common_audio/ring_buffer.c b/third_party/libwebrtc/common_audio/ring_buffer.c new file mode 100644 index 0000000000..590f5f9bf1 --- /dev/null +++ b/third_party/libwebrtc/common_audio/ring_buffer.c @@ -0,0 +1,232 @@ +/* + * 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. + */ + +// A ring buffer to hold arbitrary data. Provides no thread safety. Unless +// otherwise specified, functions return 0 on success and -1 on error. + +#include "common_audio/ring_buffer.h" + +#include <stddef.h> // size_t +#include <stdlib.h> +#include <string.h> + +// Get address of region(s) from which we can read data. +// If the region is contiguous, `data_ptr_bytes_2` will be zero. +// If non-contiguous, `data_ptr_bytes_2` will be the size in bytes of the second +// region. Returns room available to be read or `element_count`, whichever is +// smaller. +static size_t GetBufferReadRegions(RingBuffer* buf, + size_t element_count, + void** data_ptr_1, + size_t* data_ptr_bytes_1, + void** data_ptr_2, + size_t* data_ptr_bytes_2) { + + const size_t readable_elements = WebRtc_available_read(buf); + const size_t read_elements = (readable_elements < element_count ? + readable_elements : element_count); + const size_t margin = buf->element_count - buf->read_pos; + + // Check to see if read is not contiguous. + if (read_elements > margin) { + // Write data in two blocks that wrap the buffer. + *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; + *data_ptr_bytes_1 = margin * buf->element_size; + *data_ptr_2 = buf->data; + *data_ptr_bytes_2 = (read_elements - margin) * buf->element_size; + } else { + *data_ptr_1 = buf->data + buf->read_pos * buf->element_size; + *data_ptr_bytes_1 = read_elements * buf->element_size; + *data_ptr_2 = NULL; + *data_ptr_bytes_2 = 0; + } + + return read_elements; +} + +RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size) { + RingBuffer* self = NULL; + if (element_count == 0 || element_size == 0) { + return NULL; + } + + self = malloc(sizeof(RingBuffer)); + if (!self) { + return NULL; + } + + self->data = malloc(element_count * element_size); + if (!self->data) { + free(self); + self = NULL; + return NULL; + } + + self->element_count = element_count; + self->element_size = element_size; + WebRtc_InitBuffer(self); + + return self; +} + +void WebRtc_InitBuffer(RingBuffer* self) { + self->read_pos = 0; + self->write_pos = 0; + self->rw_wrap = SAME_WRAP; + + // Initialize buffer to zeros + memset(self->data, 0, self->element_count * self->element_size); +} + +void WebRtc_FreeBuffer(void* handle) { + RingBuffer* self = (RingBuffer*)handle; + if (!self) { + return; + } + + free(self->data); + free(self); +} + +size_t WebRtc_ReadBuffer(RingBuffer* self, + void** data_ptr, + void* data, + size_t element_count) { + + if (self == NULL) { + return 0; + } + if (data == NULL) { + return 0; + } + + { + void* buf_ptr_1 = NULL; + void* buf_ptr_2 = NULL; + size_t buf_ptr_bytes_1 = 0; + size_t buf_ptr_bytes_2 = 0; + const size_t read_count = GetBufferReadRegions(self, + element_count, + &buf_ptr_1, + &buf_ptr_bytes_1, + &buf_ptr_2, + &buf_ptr_bytes_2); + if (buf_ptr_bytes_2 > 0) { + // We have a wrap around when reading the buffer. Copy the buffer data to + // `data` and point to it. + memcpy(data, buf_ptr_1, buf_ptr_bytes_1); + memcpy(((char*) data) + buf_ptr_bytes_1, buf_ptr_2, buf_ptr_bytes_2); + buf_ptr_1 = data; + } else if (!data_ptr) { + // No wrap, but a memcpy was requested. + memcpy(data, buf_ptr_1, buf_ptr_bytes_1); + } + if (data_ptr) { + // `buf_ptr_1` == `data` in the case of a wrap. + *data_ptr = read_count == 0 ? NULL : buf_ptr_1; + } + + // Update read position + WebRtc_MoveReadPtr(self, (int) read_count); + + return read_count; + } +} + +size_t WebRtc_WriteBuffer(RingBuffer* self, + const void* data, + size_t element_count) { + if (!self) { + return 0; + } + if (!data) { + return 0; + } + + { + const size_t free_elements = WebRtc_available_write(self); + const size_t write_elements = (free_elements < element_count ? free_elements + : element_count); + size_t n = write_elements; + const size_t margin = self->element_count - self->write_pos; + + if (write_elements > margin) { + // Buffer wrap around when writing. + memcpy(self->data + self->write_pos * self->element_size, + data, margin * self->element_size); + self->write_pos = 0; + n -= margin; + self->rw_wrap = DIFF_WRAP; + } + memcpy(self->data + self->write_pos * self->element_size, + ((const char*) data) + ((write_elements - n) * self->element_size), + n * self->element_size); + self->write_pos += n; + + return write_elements; + } +} + +int WebRtc_MoveReadPtr(RingBuffer* self, int element_count) { + if (!self) { + return 0; + } + + { + // We need to be able to take care of negative changes, hence use "int" + // instead of "size_t". + const int free_elements = (int) WebRtc_available_write(self); + const int readable_elements = (int) WebRtc_available_read(self); + int read_pos = (int) self->read_pos; + + if (element_count > readable_elements) { + element_count = readable_elements; + } + if (element_count < -free_elements) { + element_count = -free_elements; + } + + read_pos += element_count; + if (read_pos > (int) self->element_count) { + // Buffer wrap around. Restart read position and wrap indicator. + read_pos -= (int) self->element_count; + self->rw_wrap = SAME_WRAP; + } + if (read_pos < 0) { + // Buffer wrap around. Restart read position and wrap indicator. + read_pos += (int) self->element_count; + self->rw_wrap = DIFF_WRAP; + } + + self->read_pos = (size_t) read_pos; + + return element_count; + } +} + +size_t WebRtc_available_read(const RingBuffer* self) { + if (!self) { + return 0; + } + + if (self->rw_wrap == SAME_WRAP) { + return self->write_pos - self->read_pos; + } else { + return self->element_count - self->read_pos + self->write_pos; + } +} + +size_t WebRtc_available_write(const RingBuffer* self) { + if (!self) { + return 0; + } + + return self->element_count - WebRtc_available_read(self); +} diff --git a/third_party/libwebrtc/common_audio/ring_buffer.h b/third_party/libwebrtc/common_audio/ring_buffer.h new file mode 100644 index 0000000000..de0b4fed80 --- /dev/null +++ b/third_party/libwebrtc/common_audio/ring_buffer.h @@ -0,0 +1,79 @@ +/* + * 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. + */ + +// A ring buffer to hold arbitrary data. Provides no thread safety. Unless +// otherwise specified, functions return 0 on success and -1 on error. + +#ifndef COMMON_AUDIO_RING_BUFFER_H_ +#define COMMON_AUDIO_RING_BUFFER_H_ + +// TODO(alessiob): Used by AEC, AECm and AudioRingBuffer. Remove when possible. + +#ifdef __cplusplus +extern "C" { +#endif + +#include <stddef.h> // size_t + +enum Wrap { SAME_WRAP, DIFF_WRAP }; + +typedef struct RingBuffer { + size_t read_pos; + size_t write_pos; + size_t element_count; + size_t element_size; + enum Wrap rw_wrap; + char* data; +} RingBuffer; + +// Creates and initializes the buffer. Returns null on failure. +RingBuffer* WebRtc_CreateBuffer(size_t element_count, size_t element_size); +void WebRtc_InitBuffer(RingBuffer* handle); +void WebRtc_FreeBuffer(void* handle); + +// Reads data from the buffer. Returns the number of elements that were read. +// The `data_ptr` will point to the address where the read data is located. +// If no data can be read, `data_ptr` is set to `NULL`. If all data can be read +// without buffer wrap around then `data_ptr` will point to the location in the +// buffer. Otherwise, the data will be copied to `data` (memory allocation done +// by the user) and `data_ptr` points to the address of `data`. `data_ptr` is +// only guaranteed to be valid until the next call to WebRtc_WriteBuffer(). +// +// To force a copying to `data`, pass a null `data_ptr`. +// +// Returns number of elements read. +size_t WebRtc_ReadBuffer(RingBuffer* handle, + void** data_ptr, + void* data, + size_t element_count); + +// Writes `data` to buffer and returns the number of elements written. +size_t WebRtc_WriteBuffer(RingBuffer* handle, + const void* data, + size_t element_count); + +// Moves the buffer read position and returns the number of elements moved. +// Positive `element_count` moves the read position towards the write position, +// that is, flushing the buffer. Negative `element_count` moves the read +// position away from the the write position, that is, stuffing the buffer. +// Returns number of elements moved. +int WebRtc_MoveReadPtr(RingBuffer* handle, int element_count); + +// Returns number of available elements to read. +size_t WebRtc_available_read(const RingBuffer* handle); + +// Returns number of available elements for write. +size_t WebRtc_available_write(const RingBuffer* handle); + +#ifdef __cplusplus +} +#endif + +#endif // COMMON_AUDIO_RING_BUFFER_H_ diff --git a/third_party/libwebrtc/common_audio/ring_buffer_unittest.cc b/third_party/libwebrtc/common_audio/ring_buffer_unittest.cc new file mode 100644 index 0000000000..0ead7e7981 --- /dev/null +++ b/third_party/libwebrtc/common_audio/ring_buffer_unittest.cc @@ -0,0 +1,150 @@ +/* + * 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 "common_audio/ring_buffer.h" + +#include <stdlib.h> +#include <time.h> + +#include <algorithm> +#include <memory> + +#include "test/gtest.h" + +namespace webrtc { + +struct FreeBufferDeleter { + inline void operator()(void* ptr) const { WebRtc_FreeBuffer(ptr); } +}; +typedef std::unique_ptr<RingBuffer, FreeBufferDeleter> scoped_ring_buffer; + +static void AssertElementEq(int expected, int actual) { + ASSERT_EQ(expected, actual); +} + +static int SetIncrementingData(int* data, + int num_elements, + int starting_value) { + for (int i = 0; i < num_elements; i++) { + data[i] = starting_value++; + } + return starting_value; +} + +static int CheckIncrementingData(int* data, + int num_elements, + int starting_value) { + for (int i = 0; i < num_elements; i++) { + AssertElementEq(starting_value++, data[i]); + } + return starting_value; +} + +// We use ASSERTs in this test to avoid obscuring the seed in the case of a +// failure. +static void RandomStressTest(int** data_ptr) { + const int kNumTests = 10; + const int kNumOps = 1000; + const int kMaxBufferSize = 1000; + + unsigned int seed = time(nullptr); + printf("seed=%u\n", seed); + srand(seed); + for (int i = 0; i < kNumTests; i++) { + // rand_r is not supported on many platforms, so rand is used. + const int buffer_size = std::max(rand() % kMaxBufferSize, 1); // NOLINT + std::unique_ptr<int[]> write_data(new int[buffer_size]); + std::unique_ptr<int[]> read_data(new int[buffer_size]); + scoped_ring_buffer buffer(WebRtc_CreateBuffer(buffer_size, sizeof(int))); + ASSERT_TRUE(buffer.get() != nullptr); + WebRtc_InitBuffer(buffer.get()); + int buffer_consumed = 0; + int write_element = 0; + int read_element = 0; + for (int j = 0; j < kNumOps; j++) { + const bool write = rand() % 2 == 0 ? true : false; // NOLINT + const int num_elements = rand() % buffer_size; // NOLINT + if (write) { + const int buffer_available = buffer_size - buffer_consumed; + ASSERT_EQ(static_cast<size_t>(buffer_available), + WebRtc_available_write(buffer.get())); + const int expected_elements = std::min(num_elements, buffer_available); + write_element = SetIncrementingData(write_data.get(), expected_elements, + write_element); + ASSERT_EQ( + static_cast<size_t>(expected_elements), + WebRtc_WriteBuffer(buffer.get(), write_data.get(), num_elements)); + buffer_consumed = + std::min(buffer_consumed + expected_elements, buffer_size); + } else { + const int expected_elements = std::min(num_elements, buffer_consumed); + ASSERT_EQ(static_cast<size_t>(buffer_consumed), + WebRtc_available_read(buffer.get())); + ASSERT_EQ( + static_cast<size_t>(expected_elements), + WebRtc_ReadBuffer(buffer.get(), reinterpret_cast<void**>(data_ptr), + read_data.get(), num_elements)); + int* check_ptr = read_data.get(); + if (data_ptr) { + check_ptr = *data_ptr; + } + read_element = + CheckIncrementingData(check_ptr, expected_elements, read_element); + buffer_consumed = std::max(buffer_consumed - expected_elements, 0); + } + } + } +} + +TEST(RingBufferTest, RandomStressTest) { + int* data_ptr = nullptr; + RandomStressTest(&data_ptr); +} + +TEST(RingBufferTest, RandomStressTestWithNullPtr) { + RandomStressTest(nullptr); +} + +TEST(RingBufferTest, PassingNulltoReadBufferForcesMemcpy) { + const size_t kDataSize = 2; + int write_data[kDataSize]; + int read_data[kDataSize]; + int* data_ptr; + + scoped_ring_buffer buffer(WebRtc_CreateBuffer(kDataSize, sizeof(int))); + ASSERT_TRUE(buffer.get() != nullptr); + WebRtc_InitBuffer(buffer.get()); + + SetIncrementingData(write_data, kDataSize, 0); + EXPECT_EQ(kDataSize, WebRtc_WriteBuffer(buffer.get(), write_data, kDataSize)); + SetIncrementingData(read_data, kDataSize, kDataSize); + EXPECT_EQ(kDataSize, + WebRtc_ReadBuffer(buffer.get(), reinterpret_cast<void**>(&data_ptr), + read_data, kDataSize)); + // Copying was not necessary, so `read_data` has not been updated. + CheckIncrementingData(data_ptr, kDataSize, 0); + CheckIncrementingData(read_data, kDataSize, kDataSize); + + EXPECT_EQ(kDataSize, WebRtc_WriteBuffer(buffer.get(), write_data, kDataSize)); + EXPECT_EQ(kDataSize, + WebRtc_ReadBuffer(buffer.get(), nullptr, read_data, kDataSize)); + // Passing null forces a memcpy, so `read_data` is now updated. + CheckIncrementingData(read_data, kDataSize, 0); +} + +TEST(RingBufferTest, CreateHandlesErrors) { + EXPECT_TRUE(WebRtc_CreateBuffer(0, 1) == nullptr); + EXPECT_TRUE(WebRtc_CreateBuffer(1, 0) == nullptr); + RingBuffer* buffer = WebRtc_CreateBuffer(1, 1); + EXPECT_TRUE(buffer != nullptr); + WebRtc_FreeBuffer(buffer); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c b/third_party/libwebrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c new file mode 100644 index 0000000000..a3ec24f5da --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c @@ -0,0 +1,103 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_AutoCorrToReflCoef(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +void WebRtcSpl_AutoCorrToReflCoef(const int32_t *R, int use_order, int16_t *K) +{ + int i, n; + int16_t tmp; + const int32_t *rptr; + int32_t L_num, L_den; + int16_t *acfptr, *pptr, *wptr, *p1ptr, *w1ptr, ACF[WEBRTC_SPL_MAX_LPC_ORDER], + P[WEBRTC_SPL_MAX_LPC_ORDER], W[WEBRTC_SPL_MAX_LPC_ORDER]; + + // Initialize loop and pointers. + acfptr = ACF; + rptr = R; + pptr = P; + p1ptr = &P[1]; + w1ptr = &W[1]; + wptr = w1ptr; + + // First loop; n=0. Determine shifting. + tmp = WebRtcSpl_NormW32(*R); + *acfptr = (int16_t)((*rptr++ << tmp) >> 16); + *pptr++ = *acfptr++; + + // Initialize ACF, P and W. + for (i = 1; i <= use_order; i++) + { + *acfptr = (int16_t)((*rptr++ << tmp) >> 16); + *wptr++ = *acfptr; + *pptr++ = *acfptr++; + } + + // Compute reflection coefficients. + for (n = 1; n <= use_order; n++, K++) + { + tmp = WEBRTC_SPL_ABS_W16(*p1ptr); + if (*P < tmp) + { + for (i = n; i <= use_order; i++) + *K++ = 0; + + return; + } + + // Division: WebRtcSpl_div(tmp, *P) + *K = 0; + if (tmp != 0) + { + L_num = tmp; + L_den = *P; + i = 15; + while (i--) + { + (*K) <<= 1; + L_num <<= 1; + if (L_num >= L_den) + { + L_num -= L_den; + (*K)++; + } + } + if (*p1ptr > 0) + *K = -*K; + } + + // Last iteration; don't do Schur recursion. + if (n == use_order) + return; + + // Schur recursion. + pptr = P; + wptr = w1ptr; + tmp = (int16_t)(((int32_t)*p1ptr * (int32_t)*K + 16384) >> 15); + *pptr = WebRtcSpl_AddSatW16(*pptr, tmp); + pptr++; + for (i = 1; i <= use_order - n; i++) + { + tmp = (int16_t)(((int32_t)*wptr * (int32_t)*K + 16384) >> 15); + *pptr = WebRtcSpl_AddSatW16(*(pptr + 1), tmp); + pptr++; + tmp = (int16_t)(((int32_t)*pptr * (int32_t)*K + 16384) >> 15); + *wptr = WebRtcSpl_AddSatW16(*wptr, tmp); + wptr++; + } + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/auto_correlation.c b/third_party/libwebrtc/common_audio/signal_processing/auto_correlation.c new file mode 100644 index 0000000000..1455820e8f --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/auto_correlation.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#include "rtc_base/checks.h" + +size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector, + size_t in_vector_length, + size_t order, + int32_t* result, + int* scale) { + int32_t sum = 0; + size_t i = 0, j = 0; + int16_t smax = 0; + int scaling = 0; + + RTC_DCHECK_LE(order, in_vector_length); + + // Find the maximum absolute value of the samples. + smax = WebRtcSpl_MaxAbsValueW16(in_vector, in_vector_length); + + // In order to avoid overflow when computing the sum we should scale the + // samples so that (in_vector_length * smax * smax) will not overflow. + if (smax == 0) { + scaling = 0; + } else { + // Number of bits in the sum loop. + int nbits = WebRtcSpl_GetSizeInBits((uint32_t)in_vector_length); + // Number of bits to normalize smax. + int t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax)); + + if (t > nbits) { + scaling = 0; + } else { + scaling = nbits - t; + } + } + + // Perform the actual correlation calculation. + for (i = 0; i < order + 1; i++) { + sum = 0; + /* Unroll the loop to improve performance. */ + for (j = 0; i + j + 3 < in_vector_length; j += 4) { + sum += (in_vector[j + 0] * in_vector[i + j + 0]) >> scaling; + sum += (in_vector[j + 1] * in_vector[i + j + 1]) >> scaling; + sum += (in_vector[j + 2] * in_vector[i + j + 2]) >> scaling; + sum += (in_vector[j + 3] * in_vector[i + j + 3]) >> scaling; + } + for (; j < in_vector_length - i; j++) { + sum += (in_vector[j] * in_vector[i + j]) >> scaling; + } + *result++ = sum; + } + + *scale = scaling; + return order + 1; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c b/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c new file mode 100644 index 0000000000..1c82cff50f --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse.c @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +/* Tables for data buffer indexes that are bit reversed and thus need to be + * swapped. Note that, index_7[{0, 2, 4, ...}] are for the left side of the swap + * operations, while index_7[{1, 3, 5, ...}] are for the right side of the + * operation. Same for index_8. + */ + +/* Indexes for the case of stages == 7. */ +static const int16_t index_7[112] = { + 1, 64, 2, 32, 3, 96, 4, 16, 5, 80, 6, 48, 7, 112, 9, 72, 10, 40, 11, 104, + 12, 24, 13, 88, 14, 56, 15, 120, 17, 68, 18, 36, 19, 100, 21, 84, 22, 52, + 23, 116, 25, 76, 26, 44, 27, 108, 29, 92, 30, 60, 31, 124, 33, 66, 35, 98, + 37, 82, 38, 50, 39, 114, 41, 74, 43, 106, 45, 90, 46, 58, 47, 122, 49, 70, + 51, 102, 53, 86, 55, 118, 57, 78, 59, 110, 61, 94, 63, 126, 67, 97, 69, + 81, 71, 113, 75, 105, 77, 89, 79, 121, 83, 101, 87, 117, 91, 109, 95, 125, + 103, 115, 111, 123 +}; + +/* Indexes for the case of stages == 8. */ +static const int16_t index_8[240] = { + 1, 128, 2, 64, 3, 192, 4, 32, 5, 160, 6, 96, 7, 224, 8, 16, 9, 144, 10, 80, + 11, 208, 12, 48, 13, 176, 14, 112, 15, 240, 17, 136, 18, 72, 19, 200, 20, + 40, 21, 168, 22, 104, 23, 232, 25, 152, 26, 88, 27, 216, 28, 56, 29, 184, + 30, 120, 31, 248, 33, 132, 34, 68, 35, 196, 37, 164, 38, 100, 39, 228, 41, + 148, 42, 84, 43, 212, 44, 52, 45, 180, 46, 116, 47, 244, 49, 140, 50, 76, + 51, 204, 53, 172, 54, 108, 55, 236, 57, 156, 58, 92, 59, 220, 61, 188, 62, + 124, 63, 252, 65, 130, 67, 194, 69, 162, 70, 98, 71, 226, 73, 146, 74, 82, + 75, 210, 77, 178, 78, 114, 79, 242, 81, 138, 83, 202, 85, 170, 86, 106, 87, + 234, 89, 154, 91, 218, 93, 186, 94, 122, 95, 250, 97, 134, 99, 198, 101, + 166, 103, 230, 105, 150, 107, 214, 109, 182, 110, 118, 111, 246, 113, 142, + 115, 206, 117, 174, 119, 238, 121, 158, 123, 222, 125, 190, 127, 254, 131, + 193, 133, 161, 135, 225, 137, 145, 139, 209, 141, 177, 143, 241, 147, 201, + 149, 169, 151, 233, 155, 217, 157, 185, 159, 249, 163, 197, 167, 229, 171, + 213, 173, 181, 175, 245, 179, 205, 183, 237, 187, 221, 191, 253, 199, 227, + 203, 211, 207, 243, 215, 235, 223, 251, 239, 247 +}; + +void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages) { + /* For any specific value of stages, we know exactly the indexes that are + * bit reversed. Currently (Feb. 2012) in WebRTC the only possible values of + * stages are 7 and 8, so we use tables to save unnecessary iterations and + * calculations for these two cases. + */ + if (stages == 7 || stages == 8) { + int m = 0; + int length = 112; + const int16_t* index = index_7; + + if (stages == 8) { + length = 240; + index = index_8; + } + + /* Decimation in time. Swap the elements with bit-reversed indexes. */ + for (m = 0; m < length; m += 2) { + /* We declare a int32_t* type pointer, to load both the 16-bit real + * and imaginary elements from complex_data in one instruction, reducing + * complexity. + */ + int32_t* complex_data_ptr = (int32_t*)complex_data; + int32_t temp = 0; + + temp = complex_data_ptr[index[m]]; /* Real and imaginary */ + complex_data_ptr[index[m]] = complex_data_ptr[index[m + 1]]; + complex_data_ptr[index[m + 1]] = temp; + } + } + else { + int m = 0, mr = 0, l = 0; + int n = 1 << stages; + int nn = n - 1; + + /* Decimation in time - re-order data */ + for (m = 1; m <= nn; ++m) { + int32_t* complex_data_ptr = (int32_t*)complex_data; + int32_t temp = 0; + + /* Find out indexes that are bit-reversed. */ + l = n; + do { + l >>= 1; + } while (l > nn - mr); + mr = (mr & (l - 1)) + l; + + if (mr <= m) { + continue; + } + + /* Swap the elements with bit-reversed indexes. + * This is similar to the loop in the stages == 7 or 8 cases. + */ + temp = complex_data_ptr[m]; /* Real and imaginary */ + complex_data_ptr[m] = complex_data_ptr[mr]; + complex_data_ptr[mr] = temp; + } + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_arm.S b/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_arm.S new file mode 100644 index 0000000000..be8e181aa7 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_arm.S @@ -0,0 +1,119 @@ +@ +@ Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. +@ +@ Use of this source code is governed by a BSD-style license +@ that can be found in the LICENSE file in the root of the source +@ tree. An additional intellectual property rights grant can be found +@ in the file PATENTS. All contributing project authors may +@ be found in the AUTHORS file in the root of the source tree. +@ + +@ This file contains the function WebRtcSpl_ComplexBitReverse(), optimized +@ for ARMv5 platforms. +@ Reference C code is in file complex_bit_reverse.c. Bit-exact. + +#include "rtc_base/system/asm_defines.h" + +GLOBAL_FUNCTION WebRtcSpl_ComplexBitReverse +.align 2 +DEFINE_FUNCTION WebRtcSpl_ComplexBitReverse + push {r4-r7} + + cmp r1, #7 + adr r3, index_7 @ Table pointer. + mov r4, #112 @ Number of interations. + beq PRE_LOOP_STAGES_7_OR_8 + + cmp r1, #8 + adr r3, index_8 @ Table pointer. + mov r4, #240 @ Number of interations. + beq PRE_LOOP_STAGES_7_OR_8 + + mov r3, #1 @ Initialize m. + mov r1, r3, asl r1 @ n = 1 << stages; + subs r6, r1, #1 @ nn = n - 1; + ble END + + mov r5, r0 @ &complex_data + mov r4, #0 @ ml + +LOOP_GENERIC: + rsb r12, r4, r6 @ l > nn - mr + mov r2, r1 @ n + +LOOP_SHIFT: + asr r2, #1 @ l >>= 1; + cmp r2, r12 + bgt LOOP_SHIFT + + sub r12, r2, #1 + and r4, r12, r4 + add r4, r2 @ mr = (mr & (l - 1)) + l; + cmp r4, r3 @ mr <= m ? + ble UPDATE_REGISTERS + + mov r12, r4, asl #2 + ldr r7, [r5, #4] @ complex_data[2 * m, 2 * m + 1]. + @ Offset 4 due to m incrementing from 1. + ldr r2, [r0, r12] @ complex_data[2 * mr, 2 * mr + 1]. + str r7, [r0, r12] + str r2, [r5, #4] + +UPDATE_REGISTERS: + add r3, r3, #1 + add r5, #4 + cmp r3, r1 + bne LOOP_GENERIC + + b END + +PRE_LOOP_STAGES_7_OR_8: + add r4, r3, r4, asl #1 + +LOOP_STAGES_7_OR_8: + ldrsh r2, [r3], #2 @ index[m] + ldrsh r5, [r3], #2 @ index[m + 1] + ldr r1, [r0, r2] @ complex_data[index[m], index[m] + 1] + ldr r12, [r0, r5] @ complex_data[index[m + 1], index[m + 1] + 1] + cmp r3, r4 + str r1, [r0, r5] + str r12, [r0, r2] + bne LOOP_STAGES_7_OR_8 + +END: + pop {r4-r7} + bx lr + +@ The index tables. Note the values are doubles of the actual indexes for 16-bit +@ elements, different from the generic C code. It actually provides byte offsets +@ for the indexes. + +.align 2 +index_7: @ Indexes for stages == 7. + .short 4, 256, 8, 128, 12, 384, 16, 64, 20, 320, 24, 192, 28, 448, 36, 288 + .short 40, 160, 44, 416, 48, 96, 52, 352, 56, 224, 60, 480, 68, 272, 72, 144 + .short 76, 400, 84, 336, 88, 208, 92, 464, 100, 304, 104, 176, 108, 432, 116 + .short 368, 120, 240, 124, 496, 132, 264, 140, 392, 148, 328, 152, 200, 156 + .short 456, 164, 296, 172, 424, 180, 360, 184, 232, 188, 488, 196, 280, 204 + .short 408, 212, 344, 220, 472, 228, 312, 236, 440, 244, 376, 252, 504, 268 + .short 388, 276, 324, 284, 452, 300, 420, 308, 356, 316, 484, 332, 404, 348 + .short 468, 364, 436, 380, 500, 412, 460, 444, 492 + +index_8: @ Indexes for stages == 8. + .short 4, 512, 8, 256, 12, 768, 16, 128, 20, 640, 24, 384, 28, 896, 32, 64 + .short 36, 576, 40, 320, 44, 832, 48, 192, 52, 704, 56, 448, 60, 960, 68, 544 + .short 72, 288, 76, 800, 80, 160, 84, 672, 88, 416, 92, 928, 100, 608, 104 + .short 352, 108, 864, 112, 224, 116, 736, 120, 480, 124, 992, 132, 528, 136 + .short 272, 140, 784, 148, 656, 152, 400, 156, 912, 164, 592, 168, 336, 172 + .short 848, 176, 208, 180, 720, 184, 464, 188, 976, 196, 560, 200, 304, 204 + .short 816, 212, 688, 216, 432, 220, 944, 228, 624, 232, 368, 236, 880, 244 + .short 752, 248, 496, 252, 1008, 260, 520, 268, 776, 276, 648, 280, 392, 284 + .short 904, 292, 584, 296, 328, 300, 840, 308, 712, 312, 456, 316, 968, 324 + .short 552, 332, 808, 340, 680, 344, 424, 348, 936, 356, 616, 364, 872, 372 + .short 744, 376, 488, 380, 1000, 388, 536, 396, 792, 404, 664, 412, 920, 420 + .short 600, 428, 856, 436, 728, 440, 472, 444, 984, 452, 568, 460, 824, 468 + .short 696, 476, 952, 484, 632, 492, 888, 500, 760, 508, 1016, 524, 772, 532 + .short 644, 540, 900, 548, 580, 556, 836, 564, 708, 572, 964, 588, 804, 596 + .short 676, 604, 932, 620, 868, 628, 740, 636, 996, 652, 788, 668, 916, 684 + .short 852, 692, 724, 700, 980, 716, 820, 732, 948, 748, 884, 764, 1012, 796 + .short 908, 812, 844, 828, 972, 860, 940, 892, 1004, 956, 988 diff --git a/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_mips.c b/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_mips.c new file mode 100644 index 0000000000..9007b19cf6 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/complex_bit_reverse_mips.c @@ -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 "common_audio/signal_processing/include/signal_processing_library.h" + +static int16_t coefTable_7[] = { + 4, 256, 8, 128, 12, 384, 16, 64, + 20, 320, 24, 192, 28, 448, 36, 288, + 40, 160, 44, 416, 48, 96, 52, 352, + 56, 224, 60, 480, 68, 272, 72, 144, + 76, 400, 84, 336, 88, 208, 92, 464, + 100, 304, 104, 176, 108, 432, 116, 368, + 120, 240, 124, 496, 132, 264, 140, 392, + 148, 328, 152, 200, 156, 456, 164, 296, + 172, 424, 180, 360, 184, 232, 188, 488, + 196, 280, 204, 408, 212, 344, 220, 472, + 228, 312, 236, 440, 244, 376, 252, 504, + 268, 388, 276, 324, 284, 452, 300, 420, + 308, 356, 316, 484, 332, 404, 348, 468, + 364, 436, 380, 500, 412, 460, 444, 492 +}; + +static int16_t coefTable_8[] = { + 4, 512, 8, 256, 12, 768, 16, 128, + 20, 640, 24, 384, 28, 896, 32, 64, + 36, 576, 40, 320, 44, 832, 48, 192, + 52, 704, 56, 448, 60, 960, 68, 544, + 72, 288, 76, 800, 80, 160, 84, 672, + 88, 416, 92, 928, 100, 608, 104, 352, + 108, 864, 112, 224, 116, 736, 120, 480, + 124, 992, 132, 528, 136, 272, 140, 784, + 148, 656, 152, 400, 156, 912, 164, 592, + 168, 336, 172, 848, 176, 208, 180, 720, + 184, 464, 188, 976, 196, 560, 200, 304, + 204, 816, 212, 688, 216, 432, 220, 944, + 228, 624, 232, 368, 236, 880, 244, 752, + 248, 496, 252, 1008, 260, 520, 268, 776, + 276, 648, 280, 392, 284, 904, 292, 584, + 296, 328, 300, 840, 308, 712, 312, 456, + 316, 968, 324, 552, 332, 808, 340, 680, + 344, 424, 348, 936, 356, 616, 364, 872, + 372, 744, 376, 488, 380, 1000, 388, 536, + 396, 792, 404, 664, 412, 920, 420, 600, + 428, 856, 436, 728, 440, 472, 444, 984, + 452, 568, 460, 824, 468, 696, 476, 952, + 484, 632, 492, 888, 500, 760, 508, 1016, + 524, 772, 532, 644, 540, 900, 548, 580, + 556, 836, 564, 708, 572, 964, 588, 804, + 596, 676, 604, 932, 620, 868, 628, 740, + 636, 996, 652, 788, 668, 916, 684, 852, + 692, 724, 700, 980, 716, 820, 732, 948, + 748, 884, 764, 1012, 796, 908, 812, 844, + 828, 972, 860, 940, 892, 1004, 956, 988 +}; + +void WebRtcSpl_ComplexBitReverse(int16_t frfi[], int stages) { + int l; + int16_t tr, ti; + int32_t tmp1, tmp2, tmp3, tmp4; + int32_t* ptr_i; + int32_t* ptr_j; + + if (stages == 8) { + int16_t* pcoeftable_8 = coefTable_8; + + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[l], $zero, 120 \n\t" + "1: \n\t" + "addiu %[l], %[l], -4 \n\t" + "lh %[tr], 0(%[pcoeftable_8]) \n\t" + "lh %[ti], 2(%[pcoeftable_8]) \n\t" + "lh %[tmp3], 4(%[pcoeftable_8]) \n\t" + "lh %[tmp4], 6(%[pcoeftable_8]) \n\t" + "addu %[ptr_i], %[frfi], %[tr] \n\t" + "addu %[ptr_j], %[frfi], %[ti] \n\t" + "addu %[tr], %[frfi], %[tmp3] \n\t" + "addu %[ti], %[frfi], %[tmp4] \n\t" + "ulw %[tmp1], 0(%[ptr_i]) \n\t" + "ulw %[tmp2], 0(%[ptr_j]) \n\t" + "ulw %[tmp3], 0(%[tr]) \n\t" + "ulw %[tmp4], 0(%[ti]) \n\t" + "usw %[tmp1], 0(%[ptr_j]) \n\t" + "usw %[tmp2], 0(%[ptr_i]) \n\t" + "usw %[tmp4], 0(%[tr]) \n\t" + "usw %[tmp3], 0(%[ti]) \n\t" + "lh %[tmp1], 8(%[pcoeftable_8]) \n\t" + "lh %[tmp2], 10(%[pcoeftable_8]) \n\t" + "lh %[tr], 12(%[pcoeftable_8]) \n\t" + "lh %[ti], 14(%[pcoeftable_8]) \n\t" + "addu %[ptr_i], %[frfi], %[tmp1] \n\t" + "addu %[ptr_j], %[frfi], %[tmp2] \n\t" + "addu %[tr], %[frfi], %[tr] \n\t" + "addu %[ti], %[frfi], %[ti] \n\t" + "ulw %[tmp1], 0(%[ptr_i]) \n\t" + "ulw %[tmp2], 0(%[ptr_j]) \n\t" + "ulw %[tmp3], 0(%[tr]) \n\t" + "ulw %[tmp4], 0(%[ti]) \n\t" + "usw %[tmp1], 0(%[ptr_j]) \n\t" + "usw %[tmp2], 0(%[ptr_i]) \n\t" + "usw %[tmp4], 0(%[tr]) \n\t" + "usw %[tmp3], 0(%[ti]) \n\t" + "bgtz %[l], 1b \n\t" + " addiu %[pcoeftable_8], %[pcoeftable_8], 16 \n\t" + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [ptr_i] "=&r" (ptr_i), + [ptr_j] "=&r" (ptr_j), [tr] "=&r" (tr), [l] "=&r" (l), + [tmp3] "=&r" (tmp3), [pcoeftable_8] "+r" (pcoeftable_8), + [ti] "=&r" (ti), [tmp4] "=&r" (tmp4) + : [frfi] "r" (frfi) + : "memory" + ); + } else if (stages == 7) { + int16_t* pcoeftable_7 = coefTable_7; + + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[l], $zero, 56 \n\t" + "1: \n\t" + "addiu %[l], %[l], -4 \n\t" + "lh %[tr], 0(%[pcoeftable_7]) \n\t" + "lh %[ti], 2(%[pcoeftable_7]) \n\t" + "lh %[tmp3], 4(%[pcoeftable_7]) \n\t" + "lh %[tmp4], 6(%[pcoeftable_7]) \n\t" + "addu %[ptr_i], %[frfi], %[tr] \n\t" + "addu %[ptr_j], %[frfi], %[ti] \n\t" + "addu %[tr], %[frfi], %[tmp3] \n\t" + "addu %[ti], %[frfi], %[tmp4] \n\t" + "ulw %[tmp1], 0(%[ptr_i]) \n\t" + "ulw %[tmp2], 0(%[ptr_j]) \n\t" + "ulw %[tmp3], 0(%[tr]) \n\t" + "ulw %[tmp4], 0(%[ti]) \n\t" + "usw %[tmp1], 0(%[ptr_j]) \n\t" + "usw %[tmp2], 0(%[ptr_i]) \n\t" + "usw %[tmp4], 0(%[tr]) \n\t" + "usw %[tmp3], 0(%[ti]) \n\t" + "lh %[tmp1], 8(%[pcoeftable_7]) \n\t" + "lh %[tmp2], 10(%[pcoeftable_7]) \n\t" + "lh %[tr], 12(%[pcoeftable_7]) \n\t" + "lh %[ti], 14(%[pcoeftable_7]) \n\t" + "addu %[ptr_i], %[frfi], %[tmp1] \n\t" + "addu %[ptr_j], %[frfi], %[tmp2] \n\t" + "addu %[tr], %[frfi], %[tr] \n\t" + "addu %[ti], %[frfi], %[ti] \n\t" + "ulw %[tmp1], 0(%[ptr_i]) \n\t" + "ulw %[tmp2], 0(%[ptr_j]) \n\t" + "ulw %[tmp3], 0(%[tr]) \n\t" + "ulw %[tmp4], 0(%[ti]) \n\t" + "usw %[tmp1], 0(%[ptr_j]) \n\t" + "usw %[tmp2], 0(%[ptr_i]) \n\t" + "usw %[tmp4], 0(%[tr]) \n\t" + "usw %[tmp3], 0(%[ti]) \n\t" + "bgtz %[l], 1b \n\t" + " addiu %[pcoeftable_7], %[pcoeftable_7], 16 \n\t" + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [ptr_i] "=&r" (ptr_i), + [ptr_j] "=&r" (ptr_j), [ti] "=&r" (ti), [tr] "=&r" (tr), + [l] "=&r" (l), [pcoeftable_7] "+r" (pcoeftable_7), + [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4) + : [frfi] "r" (frfi) + : "memory" + ); + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c b/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c new file mode 100644 index 0000000000..ddc9a97b59 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/complex_fft.c @@ -0,0 +1,299 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_ComplexFFT(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/complex_fft_tables.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "rtc_base/system/arch.h" + +#define CFFTSFT 14 +#define CFFTRND 1 +#define CFFTRND2 16384 + +#define CIFFTSFT 14 +#define CIFFTRND 1 + + +int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) +{ + int i, j, l, k, istep, n, m; + int16_t wr, wi; + int32_t tr32, ti32, qr32, qi32; + + /* The 1024-value is a constant given from the size of kSinTable1024[], + * and should not be changed depending on the input parameter 'stages' + */ + n = 1 << stages; + if (n > 1024) + return -1; + + l = 1; + k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change + depending on the input parameter 'stages' */ + + if (mode == 0) + { + // mode==0: Low-complexity and Low-accuracy mode + while (l < n) + { + istep = l << 1; + + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = -kSinTable1024[j]; + + for (i = m; i < n; i += istep) + { + j = i + l; + + tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; + + ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; + + qr32 = (int32_t)frfi[2 * i]; + qi32 = (int32_t)frfi[2 * i + 1]; + frfi[2 * j] = (int16_t)((qr32 - tr32) >> 1); + frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> 1); + frfi[2 * i] = (int16_t)((qr32 + tr32) >> 1); + frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> 1); + } + } + + --k; + l = istep; + + } + + } else + { + // mode==1: High-complexity and High-accuracy mode + while (l < n) + { + istep = l << 1; + + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = -kSinTable1024[j]; + +#ifdef WEBRTC_ARCH_ARM_V7 + int32_t wri = 0; + __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : + "r"((int32_t)wr), "r"((int32_t)wi)); +#endif + + for (i = m; i < n; i += istep) + { + j = i + l; + +#ifdef WEBRTC_ARCH_ARM_V7 + register int32_t frfi_r; + __asm __volatile( + "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd]," + " lsl #16\n\t" + "smlsd %[tr32], %[wri], %[frfi_r], %[cfftrnd]\n\t" + "smladx %[ti32], %[wri], %[frfi_r], %[cfftrnd]\n\t" + :[frfi_r]"=&r"(frfi_r), + [tr32]"=&r"(tr32), + [ti32]"=r"(ti32) + :[frfi_even]"r"((int32_t)frfi[2*j]), + [frfi_odd]"r"((int32_t)frfi[2*j +1]), + [wri]"r"(wri), + [cfftrnd]"r"(CFFTRND)); +#else + tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CFFTRND; + + ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CFFTRND; +#endif + + tr32 >>= 15 - CFFTSFT; + ti32 >>= 15 - CFFTSFT; + + qr32 = ((int32_t)frfi[2 * i]) * (1 << CFFTSFT); + qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CFFTSFT); + + frfi[2 * j] = (int16_t)( + (qr32 - tr32 + CFFTRND2) >> (1 + CFFTSFT)); + frfi[2 * j + 1] = (int16_t)( + (qi32 - ti32 + CFFTRND2) >> (1 + CFFTSFT)); + frfi[2 * i] = (int16_t)( + (qr32 + tr32 + CFFTRND2) >> (1 + CFFTSFT)); + frfi[2 * i + 1] = (int16_t)( + (qi32 + ti32 + CFFTRND2) >> (1 + CFFTSFT)); + } + } + + --k; + l = istep; + } + } + return 0; +} + +int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) +{ + size_t i, j, l, istep, n, m; + int k, scale, shift; + int16_t wr, wi; + int32_t tr32, ti32, qr32, qi32; + int32_t tmp32, round2; + + /* The 1024-value is a constant given from the size of kSinTable1024[], + * and should not be changed depending on the input parameter 'stages' + */ + n = ((size_t)1) << stages; + if (n > 1024) + return -1; + + scale = 0; + + l = 1; + k = 10 - 1; /* Constant for given kSinTable1024[]. Do not change + depending on the input parameter 'stages' */ + + while (l < n) + { + // variable scaling, depending upon data + shift = 0; + round2 = 8192; + + tmp32 = WebRtcSpl_MaxAbsValueW16(frfi, 2 * n); + if (tmp32 > 13573) + { + shift++; + scale++; + round2 <<= 1; + } + if (tmp32 > 27146) + { + shift++; + scale++; + round2 <<= 1; + } + + istep = l << 1; + + if (mode == 0) + { + // mode==0: Low-complexity and Low-accuracy mode + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = kSinTable1024[j]; + + for (i = m; i < n; i += istep) + { + j = i + l; + + tr32 = (wr * frfi[2 * j] - wi * frfi[2 * j + 1]) >> 15; + + ti32 = (wr * frfi[2 * j + 1] + wi * frfi[2 * j]) >> 15; + + qr32 = (int32_t)frfi[2 * i]; + qi32 = (int32_t)frfi[2 * i + 1]; + frfi[2 * j] = (int16_t)((qr32 - tr32) >> shift); + frfi[2 * j + 1] = (int16_t)((qi32 - ti32) >> shift); + frfi[2 * i] = (int16_t)((qr32 + tr32) >> shift); + frfi[2 * i + 1] = (int16_t)((qi32 + ti32) >> shift); + } + } + } else + { + // mode==1: High-complexity and High-accuracy mode + + for (m = 0; m < l; ++m) + { + j = m << k; + + /* The 256-value is a constant given as 1/4 of the size of + * kSinTable1024[], and should not be changed depending on the input + * parameter 'stages'. It will result in 0 <= j < N_SINE_WAVE/2 + */ + wr = kSinTable1024[j + 256]; + wi = kSinTable1024[j]; + +#ifdef WEBRTC_ARCH_ARM_V7 + int32_t wri = 0; + __asm __volatile("pkhbt %0, %1, %2, lsl #16" : "=r"(wri) : + "r"((int32_t)wr), "r"((int32_t)wi)); +#endif + + for (i = m; i < n; i += istep) + { + j = i + l; + +#ifdef WEBRTC_ARCH_ARM_V7 + register int32_t frfi_r; + __asm __volatile( + "pkhbt %[frfi_r], %[frfi_even], %[frfi_odd], lsl #16\n\t" + "smlsd %[tr32], %[wri], %[frfi_r], %[cifftrnd]\n\t" + "smladx %[ti32], %[wri], %[frfi_r], %[cifftrnd]\n\t" + :[frfi_r]"=&r"(frfi_r), + [tr32]"=&r"(tr32), + [ti32]"=r"(ti32) + :[frfi_even]"r"((int32_t)frfi[2*j]), + [frfi_odd]"r"((int32_t)frfi[2*j +1]), + [wri]"r"(wri), + [cifftrnd]"r"(CIFFTRND) + ); +#else + + tr32 = wr * frfi[2 * j] - wi * frfi[2 * j + 1] + CIFFTRND; + + ti32 = wr * frfi[2 * j + 1] + wi * frfi[2 * j] + CIFFTRND; +#endif + tr32 >>= 15 - CIFFTSFT; + ti32 >>= 15 - CIFFTSFT; + + qr32 = ((int32_t)frfi[2 * i]) * (1 << CIFFTSFT); + qi32 = ((int32_t)frfi[2 * i + 1]) * (1 << CIFFTSFT); + + frfi[2 * j] = (int16_t)( + (qr32 - tr32 + round2) >> (shift + CIFFTSFT)); + frfi[2 * j + 1] = (int16_t)( + (qi32 - ti32 + round2) >> (shift + CIFFTSFT)); + frfi[2 * i] = (int16_t)( + (qr32 + tr32 + round2) >> (shift + CIFFTSFT)); + frfi[2 * i + 1] = (int16_t)( + (qi32 + ti32 + round2) >> (shift + CIFFTSFT)); + } + } + + } + --k; + l = istep; + } + return scale; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/complex_fft_mips.c b/third_party/libwebrtc/common_audio/signal_processing/complex_fft_mips.c new file mode 100644 index 0000000000..27071f8b39 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/complex_fft_mips.c @@ -0,0 +1,328 @@ +/* + * 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 "common_audio/signal_processing/complex_fft_tables.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#define CFFTSFT 14 +#define CFFTRND 1 +#define CFFTRND2 16384 + +#define CIFFTSFT 14 +#define CIFFTRND 1 + +int WebRtcSpl_ComplexFFT(int16_t frfi[], int stages, int mode) { + int i = 0; + int l = 0; + int k = 0; + int istep = 0; + int n = 0; + int m = 0; + int32_t wr = 0, wi = 0; + int32_t tmp1 = 0; + int32_t tmp2 = 0; + int32_t tmp3 = 0; + int32_t tmp4 = 0; + int32_t tmp5 = 0; + int32_t tmp6 = 0; + int32_t tmp = 0; + int16_t* ptr_j = NULL; + int16_t* ptr_i = NULL; + + n = 1 << stages; + if (n > 1024) { + return -1; + } + + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + + "addiu %[k], $zero, 10 \n\t" + "addiu %[l], $zero, 1 \n\t" + "3: \n\t" + "sll %[istep], %[l], 1 \n\t" + "move %[m], $zero \n\t" + "sll %[tmp], %[l], 2 \n\t" + "move %[i], $zero \n\t" + "2: \n\t" +#if defined(MIPS_DSP_R1_LE) + "sllv %[tmp3], %[m], %[k] \n\t" + "addiu %[tmp2], %[tmp3], 512 \n\t" + "addiu %[m], %[m], 1 \n\t" + "lhx %[wi], %[tmp3](%[kSinTable1024]) \n\t" + "lhx %[wr], %[tmp2](%[kSinTable1024]) \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "sllv %[tmp3], %[m], %[k] \n\t" + "addu %[ptr_j], %[tmp3], %[kSinTable1024] \n\t" + "addiu %[ptr_i], %[ptr_j], 512 \n\t" + "addiu %[m], %[m], 1 \n\t" + "lh %[wi], 0(%[ptr_j]) \n\t" + "lh %[wr], 0(%[ptr_i]) \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "1: \n\t" + "sll %[tmp1], %[i], 2 \n\t" + "addu %[ptr_i], %[frfi], %[tmp1] \n\t" + "addu %[ptr_j], %[ptr_i], %[tmp] \n\t" + "lh %[tmp6], 0(%[ptr_i]) \n\t" + "lh %[tmp5], 2(%[ptr_i]) \n\t" + "lh %[tmp3], 0(%[ptr_j]) \n\t" + "lh %[tmp4], 2(%[ptr_j]) \n\t" + "addu %[i], %[i], %[istep] \n\t" +#if defined(MIPS_DSP_R2_LE) + "mult %[wr], %[tmp3] \n\t" + "madd %[wi], %[tmp4] \n\t" + "mult $ac1, %[wr], %[tmp4] \n\t" + "msub $ac1, %[wi], %[tmp3] \n\t" + "mflo %[tmp1] \n\t" + "mflo %[tmp2], $ac1 \n\t" + "sll %[tmp6], %[tmp6], 14 \n\t" + "sll %[tmp5], %[tmp5], 14 \n\t" + "shra_r.w %[tmp1], %[tmp1], 1 \n\t" + "shra_r.w %[tmp2], %[tmp2], 1 \n\t" + "subu %[tmp4], %[tmp6], %[tmp1] \n\t" + "addu %[tmp1], %[tmp6], %[tmp1] \n\t" + "addu %[tmp6], %[tmp5], %[tmp2] \n\t" + "subu %[tmp5], %[tmp5], %[tmp2] \n\t" + "shra_r.w %[tmp1], %[tmp1], 15 \n\t" + "shra_r.w %[tmp6], %[tmp6], 15 \n\t" + "shra_r.w %[tmp4], %[tmp4], 15 \n\t" + "shra_r.w %[tmp5], %[tmp5], 15 \n\t" +#else // #if defined(MIPS_DSP_R2_LE) + "mul %[tmp2], %[wr], %[tmp4] \n\t" + "mul %[tmp1], %[wr], %[tmp3] \n\t" + "mul %[tmp4], %[wi], %[tmp4] \n\t" + "mul %[tmp3], %[wi], %[tmp3] \n\t" + "sll %[tmp6], %[tmp6], 14 \n\t" + "sll %[tmp5], %[tmp5], 14 \n\t" + "addiu %[tmp6], %[tmp6], 16384 \n\t" + "addiu %[tmp5], %[tmp5], 16384 \n\t" + "addu %[tmp1], %[tmp1], %[tmp4] \n\t" + "subu %[tmp2], %[tmp2], %[tmp3] \n\t" + "addiu %[tmp1], %[tmp1], 1 \n\t" + "addiu %[tmp2], %[tmp2], 1 \n\t" + "sra %[tmp1], %[tmp1], 1 \n\t" + "sra %[tmp2], %[tmp2], 1 \n\t" + "subu %[tmp4], %[tmp6], %[tmp1] \n\t" + "addu %[tmp1], %[tmp6], %[tmp1] \n\t" + "addu %[tmp6], %[tmp5], %[tmp2] \n\t" + "subu %[tmp5], %[tmp5], %[tmp2] \n\t" + "sra %[tmp4], %[tmp4], 15 \n\t" + "sra %[tmp1], %[tmp1], 15 \n\t" + "sra %[tmp6], %[tmp6], 15 \n\t" + "sra %[tmp5], %[tmp5], 15 \n\t" +#endif // #if defined(MIPS_DSP_R2_LE) + "sh %[tmp1], 0(%[ptr_i]) \n\t" + "sh %[tmp6], 2(%[ptr_i]) \n\t" + "sh %[tmp4], 0(%[ptr_j]) \n\t" + "blt %[i], %[n], 1b \n\t" + " sh %[tmp5], 2(%[ptr_j]) \n\t" + "blt %[m], %[l], 2b \n\t" + " addu %[i], $zero, %[m] \n\t" + "move %[l], %[istep] \n\t" + "blt %[l], %[n], 3b \n\t" + " addiu %[k], %[k], -1 \n\t" + + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), + [tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6), + [ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [wi] "=&r" (wi), [wr] "=&r" (wr), + [m] "=&r" (m), [istep] "=&r" (istep), [l] "=&r" (l), [k] "=&r" (k), + [ptr_j] "=&r" (ptr_j), [tmp] "=&r" (tmp) + : [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024) + : "hi", "lo", "memory" +#if defined(MIPS_DSP_R2_LE) + , "$ac1hi", "$ac1lo" +#endif // #if defined(MIPS_DSP_R2_LE) + ); + + return 0; +} + +int WebRtcSpl_ComplexIFFT(int16_t frfi[], int stages, int mode) { + int i = 0, l = 0, k = 0; + int istep = 0, n = 0, m = 0; + int scale = 0, shift = 0; + int32_t wr = 0, wi = 0; + int32_t tmp1 = 0, tmp2 = 0, tmp3 = 0, tmp4 = 0; + int32_t tmp5 = 0, tmp6 = 0, tmp = 0, tempMax = 0, round2 = 0; + int16_t* ptr_j = NULL; + int16_t* ptr_i = NULL; + + n = 1 << stages; + if (n > 1024) { + return -1; + } + + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + + "addiu %[k], $zero, 10 \n\t" + "addiu %[l], $zero, 1 \n\t" + "move %[scale], $zero \n\t" + "3: \n\t" + "addiu %[shift], $zero, 14 \n\t" + "addiu %[round2], $zero, 8192 \n\t" + "move %[ptr_i], %[frfi] \n\t" + "move %[tempMax], $zero \n\t" + "addu %[i], %[n], %[n] \n\t" + "5: \n\t" + "lh %[tmp1], 0(%[ptr_i]) \n\t" + "lh %[tmp2], 2(%[ptr_i]) \n\t" + "lh %[tmp3], 4(%[ptr_i]) \n\t" + "lh %[tmp4], 6(%[ptr_i]) \n\t" +#if defined(MIPS_DSP_R1_LE) + "absq_s.w %[tmp1], %[tmp1] \n\t" + "absq_s.w %[tmp2], %[tmp2] \n\t" + "absq_s.w %[tmp3], %[tmp3] \n\t" + "absq_s.w %[tmp4], %[tmp4] \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "slt %[tmp5], %[tmp1], $zero \n\t" + "subu %[tmp6], $zero, %[tmp1] \n\t" + "movn %[tmp1], %[tmp6], %[tmp5] \n\t" + "slt %[tmp5], %[tmp2], $zero \n\t" + "subu %[tmp6], $zero, %[tmp2] \n\t" + "movn %[tmp2], %[tmp6], %[tmp5] \n\t" + "slt %[tmp5], %[tmp3], $zero \n\t" + "subu %[tmp6], $zero, %[tmp3] \n\t" + "movn %[tmp3], %[tmp6], %[tmp5] \n\t" + "slt %[tmp5], %[tmp4], $zero \n\t" + "subu %[tmp6], $zero, %[tmp4] \n\t" + "movn %[tmp4], %[tmp6], %[tmp5] \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "slt %[tmp5], %[tempMax], %[tmp1] \n\t" + "movn %[tempMax], %[tmp1], %[tmp5] \n\t" + "addiu %[i], %[i], -4 \n\t" + "slt %[tmp5], %[tempMax], %[tmp2] \n\t" + "movn %[tempMax], %[tmp2], %[tmp5] \n\t" + "slt %[tmp5], %[tempMax], %[tmp3] \n\t" + "movn %[tempMax], %[tmp3], %[tmp5] \n\t" + "slt %[tmp5], %[tempMax], %[tmp4] \n\t" + "movn %[tempMax], %[tmp4], %[tmp5] \n\t" + "bgtz %[i], 5b \n\t" + " addiu %[ptr_i], %[ptr_i], 8 \n\t" + "addiu %[tmp1], $zero, 13573 \n\t" + "addiu %[tmp2], $zero, 27146 \n\t" +#if !defined(MIPS32_R2_LE) + "sll %[tempMax], %[tempMax], 16 \n\t" + "sra %[tempMax], %[tempMax], 16 \n\t" +#else // #if !defined(MIPS32_R2_LE) + "seh %[tempMax] \n\t" +#endif // #if !defined(MIPS32_R2_LE) + "slt %[tmp1], %[tmp1], %[tempMax] \n\t" + "slt %[tmp2], %[tmp2], %[tempMax] \n\t" + "addu %[tmp1], %[tmp1], %[tmp2] \n\t" + "addu %[shift], %[shift], %[tmp1] \n\t" + "addu %[scale], %[scale], %[tmp1] \n\t" + "sllv %[round2], %[round2], %[tmp1] \n\t" + "sll %[istep], %[l], 1 \n\t" + "move %[m], $zero \n\t" + "sll %[tmp], %[l], 2 \n\t" + "2: \n\t" +#if defined(MIPS_DSP_R1_LE) + "sllv %[tmp3], %[m], %[k] \n\t" + "addiu %[tmp2], %[tmp3], 512 \n\t" + "addiu %[m], %[m], 1 \n\t" + "lhx %[wi], %[tmp3](%[kSinTable1024]) \n\t" + "lhx %[wr], %[tmp2](%[kSinTable1024]) \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "sllv %[tmp3], %[m], %[k] \n\t" + "addu %[ptr_j], %[tmp3], %[kSinTable1024] \n\t" + "addiu %[ptr_i], %[ptr_j], 512 \n\t" + "addiu %[m], %[m], 1 \n\t" + "lh %[wi], 0(%[ptr_j]) \n\t" + "lh %[wr], 0(%[ptr_i]) \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "1: \n\t" + "sll %[tmp1], %[i], 2 \n\t" + "addu %[ptr_i], %[frfi], %[tmp1] \n\t" + "addu %[ptr_j], %[ptr_i], %[tmp] \n\t" + "lh %[tmp3], 0(%[ptr_j]) \n\t" + "lh %[tmp4], 2(%[ptr_j]) \n\t" + "lh %[tmp6], 0(%[ptr_i]) \n\t" + "lh %[tmp5], 2(%[ptr_i]) \n\t" + "addu %[i], %[i], %[istep] \n\t" +#if defined(MIPS_DSP_R2_LE) + "mult %[wr], %[tmp3] \n\t" + "msub %[wi], %[tmp4] \n\t" + "mult $ac1, %[wr], %[tmp4] \n\t" + "madd $ac1, %[wi], %[tmp3] \n\t" + "mflo %[tmp1] \n\t" + "mflo %[tmp2], $ac1 \n\t" + "sll %[tmp6], %[tmp6], 14 \n\t" + "sll %[tmp5], %[tmp5], 14 \n\t" + "shra_r.w %[tmp1], %[tmp1], 1 \n\t" + "shra_r.w %[tmp2], %[tmp2], 1 \n\t" + "addu %[tmp6], %[tmp6], %[round2] \n\t" + "addu %[tmp5], %[tmp5], %[round2] \n\t" + "subu %[tmp4], %[tmp6], %[tmp1] \n\t" + "addu %[tmp1], %[tmp6], %[tmp1] \n\t" + "addu %[tmp6], %[tmp5], %[tmp2] \n\t" + "subu %[tmp5], %[tmp5], %[tmp2] \n\t" + "srav %[tmp4], %[tmp4], %[shift] \n\t" + "srav %[tmp1], %[tmp1], %[shift] \n\t" + "srav %[tmp6], %[tmp6], %[shift] \n\t" + "srav %[tmp5], %[tmp5], %[shift] \n\t" +#else // #if defined(MIPS_DSP_R2_LE) + "mul %[tmp1], %[wr], %[tmp3] \n\t" + "mul %[tmp2], %[wr], %[tmp4] \n\t" + "mul %[tmp4], %[wi], %[tmp4] \n\t" + "mul %[tmp3], %[wi], %[tmp3] \n\t" + "sll %[tmp6], %[tmp6], 14 \n\t" + "sll %[tmp5], %[tmp5], 14 \n\t" + "sub %[tmp1], %[tmp1], %[tmp4] \n\t" + "addu %[tmp2], %[tmp2], %[tmp3] \n\t" + "addiu %[tmp1], %[tmp1], 1 \n\t" + "addiu %[tmp2], %[tmp2], 1 \n\t" + "sra %[tmp2], %[tmp2], 1 \n\t" + "sra %[tmp1], %[tmp1], 1 \n\t" + "addu %[tmp6], %[tmp6], %[round2] \n\t" + "addu %[tmp5], %[tmp5], %[round2] \n\t" + "subu %[tmp4], %[tmp6], %[tmp1] \n\t" + "addu %[tmp1], %[tmp6], %[tmp1] \n\t" + "addu %[tmp6], %[tmp5], %[tmp2] \n\t" + "subu %[tmp5], %[tmp5], %[tmp2] \n\t" + "sra %[tmp4], %[tmp4], %[shift] \n\t" + "sra %[tmp1], %[tmp1], %[shift] \n\t" + "sra %[tmp6], %[tmp6], %[shift] \n\t" + "sra %[tmp5], %[tmp5], %[shift] \n\t" +#endif // #if defined(MIPS_DSP_R2_LE) + "sh %[tmp1], 0(%[ptr_i]) \n\t" + "sh %[tmp6], 2(%[ptr_i]) \n\t" + "sh %[tmp4], 0(%[ptr_j]) \n\t" + "blt %[i], %[n], 1b \n\t" + " sh %[tmp5], 2(%[ptr_j]) \n\t" + "blt %[m], %[l], 2b \n\t" + " addu %[i], $zero, %[m] \n\t" + "move %[l], %[istep] \n\t" + "blt %[l], %[n], 3b \n\t" + " addiu %[k], %[k], -1 \n\t" + + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), + [tmp4] "=&r" (tmp4), [tmp5] "=&r" (tmp5), [tmp6] "=&r" (tmp6), + [ptr_i] "=&r" (ptr_i), [i] "=&r" (i), [m] "=&r" (m), [tmp] "=&r" (tmp), + [istep] "=&r" (istep), [wi] "=&r" (wi), [wr] "=&r" (wr), [l] "=&r" (l), + [k] "=&r" (k), [round2] "=&r" (round2), [ptr_j] "=&r" (ptr_j), + [shift] "=&r" (shift), [scale] "=&r" (scale), [tempMax] "=&r" (tempMax) + : [n] "r" (n), [frfi] "r" (frfi), [kSinTable1024] "r" (kSinTable1024) + : "hi", "lo", "memory" +#if defined(MIPS_DSP_R2_LE) + , "$ac1hi", "$ac1lo" +#endif // #if defined(MIPS_DSP_R2_LE) + ); + + return scale; + +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/complex_fft_tables.h b/third_party/libwebrtc/common_audio/signal_processing/complex_fft_tables.h new file mode 100644 index 0000000000..90fac072d2 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/complex_fft_tables.h @@ -0,0 +1,132 @@ +/* + * 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 COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ + +#include <stdint.h> + +static const int16_t kSinTable1024[] = { + 0, 201, 402, 603, 804, 1005, 1206, 1406, 1607, + 1808, 2009, 2209, 2410, 2610, 2811, 3011, 3211, 3411, + 3611, 3811, 4011, 4210, 4409, 4608, 4807, 5006, 5205, + 5403, 5601, 5799, 5997, 6195, 6392, 6589, 6786, 6982, + 7179, 7375, 7571, 7766, 7961, 8156, 8351, 8545, 8739, + 8932, 9126, 9319, 9511, 9703, 9895, 10087, 10278, 10469, + 10659, 10849, 11038, 11227, 11416, 11604, 11792, 11980, 12166, + 12353, 12539, 12724, 12909, 13094, 13278, 13462, 13645, 13827, + 14009, 14191, 14372, 14552, 14732, 14911, 15090, 15268, 15446, + 15623, 15799, 15975, 16150, 16325, 16499, 16672, 16845, 17017, + 17189, 17360, 17530, 17699, 17868, 18036, 18204, 18371, 18537, + 18702, 18867, 19031, 19194, 19357, 19519, 19680, 19840, 20000, + 20159, 20317, 20474, 20631, 20787, 20942, 21096, 21249, 21402, + 21554, 21705, 21855, 22004, 22153, 22301, 22448, 22594, 22739, + 22883, 23027, 23169, 23311, 23452, 23592, 23731, 23869, 24006, + 24143, 24278, 24413, 24546, 24679, 24811, 24942, 25072, 25201, + 25329, 25456, 25582, 25707, 25831, 25954, 26077, 26198, 26318, + 26437, 26556, 26673, 26789, 26905, 27019, 27132, 27244, 27355, + 27466, 27575, 27683, 27790, 27896, 28001, 28105, 28208, 28309, + 28410, 28510, 28608, 28706, 28802, 28897, 28992, 29085, 29177, + 29268, 29358, 29446, 29534, 29621, 29706, 29790, 29873, 29955, + 30036, 30116, 30195, 30272, 30349, 30424, 30498, 30571, 30643, + 30713, 30783, 30851, 30918, 30984, 31049, 31113, 31175, 31236, + 31297, 31356, 31413, 31470, 31525, 31580, 31633, 31684, 31735, + 31785, 31833, 31880, 31926, 31970, 32014, 32056, 32097, 32137, + 32176, 32213, 32249, 32284, 32318, 32350, 32382, 32412, 32441, + 32468, 32495, 32520, 32544, 32567, 32588, 32609, 32628, 32646, + 32662, 32678, 32692, 32705, 32717, 32727, 32736, 32744, 32751, + 32757, 32761, 32764, 32766, 32767, 32766, 32764, 32761, 32757, + 32751, 32744, 32736, 32727, 32717, 32705, 32692, 32678, 32662, + 32646, 32628, 32609, 32588, 32567, 32544, 32520, 32495, 32468, + 32441, 32412, 32382, 32350, 32318, 32284, 32249, 32213, 32176, + 32137, 32097, 32056, 32014, 31970, 31926, 31880, 31833, 31785, + 31735, 31684, 31633, 31580, 31525, 31470, 31413, 31356, 31297, + 31236, 31175, 31113, 31049, 30984, 30918, 30851, 30783, 30713, + 30643, 30571, 30498, 30424, 30349, 30272, 30195, 30116, 30036, + 29955, 29873, 29790, 29706, 29621, 29534, 29446, 29358, 29268, + 29177, 29085, 28992, 28897, 28802, 28706, 28608, 28510, 28410, + 28309, 28208, 28105, 28001, 27896, 27790, 27683, 27575, 27466, + 27355, 27244, 27132, 27019, 26905, 26789, 26673, 26556, 26437, + 26318, 26198, 26077, 25954, 25831, 25707, 25582, 25456, 25329, + 25201, 25072, 24942, 24811, 24679, 24546, 24413, 24278, 24143, + 24006, 23869, 23731, 23592, 23452, 23311, 23169, 23027, 22883, + 22739, 22594, 22448, 22301, 22153, 22004, 21855, 21705, 21554, + 21402, 21249, 21096, 20942, 20787, 20631, 20474, 20317, 20159, + 20000, 19840, 19680, 19519, 19357, 19194, 19031, 18867, 18702, + 18537, 18371, 18204, 18036, 17868, 17699, 17530, 17360, 17189, + 17017, 16845, 16672, 16499, 16325, 16150, 15975, 15799, 15623, + 15446, 15268, 15090, 14911, 14732, 14552, 14372, 14191, 14009, + 13827, 13645, 13462, 13278, 13094, 12909, 12724, 12539, 12353, + 12166, 11980, 11792, 11604, 11416, 11227, 11038, 10849, 10659, + 10469, 10278, 10087, 9895, 9703, 9511, 9319, 9126, 8932, + 8739, 8545, 8351, 8156, 7961, 7766, 7571, 7375, 7179, + 6982, 6786, 6589, 6392, 6195, 5997, 5799, 5601, 5403, + 5205, 5006, 4807, 4608, 4409, 4210, 4011, 3811, 3611, + 3411, 3211, 3011, 2811, 2610, 2410, 2209, 2009, 1808, + 1607, 1406, 1206, 1005, 804, 603, 402, 201, 0, + -201, -402, -603, -804, -1005, -1206, -1406, -1607, -1808, + -2009, -2209, -2410, -2610, -2811, -3011, -3211, -3411, -3611, + -3811, -4011, -4210, -4409, -4608, -4807, -5006, -5205, -5403, + -5601, -5799, -5997, -6195, -6392, -6589, -6786, -6982, -7179, + -7375, -7571, -7766, -7961, -8156, -8351, -8545, -8739, -8932, + -9126, -9319, -9511, -9703, -9895, -10087, -10278, -10469, -10659, + -10849, -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353, + -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827, -14009, + -14191, -14372, -14552, -14732, -14911, -15090, -15268, -15446, -15623, + -15799, -15975, -16150, -16325, -16499, -16672, -16845, -17017, -17189, + -17360, -17530, -17699, -17868, -18036, -18204, -18371, -18537, -18702, + -18867, -19031, -19194, -19357, -19519, -19680, -19840, -20000, -20159, + -20317, -20474, -20631, -20787, -20942, -21096, -21249, -21402, -21554, + -21705, -21855, -22004, -22153, -22301, -22448, -22594, -22739, -22883, + -23027, -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143, + -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201, -25329, + -25456, -25582, -25707, -25831, -25954, -26077, -26198, -26318, -26437, + -26556, -26673, -26789, -26905, -27019, -27132, -27244, -27355, -27466, + -27575, -27683, -27790, -27896, -28001, -28105, -28208, -28309, -28410, + -28510, -28608, -28706, -28802, -28897, -28992, -29085, -29177, -29268, + -29358, -29446, -29534, -29621, -29706, -29790, -29873, -29955, -30036, + -30116, -30195, -30272, -30349, -30424, -30498, -30571, -30643, -30713, + -30783, -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297, + -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735, -31785, + -31833, -31880, -31926, -31970, -32014, -32056, -32097, -32137, -32176, + -32213, -32249, -32284, -32318, -32350, -32382, -32412, -32441, -32468, + -32495, -32520, -32544, -32567, -32588, -32609, -32628, -32646, -32662, + -32678, -32692, -32705, -32717, -32727, -32736, -32744, -32751, -32757, + -32761, -32764, -32766, -32767, -32766, -32764, -32761, -32757, -32751, + -32744, -32736, -32727, -32717, -32705, -32692, -32678, -32662, -32646, + -32628, -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441, + -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176, -32137, + -32097, -32056, -32014, -31970, -31926, -31880, -31833, -31785, -31735, + -31684, -31633, -31580, -31525, -31470, -31413, -31356, -31297, -31236, + -31175, -31113, -31049, -30984, -30918, -30851, -30783, -30713, -30643, + -30571, -30498, -30424, -30349, -30272, -30195, -30116, -30036, -29955, + -29873, -29790, -29706, -29621, -29534, -29446, -29358, -29268, -29177, + -29085, -28992, -28897, -28802, -28706, -28608, -28510, -28410, -28309, + -28208, -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355, + -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437, -26318, + -26198, -26077, -25954, -25831, -25707, -25582, -25456, -25329, -25201, + -25072, -24942, -24811, -24679, -24546, -24413, -24278, -24143, -24006, + -23869, -23731, -23592, -23452, -23311, -23169, -23027, -22883, -22739, + -22594, -22448, -22301, -22153, -22004, -21855, -21705, -21554, -21402, + -21249, -21096, -20942, -20787, -20631, -20474, -20317, -20159, -20000, + -19840, -19680, -19519, -19357, -19194, -19031, -18867, -18702, -18537, + -18371, -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017, + -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623, -15446, + -15268, -15090, -14911, -14732, -14552, -14372, -14191, -14009, -13827, + -13645, -13462, -13278, -13094, -12909, -12724, -12539, -12353, -12166, + -11980, -11792, -11604, -11416, -11227, -11038, -10849, -10659, -10469, + -10278, -10087, -9895, -9703, -9511, -9319, -9126, -8932, -8739, + -8545, -8351, -8156, -7961, -7766, -7571, -7375, -7179, -6982, + -6786, -6589, -6392, -6195, -5997, -5799, -5601, -5403, -5205, + -5006, -4807, -4608, -4409, -4210, -4011, -3811, -3611, -3411, + -3211, -3011, -2811, -2610, -2410, -2209, -2009, -1808, -1607, + -1406, -1206, -1005, -804, -603, -402, -201}; + +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_ diff --git a/third_party/libwebrtc/common_audio/signal_processing/copy_set_operations.c b/third_party/libwebrtc/common_audio/signal_processing/copy_set_operations.c new file mode 100644 index 0000000000..ae709d40f0 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/copy_set_operations.c @@ -0,0 +1,82 @@ +/* + * 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. + */ + + +/* + * This file contains the implementation of functions + * WebRtcSpl_MemSetW16() + * WebRtcSpl_MemSetW32() + * WebRtcSpl_MemCpyReversedOrder() + * WebRtcSpl_CopyFromEndW16() + * WebRtcSpl_ZerosArrayW16() + * WebRtcSpl_ZerosArrayW32() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include <string.h> +#include "common_audio/signal_processing/include/signal_processing_library.h" + + +void WebRtcSpl_MemSetW16(int16_t *ptr, int16_t set_value, size_t length) +{ + size_t j; + int16_t *arrptr = ptr; + + for (j = length; j > 0; j--) + { + *arrptr++ = set_value; + } +} + +void WebRtcSpl_MemSetW32(int32_t *ptr, int32_t set_value, size_t length) +{ + size_t j; + int32_t *arrptr = ptr; + + for (j = length; j > 0; j--) + { + *arrptr++ = set_value; + } +} + +void WebRtcSpl_MemCpyReversedOrder(int16_t* dest, + int16_t* source, + size_t length) +{ + size_t j; + int16_t* destPtr = dest; + int16_t* sourcePtr = source; + + for (j = 0; j < length; j++) + { + *destPtr-- = *sourcePtr++; + } +} + +void WebRtcSpl_CopyFromEndW16(const int16_t *vector_in, + size_t length, + size_t samples, + int16_t *vector_out) +{ + // Copy the last <samples> of the input vector to vector_out + WEBRTC_SPL_MEMCPY_W16(vector_out, &vector_in[length - samples], samples); +} + +void WebRtcSpl_ZerosArrayW16(int16_t *vector, size_t length) +{ + WebRtcSpl_MemSetW16(vector, 0, length); +} + +void WebRtcSpl_ZerosArrayW32(int32_t *vector, size_t length) +{ + WebRtcSpl_MemSetW32(vector, 0, length); +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/cross_correlation.c b/third_party/libwebrtc/common_audio/signal_processing/cross_correlation.c new file mode 100644 index 0000000000..c6267c92c2 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/cross_correlation.c @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +/* C version of WebRtcSpl_CrossCorrelation() for generic platforms. */ +void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation, + const int16_t* seq1, + const int16_t* seq2, + size_t dim_seq, + size_t dim_cross_correlation, + int right_shifts, + int step_seq2) { + size_t i = 0, j = 0; + + for (i = 0; i < dim_cross_correlation; i++) { + int32_t corr = 0; + for (j = 0; j < dim_seq; j++) + corr += (seq1[j] * seq2[j]) >> right_shifts; + seq2 += step_seq2; + *cross_correlation++ = corr; + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/cross_correlation_mips.c b/third_party/libwebrtc/common_audio/signal_processing/cross_correlation_mips.c new file mode 100644 index 0000000000..c395101900 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/cross_correlation_mips.c @@ -0,0 +1,104 @@ +/* + * 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 "common_audio/signal_processing/include/signal_processing_library.h" + +void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation, + const int16_t* seq1, + const int16_t* seq2, + size_t dim_seq, + size_t dim_cross_correlation, + int right_shifts, + int step_seq2) { + + int32_t t0 = 0, t1 = 0, t2 = 0, t3 = 0, sum = 0; + int16_t *pseq2 = NULL; + int16_t *pseq1 = NULL; + int16_t *pseq1_0 = (int16_t*)&seq1[0]; + int16_t *pseq2_0 = (int16_t*)&seq2[0]; + int k = 0; + + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "sll %[step_seq2], %[step_seq2], 1 \n\t" + "andi %[t0], %[dim_seq], 1 \n\t" + "bgtz %[t0], 3f \n\t" + " nop \n\t" + "1: \n\t" + "move %[pseq1], %[pseq1_0] \n\t" + "move %[pseq2], %[pseq2_0] \n\t" + "sra %[k], %[dim_seq], 1 \n\t" + "addiu %[dim_cc], %[dim_cc], -1 \n\t" + "xor %[sum], %[sum], %[sum] \n\t" + "2: \n\t" + "lh %[t0], 0(%[pseq1]) \n\t" + "lh %[t1], 0(%[pseq2]) \n\t" + "lh %[t2], 2(%[pseq1]) \n\t" + "lh %[t3], 2(%[pseq2]) \n\t" + "mul %[t0], %[t0], %[t1] \n\t" + "addiu %[k], %[k], -1 \n\t" + "mul %[t2], %[t2], %[t3] \n\t" + "addiu %[pseq1], %[pseq1], 4 \n\t" + "addiu %[pseq2], %[pseq2], 4 \n\t" + "srav %[t0], %[t0], %[right_shifts] \n\t" + "addu %[sum], %[sum], %[t0] \n\t" + "srav %[t2], %[t2], %[right_shifts] \n\t" + "bgtz %[k], 2b \n\t" + " addu %[sum], %[sum], %[t2] \n\t" + "addu %[pseq2_0], %[pseq2_0], %[step_seq2] \n\t" + "sw %[sum], 0(%[cc]) \n\t" + "bgtz %[dim_cc], 1b \n\t" + " addiu %[cc], %[cc], 4 \n\t" + "b 6f \n\t" + " nop \n\t" + "3: \n\t" + "move %[pseq1], %[pseq1_0] \n\t" + "move %[pseq2], %[pseq2_0] \n\t" + "sra %[k], %[dim_seq], 1 \n\t" + "addiu %[dim_cc], %[dim_cc], -1 \n\t" + "beqz %[k], 5f \n\t" + " xor %[sum], %[sum], %[sum] \n\t" + "4: \n\t" + "lh %[t0], 0(%[pseq1]) \n\t" + "lh %[t1], 0(%[pseq2]) \n\t" + "lh %[t2], 2(%[pseq1]) \n\t" + "lh %[t3], 2(%[pseq2]) \n\t" + "mul %[t0], %[t0], %[t1] \n\t" + "addiu %[k], %[k], -1 \n\t" + "mul %[t2], %[t2], %[t3] \n\t" + "addiu %[pseq1], %[pseq1], 4 \n\t" + "addiu %[pseq2], %[pseq2], 4 \n\t" + "srav %[t0], %[t0], %[right_shifts] \n\t" + "addu %[sum], %[sum], %[t0] \n\t" + "srav %[t2], %[t2], %[right_shifts] \n\t" + "bgtz %[k], 4b \n\t" + " addu %[sum], %[sum], %[t2] \n\t" + "5: \n\t" + "lh %[t0], 0(%[pseq1]) \n\t" + "lh %[t1], 0(%[pseq2]) \n\t" + "mul %[t0], %[t0], %[t1] \n\t" + "srav %[t0], %[t0], %[right_shifts] \n\t" + "addu %[sum], %[sum], %[t0] \n\t" + "addu %[pseq2_0], %[pseq2_0], %[step_seq2] \n\t" + "sw %[sum], 0(%[cc]) \n\t" + "bgtz %[dim_cc], 3b \n\t" + " addiu %[cc], %[cc], 4 \n\t" + "6: \n\t" + ".set pop \n\t" + : [step_seq2] "+r" (step_seq2), [t0] "=&r" (t0), [t1] "=&r" (t1), + [t2] "=&r" (t2), [t3] "=&r" (t3), [pseq1] "=&r" (pseq1), + [pseq2] "=&r" (pseq2), [pseq1_0] "+r" (pseq1_0), [pseq2_0] "+r" (pseq2_0), + [k] "=&r" (k), [dim_cc] "+r" (dim_cross_correlation), [sum] "=&r" (sum), + [cc] "+r" (cross_correlation) + : [dim_seq] "r" (dim_seq), [right_shifts] "r" (right_shifts) + : "hi", "lo", "memory" + ); +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/cross_correlation_neon.c b/third_party/libwebrtc/common_audio/signal_processing/cross_correlation_neon.c new file mode 100644 index 0000000000..f2afbdf9f5 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/cross_correlation_neon.c @@ -0,0 +1,88 @@ +/* + * 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 "common_audio/signal_processing/include/signal_processing_library.h" +#include "rtc_base/system/arch.h" + +#include <arm_neon.h> + +static inline void DotProductWithScaleNeon(int32_t* cross_correlation, + const int16_t* vector1, + const int16_t* vector2, + size_t length, + int scaling) { + size_t i = 0; + size_t len1 = length >> 3; + size_t len2 = length & 7; + int64x2_t sum0 = vdupq_n_s64(0); + int64x2_t sum1 = vdupq_n_s64(0); + + for (i = len1; i > 0; i -= 1) { + int16x8_t seq1_16x8 = vld1q_s16(vector1); + int16x8_t seq2_16x8 = vld1q_s16(vector2); +#if defined(WEBRTC_ARCH_ARM64) + int32x4_t tmp0 = vmull_s16(vget_low_s16(seq1_16x8), + vget_low_s16(seq2_16x8)); + int32x4_t tmp1 = vmull_high_s16(seq1_16x8, seq2_16x8); +#else + int32x4_t tmp0 = vmull_s16(vget_low_s16(seq1_16x8), + vget_low_s16(seq2_16x8)); + int32x4_t tmp1 = vmull_s16(vget_high_s16(seq1_16x8), + vget_high_s16(seq2_16x8)); +#endif + sum0 = vpadalq_s32(sum0, tmp0); + sum1 = vpadalq_s32(sum1, tmp1); + vector1 += 8; + vector2 += 8; + } + + // Calculate the rest of the samples. + int64_t sum_res = 0; + for (i = len2; i > 0; i -= 1) { + sum_res += WEBRTC_SPL_MUL_16_16(*vector1, *vector2); + vector1++; + vector2++; + } + + sum0 = vaddq_s64(sum0, sum1); +#if defined(WEBRTC_ARCH_ARM64) + int64_t sum2 = vaddvq_s64(sum0); + *cross_correlation = (int32_t)((sum2 + sum_res) >> scaling); +#else + int64x1_t shift = vdup_n_s64(-scaling); + int64x1_t sum2 = vadd_s64(vget_low_s64(sum0), vget_high_s64(sum0)); + sum2 = vadd_s64(sum2, vdup_n_s64(sum_res)); + sum2 = vshl_s64(sum2, shift); + vst1_lane_s32(cross_correlation, vreinterpret_s32_s64(sum2), 0); +#endif +} + +/* NEON version of WebRtcSpl_CrossCorrelation() for ARM32/64 platforms. */ +void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation, + const int16_t* seq1, + const int16_t* seq2, + size_t dim_seq, + size_t dim_cross_correlation, + int right_shifts, + int step_seq2) { + size_t i = 0; + + for (i = 0; i < dim_cross_correlation; i++) { + const int16_t* seq1_ptr = seq1; + const int16_t* seq2_ptr = seq2 + (step_seq2 * i); + + DotProductWithScaleNeon(cross_correlation, + seq1_ptr, + seq2_ptr, + dim_seq, + right_shifts); + cross_correlation++; + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/division_operations.c b/third_party/libwebrtc/common_audio/signal_processing/division_operations.c new file mode 100644 index 0000000000..4764ddfccd --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/division_operations.c @@ -0,0 +1,140 @@ +/* + * 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. + */ + + +/* + * This file contains implementations of the divisions + * WebRtcSpl_DivU32U16() + * WebRtcSpl_DivW32W16() + * WebRtcSpl_DivW32W16ResW16() + * WebRtcSpl_DivResultInQ31() + * WebRtcSpl_DivW32HiLow() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "rtc_base/sanitizer.h" + +uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den) +{ + // Guard against division with 0 + if (den != 0) + { + return (uint32_t)(num / den); + } else + { + return (uint32_t)0xFFFFFFFF; + } +} + +int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den) +{ + // Guard against division with 0 + if (den != 0) + { + return (int32_t)(num / den); + } else + { + return (int32_t)0x7FFFFFFF; + } +} + +int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den) +{ + // Guard against division with 0 + if (den != 0) + { + return (int16_t)(num / den); + } else + { + return (int16_t)0x7FFF; + } +} + +int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den) +{ + int32_t L_num = num; + int32_t L_den = den; + int32_t div = 0; + int k = 31; + int change_sign = 0; + + if (num == 0) + return 0; + + if (num < 0) + { + change_sign++; + L_num = -num; + } + if (den < 0) + { + change_sign++; + L_den = -den; + } + while (k--) + { + div <<= 1; + L_num <<= 1; + if (L_num >= L_den) + { + L_num -= L_den; + div++; + } + } + if (change_sign == 1) + { + div = -div; + } + return div; +} + +int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low) +{ + int16_t approx, tmp_hi, tmp_low, num_hi, num_low; + int32_t tmpW32; + + approx = (int16_t)WebRtcSpl_DivW32W16((int32_t)0x1FFFFFFF, den_hi); + // result in Q14 (Note: 3FFFFFFF = 0.5 in Q30) + + // tmpW32 = 1/den = approx * (2.0 - den * approx) (in Q30) + tmpW32 = (den_hi * approx << 1) + ((den_low * approx >> 15) << 1); + // tmpW32 = den * approx + + // result in Q30 (tmpW32 = 2.0-(den*approx)) + tmpW32 = (int32_t)((int64_t)0x7fffffffL - tmpW32); + + // Store tmpW32 in hi and low format + tmp_hi = (int16_t)(tmpW32 >> 16); + tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1); + + // tmpW32 = 1/den in Q29 + tmpW32 = (tmp_hi * approx + (tmp_low * approx >> 15)) << 1; + + // 1/den in hi and low format + tmp_hi = (int16_t)(tmpW32 >> 16); + tmp_low = (int16_t)((tmpW32 - ((int32_t)tmp_hi << 16)) >> 1); + + // Store num in hi and low format + num_hi = (int16_t)(num >> 16); + num_low = (int16_t)((num - ((int32_t)num_hi << 16)) >> 1); + + // num * (1/den) by 32 bit multiplication (result in Q28) + + tmpW32 = num_hi * tmp_hi + (num_hi * tmp_low >> 15) + + (num_low * tmp_hi >> 15); + + // Put result in Q31 (convert from Q28) + tmpW32 = WEBRTC_SPL_LSHIFT_W32(tmpW32, 3); + + return tmpW32; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/dot_product_with_scale.cc b/third_party/libwebrtc/common_audio/signal_processing/dot_product_with_scale.cc new file mode 100644 index 0000000000..00799dae02 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/dot_product_with_scale.cc @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/dot_product_with_scale.h" + +#include "rtc_base/numerics/safe_conversions.h" + +int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1, + const int16_t* vector2, + size_t length, + int scaling) { + int64_t sum = 0; + size_t i = 0; + + /* Unroll the loop to improve performance. */ + for (i = 0; i + 3 < length; i += 4) { + sum += (vector1[i + 0] * vector2[i + 0]) >> scaling; + sum += (vector1[i + 1] * vector2[i + 1]) >> scaling; + sum += (vector1[i + 2] * vector2[i + 2]) >> scaling; + sum += (vector1[i + 3] * vector2[i + 3]) >> scaling; + } + for (; i < length; i++) { + sum += (vector1[i] * vector2[i]) >> scaling; + } + + return rtc::saturated_cast<int32_t>(sum); +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/dot_product_with_scale.h b/third_party/libwebrtc/common_audio/signal_processing/dot_product_with_scale.h new file mode 100644 index 0000000000..9f0d922aaf --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/dot_product_with_scale.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017 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 COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ + +#include <stdint.h> +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +// Calculates the dot product between two (int16_t) vectors. +// +// Input: +// - vector1 : Vector 1 +// - vector2 : Vector 2 +// - vector_length : Number of samples used in the dot product +// - scaling : The number of right bit shifts to apply on each term +// during calculation to avoid overflow, i.e., the +// output will be in Q(-`scaling`) +// +// Return value : The dot product in Q(-scaling) +int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1, + const int16_t* vector2, + size_t length, + int scaling); + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_DOT_PRODUCT_WITH_SCALE_H_ diff --git a/third_party/libwebrtc/common_audio/signal_processing/downsample_fast.c b/third_party/libwebrtc/common_audio/signal_processing/downsample_fast.c new file mode 100644 index 0000000000..80fdc58a49 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/downsample_fast.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#include "rtc_base/checks.h" +#include "rtc_base/sanitizer.h" + +// TODO(Bjornv): Change the function parameter order to WebRTC code style. +// C version of WebRtcSpl_DownsampleFast() for generic platforms. +int WebRtcSpl_DownsampleFastC(const int16_t* data_in, + size_t data_in_length, + int16_t* data_out, + size_t data_out_length, + const int16_t* __restrict coefficients, + size_t coefficients_length, + int factor, + size_t delay) { + int16_t* const original_data_out = data_out; + size_t i = 0; + size_t j = 0; + int32_t out_s32 = 0; + size_t endpos = delay + factor * (data_out_length - 1) + 1; + + // Return error if any of the running conditions doesn't meet. + if (data_out_length == 0 || coefficients_length == 0 + || data_in_length < endpos) { + return -1; + } + + rtc_MsanCheckInitialized(coefficients, sizeof(coefficients[0]), + coefficients_length); + + for (i = delay; i < endpos; i += factor) { + out_s32 = 2048; // Round value, 0.5 in Q12. + + for (j = 0; j < coefficients_length; j++) { + // Negative overflow is permitted here, because this is + // auto-regressive filters, and the state for each batch run is + // stored in the "negative" positions of the output vector. + rtc_MsanCheckInitialized(&data_in[(ptrdiff_t) i - (ptrdiff_t) j], + sizeof(data_in[0]), 1); + // out_s32 is in Q12 domain. + out_s32 += coefficients[j] * data_in[(ptrdiff_t) i - (ptrdiff_t) j]; + } + + out_s32 >>= 12; // Q0. + + // Saturate and store the output. + *data_out++ = WebRtcSpl_SatW32ToW16(out_s32); + } + + RTC_DCHECK_EQ(original_data_out + data_out_length, data_out); + rtc_MsanCheckInitialized(original_data_out, sizeof(original_data_out[0]), + data_out_length); + + return 0; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_mips.c b/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_mips.c new file mode 100644 index 0000000000..0f3f3a069f --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_mips.c @@ -0,0 +1,169 @@ +/* + * 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 "common_audio/signal_processing/include/signal_processing_library.h" + +// Version of WebRtcSpl_DownsampleFast() for MIPS platforms. +int WebRtcSpl_DownsampleFast_mips(const int16_t* data_in, + size_t data_in_length, + int16_t* data_out, + size_t data_out_length, + const int16_t* __restrict coefficients, + size_t coefficients_length, + int factor, + size_t delay) { + int i; + int j; + int k; + int32_t out_s32 = 0; + size_t endpos = delay + factor * (data_out_length - 1) + 1; + + int32_t tmp1, tmp2, tmp3, tmp4, factor_2; + int16_t* p_coefficients; + int16_t* p_data_in; + int16_t* p_data_in_0 = (int16_t*)&data_in[delay]; + int16_t* p_coefficients_0 = (int16_t*)&coefficients[0]; +#if !defined(MIPS_DSP_R1_LE) + int32_t max_16 = 0x7FFF; + int32_t min_16 = 0xFFFF8000; +#endif // #if !defined(MIPS_DSP_R1_LE) + + // Return error if any of the running conditions doesn't meet. + if (data_out_length == 0 || coefficients_length == 0 + || data_in_length < endpos) { + return -1; + } +#if defined(MIPS_DSP_R2_LE) + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "subu %[i], %[endpos], %[delay] \n\t" + "sll %[factor_2], %[factor], 1 \n\t" + "1: \n\t" + "move %[p_data_in], %[p_data_in_0] \n\t" + "mult $zero, $zero \n\t" + "move %[p_coefs], %[p_coefs_0] \n\t" + "sra %[j], %[coef_length], 2 \n\t" + "beq %[j], $zero, 3f \n\t" + " andi %[k], %[coef_length], 3 \n\t" + "2: \n\t" + "lwl %[tmp1], 1(%[p_data_in]) \n\t" + "lwl %[tmp2], 3(%[p_coefs]) \n\t" + "lwl %[tmp3], -3(%[p_data_in]) \n\t" + "lwl %[tmp4], 7(%[p_coefs]) \n\t" + "lwr %[tmp1], -2(%[p_data_in]) \n\t" + "lwr %[tmp2], 0(%[p_coefs]) \n\t" + "lwr %[tmp3], -6(%[p_data_in]) \n\t" + "lwr %[tmp4], 4(%[p_coefs]) \n\t" + "packrl.ph %[tmp1], %[tmp1], %[tmp1] \n\t" + "packrl.ph %[tmp3], %[tmp3], %[tmp3] \n\t" + "dpa.w.ph $ac0, %[tmp1], %[tmp2] \n\t" + "dpa.w.ph $ac0, %[tmp3], %[tmp4] \n\t" + "addiu %[j], %[j], -1 \n\t" + "addiu %[p_data_in], %[p_data_in], -8 \n\t" + "bgtz %[j], 2b \n\t" + " addiu %[p_coefs], %[p_coefs], 8 \n\t" + "3: \n\t" + "beq %[k], $zero, 5f \n\t" + " nop \n\t" + "4: \n\t" + "lhu %[tmp1], 0(%[p_data_in]) \n\t" + "lhu %[tmp2], 0(%[p_coefs]) \n\t" + "addiu %[p_data_in], %[p_data_in], -2 \n\t" + "addiu %[k], %[k], -1 \n\t" + "dpa.w.ph $ac0, %[tmp1], %[tmp2] \n\t" + "bgtz %[k], 4b \n\t" + " addiu %[p_coefs], %[p_coefs], 2 \n\t" + "5: \n\t" + "extr_r.w %[out_s32], $ac0, 12 \n\t" + "addu %[p_data_in_0], %[p_data_in_0], %[factor_2] \n\t" + "subu %[i], %[i], %[factor] \n\t" + "shll_s.w %[out_s32], %[out_s32], 16 \n\t" + "sra %[out_s32], %[out_s32], 16 \n\t" + "sh %[out_s32], 0(%[data_out]) \n\t" + "bgtz %[i], 1b \n\t" + " addiu %[data_out], %[data_out], 2 \n\t" + ".set pop \n\t" + : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), + [tmp4] "=&r" (tmp4), [p_data_in] "=&r" (p_data_in), + [p_data_in_0] "+r" (p_data_in_0), [p_coefs] "=&r" (p_coefficients), + [j] "=&r" (j), [out_s32] "=&r" (out_s32), [factor_2] "=&r" (factor_2), + [i] "=&r" (i), [k] "=&r" (k) + : [coef_length] "r" (coefficients_length), [data_out] "r" (data_out), + [p_coefs_0] "r" (p_coefficients_0), [endpos] "r" (endpos), + [delay] "r" (delay), [factor] "r" (factor) + : "memory", "hi", "lo" + ); +#else // #if defined(MIPS_DSP_R2_LE) + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "sll %[factor_2], %[factor], 1 \n\t" + "subu %[i], %[endpos], %[delay] \n\t" + "1: \n\t" + "move %[p_data_in], %[p_data_in_0] \n\t" + "addiu %[out_s32], $zero, 2048 \n\t" + "move %[p_coefs], %[p_coefs_0] \n\t" + "sra %[j], %[coef_length], 1 \n\t" + "beq %[j], $zero, 3f \n\t" + " andi %[k], %[coef_length], 1 \n\t" + "2: \n\t" + "lh %[tmp1], 0(%[p_data_in]) \n\t" + "lh %[tmp2], 0(%[p_coefs]) \n\t" + "lh %[tmp3], -2(%[p_data_in]) \n\t" + "lh %[tmp4], 2(%[p_coefs]) \n\t" + "mul %[tmp1], %[tmp1], %[tmp2] \n\t" + "addiu %[p_coefs], %[p_coefs], 4 \n\t" + "mul %[tmp3], %[tmp3], %[tmp4] \n\t" + "addiu %[j], %[j], -1 \n\t" + "addiu %[p_data_in], %[p_data_in], -4 \n\t" + "addu %[tmp1], %[tmp1], %[tmp3] \n\t" + "bgtz %[j], 2b \n\t" + " addu %[out_s32], %[out_s32], %[tmp1] \n\t" + "3: \n\t" + "beq %[k], $zero, 4f \n\t" + " nop \n\t" + "lh %[tmp1], 0(%[p_data_in]) \n\t" + "lh %[tmp2], 0(%[p_coefs]) \n\t" + "mul %[tmp1], %[tmp1], %[tmp2] \n\t" + "addu %[out_s32], %[out_s32], %[tmp1] \n\t" + "4: \n\t" + "sra %[out_s32], %[out_s32], 12 \n\t" + "addu %[p_data_in_0], %[p_data_in_0], %[factor_2] \n\t" +#if defined(MIPS_DSP_R1_LE) + "shll_s.w %[out_s32], %[out_s32], 16 \n\t" + "sra %[out_s32], %[out_s32], 16 \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "slt %[tmp1], %[max_16], %[out_s32] \n\t" + "movn %[out_s32], %[max_16], %[tmp1] \n\t" + "slt %[tmp1], %[out_s32], %[min_16] \n\t" + "movn %[out_s32], %[min_16], %[tmp1] \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "subu %[i], %[i], %[factor] \n\t" + "sh %[out_s32], 0(%[data_out]) \n\t" + "bgtz %[i], 1b \n\t" + " addiu %[data_out], %[data_out], 2 \n\t" + ".set pop \n\t" + : [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), [tmp3] "=&r" (tmp3), + [tmp4] "=&r" (tmp4), [p_data_in] "=&r" (p_data_in), [k] "=&r" (k), + [p_data_in_0] "+r" (p_data_in_0), [p_coefs] "=&r" (p_coefficients), + [j] "=&r" (j), [out_s32] "=&r" (out_s32), [factor_2] "=&r" (factor_2), + [i] "=&r" (i) + : [coef_length] "r" (coefficients_length), [data_out] "r" (data_out), + [p_coefs_0] "r" (p_coefficients_0), [endpos] "r" (endpos), +#if !defined(MIPS_DSP_R1_LE) + [max_16] "r" (max_16), [min_16] "r" (min_16), +#endif // #if !defined(MIPS_DSP_R1_LE) + [delay] "r" (delay), [factor] "r" (factor) + : "memory", "hi", "lo" + ); +#endif // #if defined(MIPS_DSP_R2_LE) + return 0; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_neon.c b/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_neon.c new file mode 100644 index 0000000000..36fc0c8aee --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/downsample_fast_neon.c @@ -0,0 +1,217 @@ +/* + * 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 "common_audio/signal_processing/include/signal_processing_library.h" + +#include <arm_neon.h> + +// NEON intrinsics version of WebRtcSpl_DownsampleFast() +// for ARM 32-bit/64-bit platforms. +int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, + size_t data_in_length, + int16_t* data_out, + size_t data_out_length, + const int16_t* __restrict coefficients, + size_t coefficients_length, + int factor, + size_t delay) { + size_t i = 0; + size_t j = 0; + int32_t out_s32 = 0; + size_t endpos = delay + factor * (data_out_length - 1) + 1; + size_t res = data_out_length & 0x7; + size_t endpos1 = endpos - factor * res; + + // Return error if any of the running conditions doesn't meet. + if (data_out_length == 0 || coefficients_length == 0 + || data_in_length < endpos) { + return -1; + } + + // First part, unroll the loop 8 times, with 3 subcases + // (factor == 2, 4, others). + switch (factor) { + case 2: { + for (i = delay; i < endpos1; i += 16) { + // Round value, 0.5 in Q12. + int32x4_t out32x4_0 = vdupq_n_s32(2048); + int32x4_t out32x4_1 = vdupq_n_s32(2048); + +#if defined(WEBRTC_ARCH_ARM64) + // Unroll the loop 2 times. + for (j = 0; j < coefficients_length - 1; j += 2) { + int32x2_t coeff32 = vld1_dup_s32((int32_t*)&coefficients[j]); + int16x4_t coeff16x4 = vreinterpret_s16_s32(coeff32); + int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j - 1]); + + // Mul and accumulate low 64-bit data. + int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]); + int16x4_t in16x4_1 = vget_low_s16(in16x8x2.val[1]); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 1); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_1, coeff16x4, 0); + + // Mul and accumulate high 64-bit data. + // TODO: vget_high_s16 need extra cost on ARM64. This could be + // replaced by vmlal_high_lane_s16. But for the interface of + // vmlal_high_lane_s16, there is a bug in gcc 4.9. + // This issue need to be tracked in the future. + int16x4_t in16x4_2 = vget_high_s16(in16x8x2.val[0]); + int16x4_t in16x4_3 = vget_high_s16(in16x8x2.val[1]); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_2, coeff16x4, 1); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 0); + } + + for (; j < coefficients_length; j++) { + int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); + int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); + + // Mul and accumulate low 64-bit data. + int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); + + // Mul and accumulate high 64-bit data. + // TODO: vget_high_s16 need extra cost on ARM64. This could be + // replaced by vmlal_high_lane_s16. But for the interface of + // vmlal_high_lane_s16, there is a bug in gcc 4.9. + // This issue need to be tracked in the future. + int16x4_t in16x4_1 = vget_high_s16(in16x8x2.val[0]); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); + } +#else + // On ARMv7, the loop unrolling 2 times results in performance + // regression. + for (j = 0; j < coefficients_length; j++) { + int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); + int16x8x2_t in16x8x2 = vld2q_s16(&data_in[i - j]); + + // Mul and accumulate. + int16x4_t in16x4_0 = vget_low_s16(in16x8x2.val[0]); + int16x4_t in16x4_1 = vget_high_s16(in16x8x2.val[0]); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); + } +#endif + + // Saturate and store the output. + int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12); + int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12); + vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1)); + data_out += 8; + } + break; + } + case 4: { + for (i = delay; i < endpos1; i += 32) { + // Round value, 0.5 in Q12. + int32x4_t out32x4_0 = vdupq_n_s32(2048); + int32x4_t out32x4_1 = vdupq_n_s32(2048); + + // Unroll the loop 4 times. + for (j = 0; j < coefficients_length - 3; j += 4) { + int16x4_t coeff16x4 = vld1_s16(&coefficients[j]); + int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j - 3]); + + // Mul and accumulate low 64-bit data. + int16x4_t in16x4_0 = vget_low_s16(in16x8x4.val[0]); + int16x4_t in16x4_2 = vget_low_s16(in16x8x4.val[1]); + int16x4_t in16x4_4 = vget_low_s16(in16x8x4.val[2]); + int16x4_t in16x4_6 = vget_low_s16(in16x8x4.val[3]); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 3); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_2, coeff16x4, 2); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_4, coeff16x4, 1); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_6, coeff16x4, 0); + + // Mul and accumulate high 64-bit data. + // TODO: vget_high_s16 need extra cost on ARM64. This could be + // replaced by vmlal_high_lane_s16. But for the interface of + // vmlal_high_lane_s16, there is a bug in gcc 4.9. + // This issue need to be tracked in the future. + int16x4_t in16x4_1 = vget_high_s16(in16x8x4.val[0]); + int16x4_t in16x4_3 = vget_high_s16(in16x8x4.val[1]); + int16x4_t in16x4_5 = vget_high_s16(in16x8x4.val[2]); + int16x4_t in16x4_7 = vget_high_s16(in16x8x4.val[3]); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 3); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_3, coeff16x4, 2); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_5, coeff16x4, 1); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_7, coeff16x4, 0); + } + + for (; j < coefficients_length; j++) { + int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); + int16x8x4_t in16x8x4 = vld4q_s16(&data_in[i - j]); + + // Mul and accumulate low 64-bit data. + int16x4_t in16x4_0 = vget_low_s16(in16x8x4.val[0]); + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); + + // Mul and accumulate high 64-bit data. + // TODO: vget_high_s16 need extra cost on ARM64. This could be + // replaced by vmlal_high_lane_s16. But for the interface of + // vmlal_high_lane_s16, there is a bug in gcc 4.9. + // This issue need to be tracked in the future. + int16x4_t in16x4_1 = vget_high_s16(in16x8x4.val[0]); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); + } + + // Saturate and store the output. + int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12); + int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12); + vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1)); + data_out += 8; + } + break; + } + default: { + for (i = delay; i < endpos1; i += factor * 8) { + // Round value, 0.5 in Q12. + int32x4_t out32x4_0 = vdupq_n_s32(2048); + int32x4_t out32x4_1 = vdupq_n_s32(2048); + + for (j = 0; j < coefficients_length; j++) { + int16x4_t coeff16x4 = vld1_dup_s16(&coefficients[j]); + int16x4_t in16x4_0 = vld1_dup_s16(&data_in[i - j]); + in16x4_0 = vld1_lane_s16(&data_in[i + factor - j], in16x4_0, 1); + in16x4_0 = vld1_lane_s16(&data_in[i + factor * 2 - j], in16x4_0, 2); + in16x4_0 = vld1_lane_s16(&data_in[i + factor * 3 - j], in16x4_0, 3); + int16x4_t in16x4_1 = vld1_dup_s16(&data_in[i + factor * 4 - j]); + in16x4_1 = vld1_lane_s16(&data_in[i + factor * 5 - j], in16x4_1, 1); + in16x4_1 = vld1_lane_s16(&data_in[i + factor * 6 - j], in16x4_1, 2); + in16x4_1 = vld1_lane_s16(&data_in[i + factor * 7 - j], in16x4_1, 3); + + // Mul and accumulate. + out32x4_0 = vmlal_lane_s16(out32x4_0, in16x4_0, coeff16x4, 0); + out32x4_1 = vmlal_lane_s16(out32x4_1, in16x4_1, coeff16x4, 0); + } + + // Saturate and store the output. + int16x4_t out16x4_0 = vqshrn_n_s32(out32x4_0, 12); + int16x4_t out16x4_1 = vqshrn_n_s32(out32x4_1, 12); + vst1q_s16(data_out, vcombine_s16(out16x4_0, out16x4_1)); + data_out += 8; + } + break; + } + } + + // Second part, do the rest iterations (if any). + for (; i < endpos; i += factor) { + out_s32 = 2048; // Round value, 0.5 in Q12. + + for (j = 0; j < coefficients_length; j++) { + out_s32 = WebRtc_MulAccumW16(coefficients[j], data_in[i - j], out_s32); + } + + // Saturate and store the output. + out_s32 >>= 12; + *data_out++ = WebRtcSpl_SatW32ToW16(out_s32); + } + + return 0; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/energy.c b/third_party/libwebrtc/common_audio/signal_processing/energy.c new file mode 100644 index 0000000000..5cce6b8777 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/energy.c @@ -0,0 +1,39 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_Energy(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +int32_t WebRtcSpl_Energy(int16_t* vector, + size_t vector_length, + int* scale_factor) +{ + int32_t en = 0; + size_t i; + int scaling = + WebRtcSpl_GetScalingSquare(vector, vector_length, vector_length); + size_t looptimes = vector_length; + int16_t *vectorptr = vector; + + for (i = 0; i < looptimes; i++) + { + en += (*vectorptr * *vectorptr) >> scaling; + vectorptr++; + } + *scale_factor = scaling; + + return en; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/filter_ar.c b/third_party/libwebrtc/common_audio/signal_processing/filter_ar.c new file mode 100644 index 0000000000..b1f666d723 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/filter_ar.c @@ -0,0 +1,95 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_FilterAR(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#include "rtc_base/checks.h" + +size_t WebRtcSpl_FilterAR(const int16_t* a, + size_t a_length, + const int16_t* x, + size_t x_length, + int16_t* state, + size_t state_length, + int16_t* state_low, + size_t state_low_length, + int16_t* filtered, + int16_t* filtered_low, + size_t filtered_low_length) +{ + int64_t o; + int32_t oLOW; + size_t i, j, stop; + const int16_t* x_ptr = &x[0]; + int16_t* filteredFINAL_ptr = filtered; + int16_t* filteredFINAL_LOW_ptr = filtered_low; + + for (i = 0; i < x_length; i++) + { + // Calculate filtered[i] and filtered_low[i] + const int16_t* a_ptr = &a[1]; + // The index can become negative, but the arrays will never be indexed + // with it when negative. Nevertheless, the index cannot be a size_t + // because of this. + int filtered_ix = (int)i - 1; + int16_t* state_ptr = &state[state_length - 1]; + int16_t* state_low_ptr = &state_low[state_length - 1]; + + o = (int32_t)(*x_ptr++) * (1 << 12); + oLOW = (int32_t)0; + + stop = (i < a_length) ? i + 1 : a_length; + for (j = 1; j < stop; j++) + { + RTC_DCHECK_GE(filtered_ix, 0); + o -= *a_ptr * filtered[filtered_ix]; + oLOW -= *a_ptr++ * filtered_low[filtered_ix]; + --filtered_ix; + } + for (j = i + 1; j < a_length; j++) + { + o -= *a_ptr * *state_ptr--; + oLOW -= *a_ptr++ * *state_low_ptr--; + } + + o += (oLOW >> 12); + *filteredFINAL_ptr = (int16_t)((o + (int32_t)2048) >> 12); + *filteredFINAL_LOW_ptr++ = + (int16_t)(o - ((int32_t)(*filteredFINAL_ptr++) * (1 << 12))); + } + + // Save the filter state + if (x_length >= state_length) + { + WebRtcSpl_CopyFromEndW16(filtered, x_length, a_length - 1, state); + WebRtcSpl_CopyFromEndW16(filtered_low, x_length, a_length - 1, state_low); + } else + { + for (i = 0; i < state_length - x_length; i++) + { + state[i] = state[i + x_length]; + state_low[i] = state_low[i + x_length]; + } + for (i = 0; i < x_length; i++) + { + state[state_length - x_length + i] = filtered[i]; + state_low[state_length - x_length + i] = filtered_low[i]; + } + } + + return x_length; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c b/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c new file mode 100644 index 0000000000..9010f1ce82 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stddef.h> + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// TODO(bjornv): Change the return type to report errors. + +void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, + int16_t* data_out, + const int16_t* __restrict coefficients, + size_t coefficients_length, + size_t data_length) { + size_t i = 0; + size_t j = 0; + + RTC_DCHECK_GT(data_length, 0); + RTC_DCHECK_GT(coefficients_length, 1); + + for (i = 0; i < data_length; i++) { + int64_t output = 0; + int64_t sum = 0; + + for (j = coefficients_length - 1; j > 0; j--) { + // Negative overflow is permitted here, because this is + // auto-regressive filters, and the state for each batch run is + // stored in the "negative" positions of the output vector. + sum += coefficients[j] * data_out[(ptrdiff_t) i - (ptrdiff_t) j]; + } + + output = coefficients[0] * data_in[i]; + output -= sum; + + // Saturate and store the output. + output = WEBRTC_SPL_SAT(134215679, output, -134217728); + data_out[i] = (int16_t)((output + 2048) >> 12); + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S b/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S new file mode 100644 index 0000000000..60319d29ff --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S @@ -0,0 +1,218 @@ +@ +@ Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. +@ +@ Use of this source code is governed by a BSD-style license +@ that can be found in the LICENSE file in the root of the source +@ tree. An additional intellectual property rights grant can be found +@ in the file PATENTS. All contributing project authors may +@ be found in the AUTHORS file in the root of the source tree. +@ + +@ This file contains the function WebRtcSpl_FilterARFastQ12(), optimized for +@ ARMv7 platform. The description header can be found in +@ signal_processing_library.h +@ +@ Output is bit-exact with the generic C code as in filter_ar_fast_q12.c, and +@ the reference C code at end of this file. + +@ Assumptions: +@ (1) data_length > 0 +@ (2) coefficients_length > 1 + +@ Register usage: +@ +@ r0: &data_in[i] +@ r1: &data_out[i], for result ouput +@ r2: &coefficients[0] +@ r3: coefficients_length +@ r4: Iteration counter for the outer loop. +@ r5: data_out[j] as multiplication inputs +@ r6: Calculated value for output data_out[]; interation counter for inner loop +@ r7: Partial sum of a filtering multiplication results +@ r8: Partial sum of a filtering multiplication results +@ r9: &data_out[], for filtering input; data_in[i] +@ r10: coefficients[j] +@ r11: Scratch +@ r12: &coefficients[j] + +#include "rtc_base/system/asm_defines.h" + +GLOBAL_FUNCTION WebRtcSpl_FilterARFastQ12 +.align 2 +DEFINE_FUNCTION WebRtcSpl_FilterARFastQ12 + push {r4-r11} + + ldrsh r12, [sp, #32] @ data_length + subs r4, r12, #1 + beq ODD_LENGTH @ jump if data_length == 1 + +LOOP_LENGTH: + add r12, r2, r3, lsl #1 + sub r12, #4 @ &coefficients[coefficients_length - 2] + sub r9, r1, r3, lsl #1 + add r9, #2 @ &data_out[i - coefficients_length + 1] + ldr r5, [r9], #4 @ data_out[i - coefficients_length + {1,2}] + + mov r7, #0 @ sum1 + mov r8, #0 @ sum2 + subs r6, r3, #3 @ Iteration counter for inner loop. + beq ODD_A_LENGTH @ branch if coefficients_length == 3 + blt POST_LOOP_A_LENGTH @ branch if coefficients_length == 2 + +LOOP_A_LENGTH: + ldr r10, [r12], #-4 @ coefficients[j - 1], coefficients[j] + subs r6, #2 + smlatt r8, r10, r5, r8 @ sum2 += coefficients[j] * data_out[i - j + 1]; + smlatb r7, r10, r5, r7 @ sum1 += coefficients[j] * data_out[i - j]; + smlabt r7, r10, r5, r7 @ coefficients[j - 1] * data_out[i - j + 1]; + ldr r5, [r9], #4 @ data_out[i - j + 2], data_out[i - j + 3] + smlabb r8, r10, r5, r8 @ coefficients[j - 1] * data_out[i - j + 2]; + bgt LOOP_A_LENGTH + blt POST_LOOP_A_LENGTH + +ODD_A_LENGTH: + ldrsh r10, [r12, #2] @ Filter coefficients coefficients[2] + sub r12, #2 @ &coefficients[0] + smlabb r7, r10, r5, r7 @ sum1 += coefficients[2] * data_out[i - 2]; + smlabt r8, r10, r5, r8 @ sum2 += coefficients[2] * data_out[i - 1]; + ldr r5, [r9, #-2] @ data_out[i - 1], data_out[i] + +POST_LOOP_A_LENGTH: + ldr r10, [r12] @ coefficients[0], coefficients[1] + smlatb r7, r10, r5, r7 @ sum1 += coefficients[1] * data_out[i - 1]; + + ldr r9, [r0], #4 @ data_in[i], data_in[i + 1] + smulbb r6, r10, r9 @ output1 = coefficients[0] * data_in[i]; + sub r6, r7 @ output1 -= sum1; + + sbfx r11, r6, #12, #16 + ssat r7, #16, r6, asr #12 + cmp r7, r11 + addeq r6, r6, #2048 + ssat r6, #16, r6, asr #12 + strh r6, [r1], #2 @ Store data_out[i] + + smlatb r8, r10, r6, r8 @ sum2 += coefficients[1] * data_out[i]; + smulbt r6, r10, r9 @ output2 = coefficients[0] * data_in[i + 1]; + sub r6, r8 @ output1 -= sum1; + + sbfx r11, r6, #12, #16 + ssat r7, #16, r6, asr #12 + cmp r7, r11 + addeq r6, r6, #2048 + ssat r6, #16, r6, asr #12 + strh r6, [r1], #2 @ Store data_out[i + 1] + + subs r4, #2 + bgt LOOP_LENGTH + blt END @ For even data_length, it's done. Jump to END. + +@ Process i = data_length -1, for the case of an odd length. +ODD_LENGTH: + add r12, r2, r3, lsl #1 + sub r12, #4 @ &coefficients[coefficients_length - 2] + sub r9, r1, r3, lsl #1 + add r9, #2 @ &data_out[i - coefficients_length + 1] + mov r7, #0 @ sum1 + mov r8, #0 @ sum1 + subs r6, r3, #2 @ inner loop counter + beq EVEN_A_LENGTH @ branch if coefficients_length == 2 + +LOOP2_A_LENGTH: + ldr r10, [r12], #-4 @ coefficients[j - 1], coefficients[j] + ldr r5, [r9], #4 @ data_out[i - j], data_out[i - j + 1] + subs r6, #2 + smlatb r7, r10, r5, r7 @ sum1 += coefficients[j] * data_out[i - j]; + smlabt r8, r10, r5, r8 @ coefficients[j - 1] * data_out[i - j + 1]; + bgt LOOP2_A_LENGTH + addlt r12, #2 + blt POST_LOOP2_A_LENGTH + +EVEN_A_LENGTH: + ldrsh r10, [r12, #2] @ Filter coefficients coefficients[1] + ldrsh r5, [r9] @ data_out[i - 1] + smlabb r7, r10, r5, r7 @ sum1 += coefficients[1] * data_out[i - 1]; + +POST_LOOP2_A_LENGTH: + ldrsh r10, [r12] @ Filter coefficients coefficients[0] + ldrsh r9, [r0] @ data_in[i] + smulbb r6, r10, r9 @ output1 = coefficients[0] * data_in[i]; + sub r6, r7 @ output1 -= sum1; + sub r6, r8 @ output1 -= sum1; + sbfx r8, r6, #12, #16 + ssat r7, #16, r6, asr #12 + cmp r7, r8 + addeq r6, r6, #2048 + ssat r6, #16, r6, asr #12 + strh r6, [r1] @ Store the data_out[i] + +END: + pop {r4-r11} + bx lr + +@Reference C code: +@ +@void WebRtcSpl_FilterARFastQ12(int16_t* data_in, +@ int16_t* data_out, +@ int16_t* __restrict coefficients, +@ size_t coefficients_length, +@ size_t data_length) { +@ size_t i = 0; +@ size_t j = 0; +@ +@ assert(data_length > 0); +@ assert(coefficients_length > 1); +@ +@ for (i = 0; i < data_length - 1; i += 2) { +@ int32_t output1 = 0; +@ int32_t sum1 = 0; +@ int32_t output2 = 0; +@ int32_t sum2 = 0; +@ +@ for (j = coefficients_length - 1; j > 2; j -= 2) { +@ sum1 += coefficients[j] * data_out[i - j]; +@ sum1 += coefficients[j - 1] * data_out[i - j + 1]; +@ sum2 += coefficients[j] * data_out[i - j + 1]; +@ sum2 += coefficients[j - 1] * data_out[i - j + 2]; +@ } +@ +@ if (j == 2) { +@ sum1 += coefficients[2] * data_out[i - 2]; +@ sum2 += coefficients[2] * data_out[i - 1]; +@ } +@ +@ sum1 += coefficients[1] * data_out[i - 1]; +@ output1 = coefficients[0] * data_in[i]; +@ output1 -= sum1; +@ // Saturate and store the output. +@ output1 = WEBRTC_SPL_SAT(134215679, output1, -134217728); +@ data_out[i] = (int16_t)((output1 + 2048) >> 12); +@ +@ sum2 += coefficients[1] * data_out[i]; +@ output2 = coefficients[0] * data_in[i + 1]; +@ output2 -= sum2; +@ // Saturate and store the output. +@ output2 = WEBRTC_SPL_SAT(134215679, output2, -134217728); +@ data_out[i + 1] = (int16_t)((output2 + 2048) >> 12); +@ } +@ +@ if (i == data_length - 1) { +@ int32_t output1 = 0; +@ int32_t sum1 = 0; +@ +@ for (j = coefficients_length - 1; j > 1; j -= 2) { +@ sum1 += coefficients[j] * data_out[i - j]; +@ sum1 += coefficients[j - 1] * data_out[i - j + 1]; +@ } +@ +@ if (j == 1) { +@ sum1 += coefficients[1] * data_out[i - 1]; +@ } +@ +@ output1 = coefficients[0] * data_in[i]; +@ output1 -= sum1; +@ // Saturate and store the output. +@ output1 = WEBRTC_SPL_SAT(134215679, output1, -134217728); +@ data_out[i] = (int16_t)((output1 + 2048) >> 12); +@ } +@} diff --git a/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c b/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c new file mode 100644 index 0000000000..b9ad30f006 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, + int16_t* data_out, + const int16_t* __restrict coefficients, + size_t coefficients_length, + size_t data_length) { + int r0, r1, r2, r3; + int coef0, offset; + int i, j, k; + int coefptr, outptr, tmpout, inptr; +#if !defined(MIPS_DSP_R1_LE) + int max16 = 0x7FFF; + int min16 = 0xFFFF8000; +#endif // #if !defined(MIPS_DSP_R1_LE) + + RTC_DCHECK_GT(data_length, 0); + RTC_DCHECK_GT(coefficients_length, 1); + + __asm __volatile ( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[i], %[data_length], 0 \n\t" + "lh %[coef0], 0(%[coefficients]) \n\t" + "addiu %[j], %[coefficients_length], -1 \n\t" + "andi %[k], %[j], 1 \n\t" + "sll %[offset], %[j], 1 \n\t" + "subu %[outptr], %[data_out], %[offset] \n\t" + "addiu %[inptr], %[data_in], 0 \n\t" + "bgtz %[k], 3f \n\t" + " addu %[coefptr], %[coefficients], %[offset] \n\t" + "1: \n\t" + "lh %[r0], 0(%[inptr]) \n\t" + "addiu %[i], %[i], -1 \n\t" + "addiu %[tmpout], %[outptr], 0 \n\t" + "mult %[r0], %[coef0] \n\t" + "2: \n\t" + "lh %[r0], 0(%[tmpout]) \n\t" + "lh %[r1], 0(%[coefptr]) \n\t" + "lh %[r2], 2(%[tmpout]) \n\t" + "lh %[r3], -2(%[coefptr]) \n\t" + "addiu %[tmpout], %[tmpout], 4 \n\t" + "msub %[r0], %[r1] \n\t" + "msub %[r2], %[r3] \n\t" + "addiu %[j], %[j], -2 \n\t" + "bgtz %[j], 2b \n\t" + " addiu %[coefptr], %[coefptr], -4 \n\t" +#if defined(MIPS_DSP_R1_LE) + "extr_r.w %[r0], $ac0, 12 \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "mflo %[r0] \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "addu %[coefptr], %[coefficients], %[offset] \n\t" + "addiu %[inptr], %[inptr], 2 \n\t" + "addiu %[j], %[coefficients_length], -1 \n\t" +#if defined(MIPS_DSP_R1_LE) + "shll_s.w %[r0], %[r0], 16 \n\t" + "sra %[r0], %[r0], 16 \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "addiu %[r0], %[r0], 2048 \n\t" + "sra %[r0], %[r0], 12 \n\t" + "slt %[r1], %[max16], %[r0] \n\t" + "movn %[r0], %[max16], %[r1] \n\t" + "slt %[r1], %[r0], %[min16] \n\t" + "movn %[r0], %[min16], %[r1] \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "sh %[r0], 0(%[tmpout]) \n\t" + "bgtz %[i], 1b \n\t" + " addiu %[outptr], %[outptr], 2 \n\t" + "b 5f \n\t" + " nop \n\t" + "3: \n\t" + "lh %[r0], 0(%[inptr]) \n\t" + "addiu %[i], %[i], -1 \n\t" + "addiu %[tmpout], %[outptr], 0 \n\t" + "mult %[r0], %[coef0] \n\t" + "4: \n\t" + "lh %[r0], 0(%[tmpout]) \n\t" + "lh %[r1], 0(%[coefptr]) \n\t" + "lh %[r2], 2(%[tmpout]) \n\t" + "lh %[r3], -2(%[coefptr]) \n\t" + "addiu %[tmpout], %[tmpout], 4 \n\t" + "msub %[r0], %[r1] \n\t" + "msub %[r2], %[r3] \n\t" + "addiu %[j], %[j], -2 \n\t" + "bgtz %[j], 4b \n\t" + " addiu %[coefptr], %[coefptr], -4 \n\t" + "lh %[r0], 0(%[tmpout]) \n\t" + "lh %[r1], 0(%[coefptr]) \n\t" + "msub %[r0], %[r1] \n\t" +#if defined(MIPS_DSP_R1_LE) + "extr_r.w %[r0], $ac0, 12 \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "mflo %[r0] \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "addu %[coefptr], %[coefficients], %[offset] \n\t" + "addiu %[inptr], %[inptr], 2 \n\t" + "addiu %[j], %[coefficients_length], -1 \n\t" +#if defined(MIPS_DSP_R1_LE) + "shll_s.w %[r0], %[r0], 16 \n\t" + "sra %[r0], %[r0], 16 \n\t" +#else // #if defined(MIPS_DSP_R1_LE) + "addiu %[r0], %[r0], 2048 \n\t" + "sra %[r0], %[r0], 12 \n\t" + "slt %[r1], %[max16], %[r0] \n\t" + "movn %[r0], %[max16], %[r1] \n\t" + "slt %[r1], %[r0], %[min16] \n\t" + "movn %[r0], %[min16], %[r1] \n\t" +#endif // #if defined(MIPS_DSP_R1_LE) + "sh %[r0], 2(%[tmpout]) \n\t" + "bgtz %[i], 3b \n\t" + " addiu %[outptr], %[outptr], 2 \n\t" + "5: \n\t" + ".set pop \n\t" + : [i] "=&r" (i), [j] "=&r" (j), [k] "=&r" (k), [r0] "=&r" (r0), + [r1] "=&r" (r1), [r2] "=&r" (r2), [r3] "=&r" (r3), + [coef0] "=&r" (coef0), [offset] "=&r" (offset), + [outptr] "=&r" (outptr), [inptr] "=&r" (inptr), + [coefptr] "=&r" (coefptr), [tmpout] "=&r" (tmpout) + : [coefficients] "r" (coefficients), [data_length] "r" (data_length), + [coefficients_length] "r" (coefficients_length), +#if !defined(MIPS_DSP_R1_LE) + [max16] "r" (max16), [min16] "r" (min16), +#endif + [data_out] "r" (data_out), [data_in] "r" (data_in) + : "hi", "lo", "memory" + ); +} + diff --git a/third_party/libwebrtc/common_audio/signal_processing/filter_ma_fast_q12.c b/third_party/libwebrtc/common_audio/signal_processing/filter_ma_fast_q12.c new file mode 100644 index 0000000000..329d47e14f --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/filter_ma_fast_q12.c @@ -0,0 +1,55 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_FilterMAFastQ12(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#include "rtc_base/sanitizer.h" + +void WebRtcSpl_FilterMAFastQ12(const int16_t* in_ptr, + int16_t* out_ptr, + const int16_t* B, + size_t B_length, + size_t length) +{ + size_t i, j; + + rtc_MsanCheckInitialized(B, sizeof(B[0]), B_length); + rtc_MsanCheckInitialized(in_ptr - B_length + 1, sizeof(in_ptr[0]), + B_length + length - 1); + + for (i = 0; i < length; i++) + { + int32_t o = 0; + + for (j = 0; j < B_length; j++) + { + // Negative overflow is permitted here, because this is + // auto-regressive filters, and the state for each batch run is + // stored in the "negative" positions of the output vector. + o += B[j] * in_ptr[(ptrdiff_t) i - (ptrdiff_t) j]; + } + + // If output is higher than 32768, saturate it. Same with negative side + // 2^27 = 134217728, which corresponds to 32768 in Q12 + + // Saturate the output + o = WEBRTC_SPL_SAT((int32_t)134215679, o, (int32_t)-134217728); + + *out_ptr++ = (int16_t)((o + (int32_t)2048) >> 12); + } + return; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/get_hanning_window.c b/third_party/libwebrtc/common_audio/signal_processing/get_hanning_window.c new file mode 100644 index 0000000000..8f29da8d9b --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/get_hanning_window.c @@ -0,0 +1,77 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_GetHanningWindow(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// Hanning table with 256 entries +static const int16_t kHanningTable[] = { + 1, 2, 6, 10, 15, 22, 30, 39, + 50, 62, 75, 89, 104, 121, 138, 157, + 178, 199, 222, 246, 271, 297, 324, 353, + 383, 413, 446, 479, 513, 549, 586, 624, + 663, 703, 744, 787, 830, 875, 920, 967, + 1015, 1064, 1114, 1165, 1218, 1271, 1325, 1381, + 1437, 1494, 1553, 1612, 1673, 1734, 1796, 1859, + 1924, 1989, 2055, 2122, 2190, 2259, 2329, 2399, + 2471, 2543, 2617, 2691, 2765, 2841, 2918, 2995, + 3073, 3152, 3232, 3312, 3393, 3475, 3558, 3641, + 3725, 3809, 3895, 3980, 4067, 4154, 4242, 4330, + 4419, 4509, 4599, 4689, 4781, 4872, 4964, 5057, + 5150, 5244, 5338, 5432, 5527, 5622, 5718, 5814, + 5910, 6007, 6104, 6202, 6299, 6397, 6495, 6594, + 6693, 6791, 6891, 6990, 7090, 7189, 7289, 7389, + 7489, 7589, 7690, 7790, 7890, 7991, 8091, 8192, + 8293, 8393, 8494, 8594, 8694, 8795, 8895, 8995, + 9095, 9195, 9294, 9394, 9493, 9593, 9691, 9790, + 9889, 9987, 10085, 10182, 10280, 10377, 10474, 10570, +10666, 10762, 10857, 10952, 11046, 11140, 11234, 11327, +11420, 11512, 11603, 11695, 11785, 11875, 11965, 12054, +12142, 12230, 12317, 12404, 12489, 12575, 12659, 12743, +12826, 12909, 12991, 13072, 13152, 13232, 13311, 13389, +13466, 13543, 13619, 13693, 13767, 13841, 13913, 13985, +14055, 14125, 14194, 14262, 14329, 14395, 14460, 14525, +14588, 14650, 14711, 14772, 14831, 14890, 14947, 15003, +15059, 15113, 15166, 15219, 15270, 15320, 15369, 15417, +15464, 15509, 15554, 15597, 15640, 15681, 15721, 15760, +15798, 15835, 15871, 15905, 15938, 15971, 16001, 16031, +16060, 16087, 16113, 16138, 16162, 16185, 16206, 16227, +16246, 16263, 16280, 16295, 16309, 16322, 16334, 16345, +16354, 16362, 16369, 16374, 16378, 16382, 16383, 16384 +}; + +void WebRtcSpl_GetHanningWindow(int16_t *v, size_t size) +{ + size_t jj; + int16_t *vptr1; + + int32_t index; + int32_t factor = ((int32_t)0x40000000); + + factor = WebRtcSpl_DivW32W16(factor, (int16_t)size); + if (size < 513) + index = (int32_t)-0x200000; + else + index = (int32_t)-0x100000; + vptr1 = v; + + for (jj = 0; jj < size; jj++) + { + index += factor; + (*vptr1++) = kHanningTable[index >> 22]; + } + +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/get_scaling_square.c b/third_party/libwebrtc/common_audio/signal_processing/get_scaling_square.c new file mode 100644 index 0000000000..4eb126941e --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/get_scaling_square.c @@ -0,0 +1,46 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_GetScalingSquare(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +int16_t WebRtcSpl_GetScalingSquare(int16_t* in_vector, + size_t in_vector_length, + size_t times) +{ + int16_t nbits = WebRtcSpl_GetSizeInBits((uint32_t)times); + size_t i; + int16_t smax = -1; + int16_t sabs; + int16_t *sptr = in_vector; + int16_t t; + size_t looptimes = in_vector_length; + + for (i = looptimes; i > 0; i--) + { + sabs = (*sptr > 0 ? *sptr++ : -*sptr++); + smax = (sabs > smax ? sabs : smax); + } + t = WebRtcSpl_NormW32(WEBRTC_SPL_MUL(smax, smax)); + + if (smax == 0) + { + return 0; // Since norm(0) returns 0 + } else + { + return (t > nbits) ? 0 : nbits - t; + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/ilbc_specific_functions.c b/third_party/libwebrtc/common_audio/signal_processing/ilbc_specific_functions.c new file mode 100644 index 0000000000..cbdd3dcbcd --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/ilbc_specific_functions.c @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This file contains implementations of the iLBC specific functions + * WebRtcSpl_ReverseOrderMultArrayElements() + * WebRtcSpl_ElementwiseVectorMult() + * WebRtcSpl_AddVectorsAndShift() + * WebRtcSpl_AddAffineVectorToVector() + * WebRtcSpl_AffineTransformVector() + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +void WebRtcSpl_ReverseOrderMultArrayElements(int16_t *out, const int16_t *in, + const int16_t *win, + size_t vector_length, + int16_t right_shifts) +{ + size_t i; + int16_t *outptr = out; + const int16_t *inptr = in; + const int16_t *winptr = win; + for (i = 0; i < vector_length; i++) + { + *outptr++ = (int16_t)((*inptr++ * *winptr--) >> right_shifts); + } +} + +void WebRtcSpl_ElementwiseVectorMult(int16_t *out, const int16_t *in, + const int16_t *win, size_t vector_length, + int16_t right_shifts) +{ + size_t i; + int16_t *outptr = out; + const int16_t *inptr = in; + const int16_t *winptr = win; + for (i = 0; i < vector_length; i++) + { + *outptr++ = (int16_t)((*inptr++ * *winptr++) >> right_shifts); + } +} + +void WebRtcSpl_AddVectorsAndShift(int16_t *out, const int16_t *in1, + const int16_t *in2, size_t vector_length, + int16_t right_shifts) +{ + size_t i; + int16_t *outptr = out; + const int16_t *in1ptr = in1; + const int16_t *in2ptr = in2; + for (i = vector_length; i > 0; i--) + { + (*outptr++) = (int16_t)(((*in1ptr++) + (*in2ptr++)) >> right_shifts); + } +} + +void WebRtcSpl_AddAffineVectorToVector(int16_t *out, const int16_t *in, + int16_t gain, int32_t add_constant, + int16_t right_shifts, + size_t vector_length) +{ + size_t i; + + for (i = 0; i < vector_length; i++) + { + out[i] += (int16_t)((in[i] * gain + add_constant) >> right_shifts); + } +} + +void WebRtcSpl_AffineTransformVector(int16_t *out, const int16_t *in, + int16_t gain, int32_t add_constant, + int16_t right_shifts, size_t vector_length) +{ + size_t i; + + for (i = 0; i < vector_length; i++) + { + out[i] = (int16_t)((in[i] * gain + add_constant) >> right_shifts); + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/include/real_fft.h b/third_party/libwebrtc/common_audio/signal_processing/include/real_fft.h new file mode 100644 index 0000000000..a0da5096c1 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/include/real_fft.h @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ + +#include <stdint.h> + +// For ComplexFFT(), the maximum fft order is 10; +// WebRTC APM uses orders of only 7 and 8. +enum { kMaxFFTOrder = 10 }; + +struct RealFFT; + +#ifdef __cplusplus +extern "C" { +#endif + +struct RealFFT* WebRtcSpl_CreateRealFFT(int order); +void WebRtcSpl_FreeRealFFT(struct RealFFT* self); + +// Compute an FFT for a real-valued signal of length of 2^order, +// where 1 < order <= MAX_FFT_ORDER. Transform length is determined by the +// specification structure, which must be initialized prior to calling the FFT +// function with WebRtcSpl_CreateRealFFT(). +// The relationship between the input and output sequences can +// be expressed in terms of the DFT, i.e.: +// x[n] = (2^(-scalefactor)/N) . SUM[k=0,...,N-1] X[k].e^(jnk.2.pi/N) +// n=0,1,2,...N-1 +// N=2^order. +// The conjugate-symmetric output sequence is represented using a CCS vector, +// which is of length N+2, and is organized as follows: +// Index: 0 1 2 3 4 5 . . . N-2 N-1 N N+1 +// Component: R0 0 R1 I1 R2 I2 . . . R[N/2-1] I[N/2-1] R[N/2] 0 +// where R[n] and I[n], respectively, denote the real and imaginary components +// for FFT bin 'n'. Bins are numbered from 0 to N/2, where N is the FFT length. +// Bin index 0 corresponds to the DC component, and bin index N/2 corresponds to +// the foldover frequency. +// +// Input Arguments: +// self - pointer to preallocated and initialized FFT specification structure. +// real_data_in - the input signal. For an ARM Neon platform, it must be +// aligned on a 32-byte boundary. +// +// Output Arguments: +// complex_data_out - the output complex signal with (2^order + 2) 16-bit +// elements. For an ARM Neon platform, it must be different +// from real_data_in, and aligned on a 32-byte boundary. +// +// Return Value: +// 0 - FFT calculation is successful. +// -1 - Error with bad arguments (null pointers). +int WebRtcSpl_RealForwardFFT(struct RealFFT* self, + const int16_t* real_data_in, + int16_t* complex_data_out); + +// Compute the inverse FFT for a conjugate-symmetric input sequence of length of +// 2^order, where 1 < order <= MAX_FFT_ORDER. Transform length is determined by +// the specification structure, which must be initialized prior to calling the +// FFT function with WebRtcSpl_CreateRealFFT(). +// For a transform of length M, the input sequence is represented using a packed +// CCS vector of length M+2, which is explained in the comments for +// WebRtcSpl_RealForwardFFTC above. +// +// Input Arguments: +// self - pointer to preallocated and initialized FFT specification structure. +// complex_data_in - the input complex signal with (2^order + 2) 16-bit +// elements. For an ARM Neon platform, it must be aligned on +// a 32-byte boundary. +// +// Output Arguments: +// real_data_out - the output real signal. For an ARM Neon platform, it must +// be different to complex_data_in, and aligned on a 32-byte +// boundary. +// +// Return Value: +// 0 or a positive number - a value that the elements in the `real_data_out` +// should be shifted left with in order to get +// correct physical values. +// -1 - Error with bad arguments (null pointers). +int WebRtcSpl_RealInverseFFT(struct RealFFT* self, + const int16_t* complex_data_in, + int16_t* real_data_out); + +#ifdef __cplusplus +} +#endif + +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_ diff --git a/third_party/libwebrtc/common_audio/signal_processing/include/signal_processing_library.h b/third_party/libwebrtc/common_audio/signal_processing/include/signal_processing_library.h new file mode 100644 index 0000000000..48c9b309b4 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/include/signal_processing_library.h @@ -0,0 +1,1635 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * This header file includes all of the fix point signal processing library + * (SPL) function descriptions and declarations. For specific function calls, + * see bottom of file. + */ + +#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ + +#include <string.h> + +#include "common_audio/signal_processing/dot_product_with_scale.h" + +// Macros specific for the fixed point implementation +#define WEBRTC_SPL_WORD16_MAX 32767 +#define WEBRTC_SPL_WORD16_MIN -32768 +#define WEBRTC_SPL_WORD32_MAX (int32_t)0x7fffffff +#define WEBRTC_SPL_WORD32_MIN (int32_t)0x80000000 +#define WEBRTC_SPL_MAX_LPC_ORDER 14 +#define WEBRTC_SPL_MIN(A, B) (A < B ? A : B) // Get min value +#define WEBRTC_SPL_MAX(A, B) (A > B ? A : B) // Get max value +// TODO(kma/bjorn): For the next two macros, investigate how to correct the code +// for inputs of a = WEBRTC_SPL_WORD16_MIN or WEBRTC_SPL_WORD32_MIN. +#define WEBRTC_SPL_ABS_W16(a) (((int16_t)a >= 0) ? ((int16_t)a) : -((int16_t)a)) +#define WEBRTC_SPL_ABS_W32(a) (((int32_t)a >= 0) ? ((int32_t)a) : -((int32_t)a)) + +#define WEBRTC_SPL_MUL(a, b) ((int32_t)((int32_t)(a) * (int32_t)(b))) +#define WEBRTC_SPL_UMUL(a, b) ((uint32_t)((uint32_t)(a) * (uint32_t)(b))) +#define WEBRTC_SPL_UMUL_32_16(a, b) ((uint32_t)((uint32_t)(a) * (uint16_t)(b))) +#define WEBRTC_SPL_MUL_16_U16(a, b) ((int32_t)(int16_t)(a) * (uint16_t)(b)) + +// clang-format off +// clang-format would choose some identation +// leading to presubmit error (cpplint.py) +#ifndef WEBRTC_ARCH_ARM_V7 +// For ARMv7 platforms, these are inline functions in spl_inl_armv7.h +#ifndef MIPS32_LE +// For MIPS platforms, these are inline functions in spl_inl_mips.h +#define WEBRTC_SPL_MUL_16_16(a, b) ((int32_t)(((int16_t)(a)) * ((int16_t)(b)))) +#define WEBRTC_SPL_MUL_16_32_RSFT16(a, b) \ + (WEBRTC_SPL_MUL_16_16(a, b >> 16) + \ + ((WEBRTC_SPL_MUL_16_16(a, (b & 0xffff) >> 1) + 0x4000) >> 15)) +#endif +#endif + +#define WEBRTC_SPL_MUL_16_32_RSFT11(a, b) \ + (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 5) + \ + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x0200) >> 10)) +#define WEBRTC_SPL_MUL_16_32_RSFT14(a, b) \ + (WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 2) + \ + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x1000) >> 13)) +#define WEBRTC_SPL_MUL_16_32_RSFT15(a, b) \ + ((WEBRTC_SPL_MUL_16_16(a, (b) >> 16) * (1 << 1)) + \ + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14)) +// clang-format on + +#define WEBRTC_SPL_MUL_16_16_RSFT(a, b, c) (WEBRTC_SPL_MUL_16_16(a, b) >> (c)) + +#define WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, c) \ + ((WEBRTC_SPL_MUL_16_16(a, b) + ((int32_t)(((int32_t)1) << ((c)-1)))) >> (c)) + +// C + the 32 most significant bits of A * B +#define WEBRTC_SPL_SCALEDIFF32(A, B, C) \ + (C + (B >> 16) * A + (((uint32_t)(B & 0x0000FFFF) * A) >> 16)) + +#define WEBRTC_SPL_SAT(a, b, c) (b > a ? a : b < c ? c : b) + +// Shifting with negative numbers allowed +// Positive means left shift +#define WEBRTC_SPL_SHIFT_W32(x, c) ((c) >= 0 ? (x) * (1 << (c)) : (x) >> -(c)) + +// Shifting with negative numbers not allowed +// We cannot do casting here due to signed/unsigned problem +#define WEBRTC_SPL_LSHIFT_W32(x, c) ((x) << (c)) + +#define WEBRTC_SPL_RSHIFT_U32(x, c) ((uint32_t)(x) >> (c)) + +#define WEBRTC_SPL_RAND(a) ((int16_t)((((int16_t)a * 18816) >> 7) & 0x00007fff)) + +#ifdef __cplusplus +extern "C" { +#endif + +#define WEBRTC_SPL_MEMCPY_W16(v1, v2, length) \ + memcpy(v1, v2, (length) * sizeof(int16_t)) + +// inline functions: +#include "common_audio/signal_processing/include/spl_inl.h" + +// third party math functions +#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" + +int16_t WebRtcSpl_GetScalingSquare(int16_t* in_vector, + size_t in_vector_length, + size_t times); + +// Copy and set operations. Implementation in copy_set_operations.c. +// Descriptions at bottom of file. +void WebRtcSpl_MemSetW16(int16_t* vector, + int16_t set_value, + size_t vector_length); +void WebRtcSpl_MemSetW32(int32_t* vector, + int32_t set_value, + size_t vector_length); +void WebRtcSpl_MemCpyReversedOrder(int16_t* out_vector, + int16_t* in_vector, + size_t vector_length); +void WebRtcSpl_CopyFromEndW16(const int16_t* in_vector, + size_t in_vector_length, + size_t samples, + int16_t* out_vector); +void WebRtcSpl_ZerosArrayW16(int16_t* vector, size_t vector_length); +void WebRtcSpl_ZerosArrayW32(int32_t* vector, size_t vector_length); +// End: Copy and set operations. + +// Minimum and maximum operation functions and their pointers. +// Implementation in min_max_operations.c. + +// Returns the largest absolute value in a signed 16-bit vector. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Maximum absolute value in vector. +typedef int16_t (*MaxAbsValueW16)(const int16_t* vector, size_t length); +extern const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16; +int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length); +#if defined(WEBRTC_HAS_NEON) +int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length); +#endif +#if defined(MIPS32_LE) +int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length); +#endif + +// Returns the largest absolute value in a signed 32-bit vector. +// +// Input: +// - vector : 32-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Maximum absolute value in vector. +typedef int32_t (*MaxAbsValueW32)(const int32_t* vector, size_t length); +extern const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32; +int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length); +#if defined(WEBRTC_HAS_NEON) +int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length); +#endif +#if defined(MIPS_DSP_R1_LE) +int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length); +#endif + +// Returns the maximum value of a 16-bit vector. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Maximum sample value in `vector`. +typedef int16_t (*MaxValueW16)(const int16_t* vector, size_t length); +extern const MaxValueW16 WebRtcSpl_MaxValueW16; +int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length); +#if defined(WEBRTC_HAS_NEON) +int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length); +#endif +#if defined(MIPS32_LE) +int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length); +#endif + +// Returns the maximum value of a 32-bit vector. +// +// Input: +// - vector : 32-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Maximum sample value in `vector`. +typedef int32_t (*MaxValueW32)(const int32_t* vector, size_t length); +extern const MaxValueW32 WebRtcSpl_MaxValueW32; +int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length); +#if defined(WEBRTC_HAS_NEON) +int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length); +#endif +#if defined(MIPS32_LE) +int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length); +#endif + +// Returns the minimum value of a 16-bit vector. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Minimum sample value in `vector`. +typedef int16_t (*MinValueW16)(const int16_t* vector, size_t length); +extern const MinValueW16 WebRtcSpl_MinValueW16; +int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length); +#if defined(WEBRTC_HAS_NEON) +int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length); +#endif +#if defined(MIPS32_LE) +int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length); +#endif + +// Returns the minimum value of a 32-bit vector. +// +// Input: +// - vector : 32-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Minimum sample value in `vector`. +typedef int32_t (*MinValueW32)(const int32_t* vector, size_t length); +extern const MinValueW32 WebRtcSpl_MinValueW32; +int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length); +#if defined(WEBRTC_HAS_NEON) +int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length); +#endif +#if defined(MIPS32_LE) +int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length); +#endif + +// Returns both the minimum and maximum values of a 16-bit vector. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// Ouput: +// - max_val : Maximum sample value in `vector`. +// - min_val : Minimum sample value in `vector`. +void WebRtcSpl_MinMaxW16(const int16_t* vector, + size_t length, + int16_t* min_val, + int16_t* max_val); +#if defined(WEBRTC_HAS_NEON) +void WebRtcSpl_MinMaxW16Neon(const int16_t* vector, + size_t length, + int16_t* min_val, + int16_t* max_val); +#endif + +// Returns the vector index to the largest absolute value of a 16-bit vector. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Index to the maximum absolute value in vector. +// If there are multiple equal maxima, return the index of the +// first. -32768 will always have precedence over 32767 (despite +// -32768 presenting an int16 absolute value of 32767). +size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length); + +// Returns the element with the largest absolute value of a 16-bit vector. Note +// that this function can return a negative value. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// +// Return value : The element with the largest absolute value. Note that this +// may be a negative value. +int16_t WebRtcSpl_MaxAbsElementW16(const int16_t* vector, size_t length); + +// Returns the vector index to the maximum sample value of a 16-bit vector. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Index to the maximum value in vector (if multiple +// indexes have the maximum, return the first). +size_t WebRtcSpl_MaxIndexW16(const int16_t* vector, size_t length); + +// Returns the vector index to the maximum sample value of a 32-bit vector. +// +// Input: +// - vector : 32-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Index to the maximum value in vector (if multiple +// indexes have the maximum, return the first). +size_t WebRtcSpl_MaxIndexW32(const int32_t* vector, size_t length); + +// Returns the vector index to the minimum sample value of a 16-bit vector. +// +// Input: +// - vector : 16-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Index to the mimimum value in vector (if multiple +// indexes have the minimum, return the first). +size_t WebRtcSpl_MinIndexW16(const int16_t* vector, size_t length); + +// Returns the vector index to the minimum sample value of a 32-bit vector. +// +// Input: +// - vector : 32-bit input vector. +// - length : Number of samples in vector. +// +// Return value : Index to the mimimum value in vector (if multiple +// indexes have the minimum, return the first). +size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length); + +// End: Minimum and maximum operations. + +// Vector scaling operations. Implementation in vector_scaling_operations.c. +// Description at bottom of file. +void WebRtcSpl_VectorBitShiftW16(int16_t* out_vector, + size_t vector_length, + const int16_t* in_vector, + int16_t right_shifts); +void WebRtcSpl_VectorBitShiftW32(int32_t* out_vector, + size_t vector_length, + const int32_t* in_vector, + int16_t right_shifts); +void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out_vector, + size_t vector_length, + const int32_t* in_vector, + int right_shifts); +void WebRtcSpl_ScaleVector(const int16_t* in_vector, + int16_t* out_vector, + int16_t gain, + size_t vector_length, + int16_t right_shifts); +void WebRtcSpl_ScaleVectorWithSat(const int16_t* in_vector, + int16_t* out_vector, + int16_t gain, + size_t vector_length, + int16_t right_shifts); +void WebRtcSpl_ScaleAndAddVectors(const int16_t* in_vector1, + int16_t gain1, + int right_shifts1, + const int16_t* in_vector2, + int16_t gain2, + int right_shifts2, + int16_t* out_vector, + size_t vector_length); + +// The functions (with related pointer) perform the vector operation: +// out_vector[k] = ((scale1 * in_vector1[k]) + (scale2 * in_vector2[k]) +// + round_value) >> right_shifts, +// where round_value = (1 << right_shifts) >> 1. +// +// Input: +// - in_vector1 : Input vector 1 +// - in_vector1_scale : Gain to be used for vector 1 +// - in_vector2 : Input vector 2 +// - in_vector2_scale : Gain to be used for vector 2 +// - right_shifts : Number of right bit shifts to be applied +// - length : Number of elements in the input vectors +// +// Output: +// - out_vector : Output vector +// Return value : 0 if OK, -1 if (in_vector1 == null +// || in_vector2 == null || out_vector == null +// || length <= 0 || right_shift < 0). +typedef int (*ScaleAndAddVectorsWithRound)(const int16_t* in_vector1, + int16_t in_vector1_scale, + const int16_t* in_vector2, + int16_t in_vector2_scale, + int right_shifts, + int16_t* out_vector, + size_t length); +extern const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound; +int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1, + int16_t in_vector1_scale, + const int16_t* in_vector2, + int16_t in_vector2_scale, + int right_shifts, + int16_t* out_vector, + size_t length); +#if defined(MIPS_DSP_R1_LE) +int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1, + int16_t in_vector1_scale, + const int16_t* in_vector2, + int16_t in_vector2_scale, + int right_shifts, + int16_t* out_vector, + size_t length); +#endif +// End: Vector scaling operations. + +// iLBC specific functions. Implementations in ilbc_specific_functions.c. +// Description at bottom of file. +void WebRtcSpl_ReverseOrderMultArrayElements(int16_t* out_vector, + const int16_t* in_vector, + const int16_t* window, + size_t vector_length, + int16_t right_shifts); +void WebRtcSpl_ElementwiseVectorMult(int16_t* out_vector, + const int16_t* in_vector, + const int16_t* window, + size_t vector_length, + int16_t right_shifts); +void WebRtcSpl_AddVectorsAndShift(int16_t* out_vector, + const int16_t* in_vector1, + const int16_t* in_vector2, + size_t vector_length, + int16_t right_shifts); +void WebRtcSpl_AddAffineVectorToVector(int16_t* out_vector, + const int16_t* in_vector, + int16_t gain, + int32_t add_constant, + int16_t right_shifts, + size_t vector_length); +void WebRtcSpl_AffineTransformVector(int16_t* out_vector, + const int16_t* in_vector, + int16_t gain, + int32_t add_constant, + int16_t right_shifts, + size_t vector_length); +// End: iLBC specific functions. + +// Signal processing operations. + +// A 32-bit fix-point implementation of auto-correlation computation +// +// Input: +// - in_vector : Vector to calculate autocorrelation upon +// - in_vector_length : Length (in samples) of `vector` +// - order : The order up to which the autocorrelation should be +// calculated +// +// Output: +// - result : auto-correlation values (values should be seen +// relative to each other since the absolute values +// might have been down shifted to avoid overflow) +// +// - scale : The number of left shifts required to obtain the +// auto-correlation in Q0 +// +// Return value : Number of samples in `result`, i.e. (order+1) +size_t WebRtcSpl_AutoCorrelation(const int16_t* in_vector, + size_t in_vector_length, + size_t order, + int32_t* result, + int* scale); + +// A 32-bit fix-point implementation of the Levinson-Durbin algorithm that +// does NOT use the 64 bit class +// +// Input: +// - auto_corr : Vector with autocorrelation values of length >= `order`+1 +// - order : The LPC filter order (support up to order 20) +// +// Output: +// - lpc_coef : lpc_coef[0..order] LPC coefficients in Q12 +// - refl_coef : refl_coef[0...order-1]| Reflection coefficients in Q15 +// +// Return value : 1 for stable 0 for unstable +int16_t WebRtcSpl_LevinsonDurbin(const int32_t* auto_corr, + int16_t* lpc_coef, + int16_t* refl_coef, + size_t order); + +// Converts reflection coefficients `refl_coef` to LPC coefficients `lpc_coef`. +// This version is a 16 bit operation. +// +// NOTE: The 16 bit refl_coef -> lpc_coef conversion might result in a +// "slightly unstable" filter (i.e., a pole just outside the unit circle) in +// "rare" cases even if the reflection coefficients are stable. +// +// Input: +// - refl_coef : Reflection coefficients in Q15 that should be converted +// to LPC coefficients +// - use_order : Number of coefficients in `refl_coef` +// +// Output: +// - lpc_coef : LPC coefficients in Q12 +void WebRtcSpl_ReflCoefToLpc(const int16_t* refl_coef, + int use_order, + int16_t* lpc_coef); + +// Converts LPC coefficients `lpc_coef` to reflection coefficients `refl_coef`. +// This version is a 16 bit operation. +// The conversion is implemented by the step-down algorithm. +// +// Input: +// - lpc_coef : LPC coefficients in Q12, that should be converted to +// reflection coefficients +// - use_order : Number of coefficients in `lpc_coef` +// +// Output: +// - refl_coef : Reflection coefficients in Q15. +void WebRtcSpl_LpcToReflCoef(int16_t* lpc_coef, + int use_order, + int16_t* refl_coef); + +// Calculates reflection coefficients (16 bit) from auto-correlation values +// +// Input: +// - auto_corr : Auto-correlation values +// - use_order : Number of coefficients wanted be calculated +// +// Output: +// - refl_coef : Reflection coefficients in Q15. +void WebRtcSpl_AutoCorrToReflCoef(const int32_t* auto_corr, + int use_order, + int16_t* refl_coef); + +// The functions (with related pointer) calculate the cross-correlation between +// two sequences `seq1` and `seq2`. +// `seq1` is fixed and `seq2` slides as the pointer is increased with the +// amount `step_seq2`. Note the arguments should obey the relationship: +// `dim_seq` - 1 + `step_seq2` * (`dim_cross_correlation` - 1) < +// buffer size of `seq2` +// +// Input: +// - seq1 : First sequence (fixed throughout the correlation) +// - seq2 : Second sequence (slides `step_vector2` for each +// new correlation) +// - dim_seq : Number of samples to use in the cross-correlation +// - dim_cross_correlation : Number of cross-correlations to calculate (the +// start position for `vector2` is updated for each +// new one) +// - right_shifts : Number of right bit shifts to use. This will +// become the output Q-domain. +// - step_seq2 : How many (positive or negative) steps the +// `vector2` pointer should be updated for each new +// cross-correlation value. +// +// Output: +// - cross_correlation : The cross-correlation in Q(-right_shifts) +typedef void (*CrossCorrelation)(int32_t* cross_correlation, + const int16_t* seq1, + const int16_t* seq2, + size_t dim_seq, + size_t dim_cross_correlation, + int right_shifts, + int step_seq2); +extern const CrossCorrelation WebRtcSpl_CrossCorrelation; +void WebRtcSpl_CrossCorrelationC(int32_t* cross_correlation, + const int16_t* seq1, + const int16_t* seq2, + size_t dim_seq, + size_t dim_cross_correlation, + int right_shifts, + int step_seq2); +#if defined(WEBRTC_HAS_NEON) +void WebRtcSpl_CrossCorrelationNeon(int32_t* cross_correlation, + const int16_t* seq1, + const int16_t* seq2, + size_t dim_seq, + size_t dim_cross_correlation, + int right_shifts, + int step_seq2); +#endif +#if defined(MIPS32_LE) +void WebRtcSpl_CrossCorrelation_mips(int32_t* cross_correlation, + const int16_t* seq1, + const int16_t* seq2, + size_t dim_seq, + size_t dim_cross_correlation, + int right_shifts, + int step_seq2); +#endif + +// Creates (the first half of) a Hanning window. Size must be at least 1 and +// at most 512. +// +// Input: +// - size : Length of the requested Hanning window (1 to 512) +// +// Output: +// - window : Hanning vector in Q14. +void WebRtcSpl_GetHanningWindow(int16_t* window, size_t size); + +// Calculates y[k] = sqrt(1 - x[k]^2) for each element of the input vector +// `in_vector`. Input and output values are in Q15. +// +// Inputs: +// - in_vector : Values to calculate sqrt(1 - x^2) of +// - vector_length : Length of vector `in_vector` +// +// Output: +// - out_vector : Output values in Q15 +void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t* in_vector, + size_t vector_length, + int16_t* out_vector); +// End: Signal processing operations. + +// Randomization functions. Implementations collected in +// randomization_functions.c and descriptions at bottom of this file. +int16_t WebRtcSpl_RandU(uint32_t* seed); +int16_t WebRtcSpl_RandN(uint32_t* seed); +int16_t WebRtcSpl_RandUArray(int16_t* vector, + int16_t vector_length, + uint32_t* seed); +// End: Randomization functions. + +// Math functions +int32_t WebRtcSpl_Sqrt(int32_t value); + +// Divisions. Implementations collected in division_operations.c and +// descriptions at bottom of this file. +uint32_t WebRtcSpl_DivU32U16(uint32_t num, uint16_t den); +int32_t WebRtcSpl_DivW32W16(int32_t num, int16_t den); +int16_t WebRtcSpl_DivW32W16ResW16(int32_t num, int16_t den); +int32_t WebRtcSpl_DivResultInQ31(int32_t num, int32_t den); +int32_t WebRtcSpl_DivW32HiLow(int32_t num, int16_t den_hi, int16_t den_low); +// End: Divisions. + +int32_t WebRtcSpl_Energy(int16_t* vector, + size_t vector_length, + int* scale_factor); + +// Filter operations. +size_t WebRtcSpl_FilterAR(const int16_t* ar_coef, + size_t ar_coef_length, + const int16_t* in_vector, + size_t in_vector_length, + int16_t* filter_state, + size_t filter_state_length, + int16_t* filter_state_low, + size_t filter_state_low_length, + int16_t* out_vector, + int16_t* out_vector_low, + size_t out_vector_low_length); + +// WebRtcSpl_FilterMAFastQ12(...) +// +// Performs a MA filtering on a vector in Q12 +// +// Input: +// - in_vector : Input samples (state in positions +// in_vector[-order] .. in_vector[-1]) +// - ma_coef : Filter coefficients (in Q12) +// - ma_coef_length : Number of B coefficients (order+1) +// - vector_length : Number of samples to be filtered +// +// Output: +// - out_vector : Filtered samples +// +void WebRtcSpl_FilterMAFastQ12(const int16_t* in_vector, + int16_t* out_vector, + const int16_t* ma_coef, + size_t ma_coef_length, + size_t vector_length); + +// Performs a AR filtering on a vector in Q12 +// Input: +// - data_in : Input samples +// - data_out : State information in positions +// data_out[-order] .. data_out[-1] +// - coefficients : Filter coefficients (in Q12) +// - coefficients_length: Number of coefficients (order+1) +// - data_length : Number of samples to be filtered +// Output: +// - data_out : Filtered samples +void WebRtcSpl_FilterARFastQ12(const int16_t* data_in, + int16_t* data_out, + const int16_t* __restrict coefficients, + size_t coefficients_length, + size_t data_length); + +// The functions (with related pointer) perform a MA down sampling filter +// on a vector. +// Input: +// - data_in : Input samples (state in positions +// data_in[-order] .. data_in[-1]) +// - data_in_length : Number of samples in `data_in` to be filtered. +// This must be at least +// `delay` + `factor`*(`out_vector_length`-1) + 1) +// - data_out_length : Number of down sampled samples desired +// - coefficients : Filter coefficients (in Q12) +// - coefficients_length: Number of coefficients (order+1) +// - factor : Decimation factor +// - delay : Delay of filter (compensated for in out_vector) +// Output: +// - data_out : Filtered samples +// Return value : 0 if OK, -1 if `in_vector` is too short +typedef int (*DownsampleFast)(const int16_t* data_in, + size_t data_in_length, + int16_t* data_out, + size_t data_out_length, + const int16_t* __restrict coefficients, + size_t coefficients_length, + int factor, + size_t delay); +extern const DownsampleFast WebRtcSpl_DownsampleFast; +int WebRtcSpl_DownsampleFastC(const int16_t* data_in, + size_t data_in_length, + int16_t* data_out, + size_t data_out_length, + const int16_t* __restrict coefficients, + size_t coefficients_length, + int factor, + size_t delay); +#if defined(WEBRTC_HAS_NEON) +int WebRtcSpl_DownsampleFastNeon(const int16_t* data_in, + size_t data_in_length, + int16_t* data_out, + size_t data_out_length, + const int16_t* __restrict coefficients, + size_t coefficients_length, + int factor, + size_t delay); +#endif +#if defined(MIPS32_LE) +int WebRtcSpl_DownsampleFast_mips(const int16_t* data_in, + size_t data_in_length, + int16_t* data_out, + size_t data_out_length, + const int16_t* __restrict coefficients, + size_t coefficients_length, + int factor, + size_t delay); +#endif + +// End: Filter operations. + +// FFT operations + +int WebRtcSpl_ComplexFFT(int16_t vector[], int stages, int mode); +int WebRtcSpl_ComplexIFFT(int16_t vector[], int stages, int mode); + +// Treat a 16-bit complex data buffer `complex_data` as an array of 32-bit +// values, and swap elements whose indexes are bit-reverses of each other. +// +// Input: +// - complex_data : Complex data buffer containing 2^`stages` real +// elements interleaved with 2^`stages` imaginary +// elements: [Re Im Re Im Re Im....] +// - stages : Number of FFT stages. Must be at least 3 and at most +// 10, since the table WebRtcSpl_kSinTable1024[] is 1024 +// elements long. +// +// Output: +// - complex_data : The complex data buffer. + +void WebRtcSpl_ComplexBitReverse(int16_t* __restrict complex_data, int stages); + +// End: FFT operations + +/************************************************************ + * + * RESAMPLING FUNCTIONS AND THEIR STRUCTS ARE DEFINED BELOW + * + ************************************************************/ + +/******************************************************************* + * resample.c + * + * Includes the following resampling combinations + * 22 kHz -> 16 kHz + * 16 kHz -> 22 kHz + * 22 kHz -> 8 kHz + * 8 kHz -> 22 kHz + * + ******************************************************************/ + +// state structure for 22 -> 16 resampler +typedef struct { + int32_t S_22_44[8]; + int32_t S_44_32[8]; + int32_t S_32_16[8]; +} WebRtcSpl_State22khzTo16khz; + +void WebRtcSpl_Resample22khzTo16khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State22khzTo16khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state); + +// state structure for 16 -> 22 resampler +typedef struct { + int32_t S_16_32[8]; + int32_t S_32_22[8]; +} WebRtcSpl_State16khzTo22khz; + +void WebRtcSpl_Resample16khzTo22khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State16khzTo22khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state); + +// state structure for 22 -> 8 resampler +typedef struct { + int32_t S_22_22[16]; + int32_t S_22_16[8]; + int32_t S_16_8[8]; +} WebRtcSpl_State22khzTo8khz; + +void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State22khzTo8khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state); + +// state structure for 8 -> 22 resampler +typedef struct { + int32_t S_8_16[8]; + int32_t S_16_11[8]; + int32_t S_11_22[8]; +} WebRtcSpl_State8khzTo22khz; + +void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State8khzTo22khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state); + +/******************************************************************* + * resample_fractional.c + * Functions for internal use in the other resample functions + * + * Includes the following resampling combinations + * 48 kHz -> 32 kHz + * 32 kHz -> 24 kHz + * 44 kHz -> 32 kHz + * + ******************************************************************/ + +void WebRtcSpl_Resample48khzTo32khz(const int32_t* In, int32_t* Out, size_t K); + +void WebRtcSpl_Resample32khzTo24khz(const int32_t* In, int32_t* Out, size_t K); + +void WebRtcSpl_Resample44khzTo32khz(const int32_t* In, int32_t* Out, size_t K); + +/******************************************************************* + * resample_48khz.c + * + * Includes the following resampling combinations + * 48 kHz -> 16 kHz + * 16 kHz -> 48 kHz + * 48 kHz -> 8 kHz + * 8 kHz -> 48 kHz + * + ******************************************************************/ + +typedef struct { + int32_t S_48_48[16]; + int32_t S_48_32[8]; + int32_t S_32_16[8]; +} WebRtcSpl_State48khzTo16khz; + +void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State48khzTo16khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state); + +typedef struct { + int32_t S_16_32[8]; + int32_t S_32_24[8]; + int32_t S_24_48[8]; +} WebRtcSpl_State16khzTo48khz; + +void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State16khzTo48khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state); + +typedef struct { + int32_t S_48_24[8]; + int32_t S_24_24[16]; + int32_t S_24_16[8]; + int32_t S_16_8[8]; +} WebRtcSpl_State48khzTo8khz; + +void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State48khzTo8khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state); + +typedef struct { + int32_t S_8_16[8]; + int32_t S_16_12[8]; + int32_t S_12_24[8]; + int32_t S_24_48[8]; +} WebRtcSpl_State8khzTo48khz; + +void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, + int16_t* out, + WebRtcSpl_State8khzTo48khz* state, + int32_t* tmpmem); + +void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state); + +/******************************************************************* + * resample_by_2.c + * + * Includes down and up sampling by a factor of two. + * + ******************************************************************/ + +void WebRtcSpl_DownsampleBy2(const int16_t* in, + size_t len, + int16_t* out, + int32_t* filtState); + +void WebRtcSpl_UpsampleBy2(const int16_t* in, + size_t len, + int16_t* out, + int32_t* filtState); + +/************************************************************ + * END OF RESAMPLING FUNCTIONS + ************************************************************/ +void WebRtcSpl_AnalysisQMF(const int16_t* in_data, + size_t in_data_length, + int16_t* low_band, + int16_t* high_band, + int32_t* filter_state1, + int32_t* filter_state2); +void WebRtcSpl_SynthesisQMF(const int16_t* low_band, + const int16_t* high_band, + size_t band_length, + int16_t* out_data, + int32_t* filter_state1, + int32_t* filter_state2); + +#ifdef __cplusplus +} +#endif // __cplusplus +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SIGNAL_PROCESSING_LIBRARY_H_ + +// +// WebRtcSpl_AddSatW16(...) +// WebRtcSpl_AddSatW32(...) +// +// Returns the result of a saturated 16-bit, respectively 32-bit, addition of +// the numbers specified by the `var1` and `var2` parameters. +// +// Input: +// - var1 : Input variable 1 +// - var2 : Input variable 2 +// +// Return value : Added and saturated value +// + +// +// WebRtcSpl_SubSatW16(...) +// WebRtcSpl_SubSatW32(...) +// +// Returns the result of a saturated 16-bit, respectively 32-bit, subtraction +// of the numbers specified by the `var1` and `var2` parameters. +// +// Input: +// - var1 : Input variable 1 +// - var2 : Input variable 2 +// +// Returned value : Subtracted and saturated value +// + +// +// WebRtcSpl_GetSizeInBits(...) +// +// Returns the # of bits that are needed at the most to represent the number +// specified by the `value` parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bits needed to represent `value` +// + +// +// WebRtcSpl_NormW32(...) +// +// Norm returns the # of left shifts required to 32-bit normalize the 32-bit +// signed number specified by the `value` parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bit shifts needed to 32-bit normalize `value` +// + +// +// WebRtcSpl_NormW16(...) +// +// Norm returns the # of left shifts required to 16-bit normalize the 16-bit +// signed number specified by the `value` parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bit shifts needed to 32-bit normalize `value` +// + +// +// WebRtcSpl_NormU32(...) +// +// Norm returns the # of left shifts required to 32-bit normalize the unsigned +// 32-bit number specified by the `value` parameter. +// +// Input: +// - value : Input value +// +// Return value : Number of bit shifts needed to 32-bit normalize `value` +// + +// +// WebRtcSpl_GetScalingSquare(...) +// +// Returns the # of bits required to scale the samples specified in the +// `in_vector` parameter so that, if the squares of the samples are added the +// # of times specified by the `times` parameter, the 32-bit addition will not +// overflow (result in int32_t). +// +// Input: +// - in_vector : Input vector to check scaling on +// - in_vector_length : Samples in `in_vector` +// - times : Number of additions to be performed +// +// Return value : Number of right bit shifts needed to avoid +// overflow in the addition calculation +// + +// +// WebRtcSpl_MemSetW16(...) +// +// Sets all the values in the int16_t vector `vector` of length +// `vector_length` to the specified value `set_value` +// +// Input: +// - vector : Pointer to the int16_t vector +// - set_value : Value specified +// - vector_length : Length of vector +// + +// +// WebRtcSpl_MemSetW32(...) +// +// Sets all the values in the int32_t vector `vector` of length +// `vector_length` to the specified value `set_value` +// +// Input: +// - vector : Pointer to the int16_t vector +// - set_value : Value specified +// - vector_length : Length of vector +// + +// +// WebRtcSpl_MemCpyReversedOrder(...) +// +// Copies all the values from the source int16_t vector `in_vector` to a +// destination int16_t vector `out_vector`. It is done in reversed order, +// meaning that the first sample of `in_vector` is copied to the last sample of +// the `out_vector`. The procedure continues until the last sample of +// `in_vector` has been copied to the first sample of `out_vector`. This +// creates a reversed vector. Used in e.g. prediction in iLBC. +// +// Input: +// - in_vector : Pointer to the first sample in a int16_t vector +// of length `length` +// - vector_length : Number of elements to copy +// +// Output: +// - out_vector : Pointer to the last sample in a int16_t vector +// of length `length` +// + +// +// WebRtcSpl_CopyFromEndW16(...) +// +// Copies the rightmost `samples` of `in_vector` (of length `in_vector_length`) +// to the vector `out_vector`. +// +// Input: +// - in_vector : Input vector +// - in_vector_length : Number of samples in `in_vector` +// - samples : Number of samples to extract (from right side) +// from `in_vector` +// +// Output: +// - out_vector : Vector with the requested samples +// + +// +// WebRtcSpl_ZerosArrayW16(...) +// WebRtcSpl_ZerosArrayW32(...) +// +// Inserts the value "zero" in all positions of a w16 and a w32 vector +// respectively. +// +// Input: +// - vector_length : Number of samples in vector +// +// Output: +// - vector : Vector containing all zeros +// + +// +// WebRtcSpl_VectorBitShiftW16(...) +// WebRtcSpl_VectorBitShiftW32(...) +// +// Bit shifts all the values in a vector up or downwards. Different calls for +// int16_t and int32_t vectors respectively. +// +// Input: +// - vector_length : Length of vector +// - in_vector : Pointer to the vector that should be bit shifted +// - right_shifts : Number of right bit shifts (negative value gives left +// shifts) +// +// Output: +// - out_vector : Pointer to the result vector (can be the same as +// `in_vector`) +// + +// +// WebRtcSpl_VectorBitShiftW32ToW16(...) +// +// Bit shifts all the values in a int32_t vector up or downwards and +// stores the result as an int16_t vector. The function will saturate the +// signal if needed, before storing in the output vector. +// +// Input: +// - vector_length : Length of vector +// - in_vector : Pointer to the vector that should be bit shifted +// - right_shifts : Number of right bit shifts (negative value gives left +// shifts) +// +// Output: +// - out_vector : Pointer to the result vector (can be the same as +// `in_vector`) +// + +// +// WebRtcSpl_ScaleVector(...) +// +// Performs the vector operation: +// out_vector[k] = (gain*in_vector[k])>>right_shifts +// +// Input: +// - in_vector : Input vector +// - gain : Scaling gain +// - vector_length : Elements in the `in_vector` +// - right_shifts : Number of right bit shifts applied +// +// Output: +// - out_vector : Output vector (can be the same as `in_vector`) +// + +// +// WebRtcSpl_ScaleVectorWithSat(...) +// +// Performs the vector operation: +// out_vector[k] = SATURATE( (gain*in_vector[k])>>right_shifts ) +// +// Input: +// - in_vector : Input vector +// - gain : Scaling gain +// - vector_length : Elements in the `in_vector` +// - right_shifts : Number of right bit shifts applied +// +// Output: +// - out_vector : Output vector (can be the same as `in_vector`) +// + +// +// WebRtcSpl_ScaleAndAddVectors(...) +// +// Performs the vector operation: +// out_vector[k] = (gain1*in_vector1[k])>>right_shifts1 +// + (gain2*in_vector2[k])>>right_shifts2 +// +// Input: +// - in_vector1 : Input vector 1 +// - gain1 : Gain to be used for vector 1 +// - right_shifts1 : Right bit shift to be used for vector 1 +// - in_vector2 : Input vector 2 +// - gain2 : Gain to be used for vector 2 +// - right_shifts2 : Right bit shift to be used for vector 2 +// - vector_length : Elements in the input vectors +// +// Output: +// - out_vector : Output vector +// + +// +// WebRtcSpl_ReverseOrderMultArrayElements(...) +// +// Performs the vector operation: +// out_vector[n] = (in_vector[n]*window[-n])>>right_shifts +// +// Input: +// - in_vector : Input vector +// - window : Window vector (should be reversed). The pointer +// should be set to the last value in the vector +// - right_shifts : Number of right bit shift to be applied after the +// multiplication +// - vector_length : Number of elements in `in_vector` +// +// Output: +// - out_vector : Output vector (can be same as `in_vector`) +// + +// +// WebRtcSpl_ElementwiseVectorMult(...) +// +// Performs the vector operation: +// out_vector[n] = (in_vector[n]*window[n])>>right_shifts +// +// Input: +// - in_vector : Input vector +// - window : Window vector. +// - right_shifts : Number of right bit shift to be applied after the +// multiplication +// - vector_length : Number of elements in `in_vector` +// +// Output: +// - out_vector : Output vector (can be same as `in_vector`) +// + +// +// WebRtcSpl_AddVectorsAndShift(...) +// +// Performs the vector operation: +// out_vector[k] = (in_vector1[k] + in_vector2[k])>>right_shifts +// +// Input: +// - in_vector1 : Input vector 1 +// - in_vector2 : Input vector 2 +// - right_shifts : Number of right bit shift to be applied after the +// multiplication +// - vector_length : Number of elements in `in_vector1` and `in_vector2` +// +// Output: +// - out_vector : Output vector (can be same as `in_vector1`) +// + +// +// WebRtcSpl_AddAffineVectorToVector(...) +// +// Adds an affine transformed vector to another vector `out_vector`, i.e, +// performs +// out_vector[k] += (in_vector[k]*gain+add_constant)>>right_shifts +// +// Input: +// - in_vector : Input vector +// - gain : Gain value, used to multiply the in vector with +// - add_constant : Constant value to add (usually 1<<(right_shifts-1), +// but others can be used as well +// - right_shifts : Number of right bit shifts (0-16) +// - vector_length : Number of samples in `in_vector` and `out_vector` +// +// Output: +// - out_vector : Vector with the output +// + +// +// WebRtcSpl_AffineTransformVector(...) +// +// Affine transforms a vector, i.e, performs +// out_vector[k] = (in_vector[k]*gain+add_constant)>>right_shifts +// +// Input: +// - in_vector : Input vector +// - gain : Gain value, used to multiply the in vector with +// - add_constant : Constant value to add (usually 1<<(right_shifts-1), +// but others can be used as well +// - right_shifts : Number of right bit shifts (0-16) +// - vector_length : Number of samples in `in_vector` and `out_vector` +// +// Output: +// - out_vector : Vector with the output +// + +// +// WebRtcSpl_IncreaseSeed(...) +// +// Increases the seed (and returns the new value) +// +// Input: +// - seed : Seed for random calculation +// +// Output: +// - seed : Updated seed value +// +// Return value : The new seed value +// + +// +// WebRtcSpl_RandU(...) +// +// Produces a uniformly distributed value in the int16_t range +// +// Input: +// - seed : Seed for random calculation +// +// Output: +// - seed : Updated seed value +// +// Return value : Uniformly distributed value in the range +// [Word16_MIN...Word16_MAX] +// + +// +// WebRtcSpl_RandN(...) +// +// Produces a normal distributed value in the int16_t range +// +// Input: +// - seed : Seed for random calculation +// +// Output: +// - seed : Updated seed value +// +// Return value : N(0,1) value in the Q13 domain +// + +// +// WebRtcSpl_RandUArray(...) +// +// Produces a uniformly distributed vector with elements in the int16_t +// range +// +// Input: +// - vector_length : Samples wanted in the vector +// - seed : Seed for random calculation +// +// Output: +// - vector : Vector with the uniform values +// - seed : Updated seed value +// +// Return value : Number of samples in vector, i.e., `vector_length` +// + +// +// WebRtcSpl_Sqrt(...) +// +// Returns the square root of the input value `value`. The precision of this +// function is integer precision, i.e., sqrt(8) gives 2 as answer. +// If `value` is a negative number then 0 is returned. +// +// Algorithm: +// +// A sixth order Taylor Series expansion is used here to compute the square +// root of a number y^0.5 = (1+x)^0.5 +// where +// x = y-1 +// = 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5) +// 0.5 <= x < 1 +// +// Input: +// - value : Value to calculate sqrt of +// +// Return value : Result of the sqrt calculation +// + +// +// WebRtcSpl_DivU32U16(...) +// +// Divides a uint32_t `num` by a uint16_t `den`. +// +// If `den`==0, (uint32_t)0xFFFFFFFF is returned. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division (as a uint32_t), i.e., the +// integer part of num/den. +// + +// +// WebRtcSpl_DivW32W16(...) +// +// Divides a int32_t `num` by a int16_t `den`. +// +// If `den`==0, (int32_t)0x7FFFFFFF is returned. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division (as a int32_t), i.e., the +// integer part of num/den. +// + +// +// WebRtcSpl_DivW32W16ResW16(...) +// +// Divides a int32_t `num` by a int16_t `den`, assuming that the +// result is less than 32768, otherwise an unpredictable result will occur. +// +// If `den`==0, (int16_t)0x7FFF is returned. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division (as a int16_t), i.e., the +// integer part of num/den. +// + +// +// WebRtcSpl_DivResultInQ31(...) +// +// Divides a int32_t `num` by a int16_t `den`, assuming that the +// absolute value of the denominator is larger than the numerator, otherwise +// an unpredictable result will occur. +// +// Input: +// - num : Numerator +// - den : Denominator +// +// Return value : Result of the division in Q31. +// + +// +// WebRtcSpl_DivW32HiLow(...) +// +// Divides a int32_t `num` by a denominator in hi, low format. The +// absolute value of the denominator has to be larger (or equal to) the +// numerator. +// +// Input: +// - num : Numerator +// - den_hi : High part of denominator +// - den_low : Low part of denominator +// +// Return value : Divided value in Q31 +// + +// +// WebRtcSpl_Energy(...) +// +// Calculates the energy of a vector +// +// Input: +// - vector : Vector which the energy should be calculated on +// - vector_length : Number of samples in vector +// +// Output: +// - scale_factor : Number of left bit shifts needed to get the physical +// energy value, i.e, to get the Q0 value +// +// Return value : Energy value in Q(-`scale_factor`) +// + +// +// WebRtcSpl_FilterAR(...) +// +// Performs a 32-bit AR filtering on a vector in Q12 +// +// Input: +// - ar_coef : AR-coefficient vector (values in Q12), +// ar_coef[0] must be 4096. +// - ar_coef_length : Number of coefficients in `ar_coef`. +// - in_vector : Vector to be filtered. +// - in_vector_length : Number of samples in `in_vector`. +// - filter_state : Current state (higher part) of the filter. +// - filter_state_length : Length (in samples) of `filter_state`. +// - filter_state_low : Current state (lower part) of the filter. +// - filter_state_low_length : Length (in samples) of `filter_state_low`. +// - out_vector_low_length : Maximum length (in samples) of +// `out_vector_low`. +// +// Output: +// - filter_state : Updated state (upper part) vector. +// - filter_state_low : Updated state (lower part) vector. +// - out_vector : Vector containing the upper part of the +// filtered values. +// - out_vector_low : Vector containing the lower part of the +// filtered values. +// +// Return value : Number of samples in the `out_vector`. +// + +// +// WebRtcSpl_ComplexIFFT(...) +// +// Complex Inverse FFT +// +// Computes an inverse complex 2^`stages`-point FFT on the input vector, which +// is in bit-reversed order. The original content of the vector is destroyed in +// the process, since the input is overwritten by the output, normal-ordered, +// FFT vector. With X as the input complex vector, y as the output complex +// vector and with M = 2^`stages`, the following is computed: +// +// M-1 +// y(k) = sum[X(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] +// i=0 +// +// The implementations are optimized for speed, not for code size. It uses the +// decimation-in-time algorithm with radix-2 butterfly technique. +// +// Input: +// - vector : In pointer to complex vector containing 2^`stages` +// real elements interleaved with 2^`stages` imaginary +// elements. +// [ReImReImReIm....] +// The elements are in Q(-scale) domain, see more on Return +// Value below. +// +// - stages : Number of FFT stages. Must be at least 3 and at most 10, +// since the table WebRtcSpl_kSinTable1024[] is 1024 +// elements long. +// +// - mode : This parameter gives the user to choose how the FFT +// should work. +// mode==0: Low-complexity and Low-accuracy mode +// mode==1: High-complexity and High-accuracy mode +// +// Output: +// - vector : Out pointer to the FFT vector (the same as input). +// +// Return Value : The scale value that tells the number of left bit shifts +// that the elements in the `vector` should be shifted with +// in order to get Q0 values, i.e. the physically correct +// values. The scale parameter is always 0 or positive, +// except if N>1024 (`stages`>10), which returns a scale +// value of -1, indicating error. +// + +// +// WebRtcSpl_ComplexFFT(...) +// +// Complex FFT +// +// Computes a complex 2^`stages`-point FFT on the input vector, which is in +// bit-reversed order. The original content of the vector is destroyed in +// the process, since the input is overwritten by the output, normal-ordered, +// FFT vector. With x as the input complex vector, Y as the output complex +// vector and with M = 2^`stages`, the following is computed: +// +// M-1 +// Y(k) = 1/M * sum[x(i)*[cos(2*pi*i*k/M) + j*sin(2*pi*i*k/M)]] +// i=0 +// +// The implementations are optimized for speed, not for code size. It uses the +// decimation-in-time algorithm with radix-2 butterfly technique. +// +// This routine prevents overflow by scaling by 2 before each FFT stage. This is +// a fixed scaling, for proper normalization - there will be log2(n) passes, so +// this results in an overall factor of 1/n, distributed to maximize arithmetic +// accuracy. +// +// Input: +// - vector : In pointer to complex vector containing 2^`stages` real +// elements interleaved with 2^`stages` imaginary elements. +// [ReImReImReIm....] +// The output is in the Q0 domain. +// +// - stages : Number of FFT stages. Must be at least 3 and at most 10, +// since the table WebRtcSpl_kSinTable1024[] is 1024 +// elements long. +// +// - mode : This parameter gives the user to choose how the FFT +// should work. +// mode==0: Low-complexity and Low-accuracy mode +// mode==1: High-complexity and High-accuracy mode +// +// Output: +// - vector : The output FFT vector is in the Q0 domain. +// +// Return value : The scale parameter is always 0, except if N>1024, +// which returns a scale value of -1, indicating error. +// + +// +// WebRtcSpl_AnalysisQMF(...) +// +// Splits a 0-2*F Hz signal into two sub bands: 0-F Hz and F-2*F Hz. The +// current version has F = 8000, therefore, a super-wideband audio signal is +// split to lower-band 0-8 kHz and upper-band 8-16 kHz. +// +// Input: +// - in_data : Wide band speech signal, 320 samples (10 ms) +// +// Input & Output: +// - filter_state1 : Filter state for first All-pass filter +// - filter_state2 : Filter state for second All-pass filter +// +// Output: +// - low_band : Lower-band signal 0-8 kHz band, 160 samples (10 ms) +// - high_band : Upper-band signal 8-16 kHz band (flipped in frequency +// domain), 160 samples (10 ms) +// + +// +// WebRtcSpl_SynthesisQMF(...) +// +// Combines the two sub bands (0-F and F-2*F Hz) into a signal of 0-2*F +// Hz, (current version has F = 8000 Hz). So the filter combines lower-band +// (0-8 kHz) and upper-band (8-16 kHz) channels to obtain super-wideband 0-16 +// kHz audio. +// +// Input: +// - low_band : The signal with the 0-8 kHz band, 160 samples (10 ms) +// - high_band : The signal with the 8-16 kHz band, 160 samples (10 ms) +// +// Input & Output: +// - filter_state1 : Filter state for first All-pass filter +// - filter_state2 : Filter state for second All-pass filter +// +// Output: +// - out_data : Super-wideband speech signal, 0-16 kHz +// + +// int16_t WebRtcSpl_SatW32ToW16(...) +// +// This function saturates a 32-bit word into a 16-bit word. +// +// Input: +// - value32 : The value of a 32-bit word. +// +// Output: +// - out16 : the saturated 16-bit word. +// + +// int32_t WebRtc_MulAccumW16(...) +// +// This function multiply a 16-bit word by a 16-bit word, and accumulate this +// value to a 32-bit integer. +// +// Input: +// - a : The value of the first 16-bit word. +// - b : The value of the second 16-bit word. +// - c : The value of an 32-bit integer. +// +// Return Value: The value of a * b + c. +// diff --git a/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl.h b/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl.h new file mode 100644 index 0000000000..2b0995886a --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl.h @@ -0,0 +1,155 @@ +/* + * 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. + */ + +// This header file includes the inline functions in +// the fix point signal processing library. + +#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ + +#include <stdint.h> + +#include "rtc_base/compile_assert_c.h" + +extern const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64]; + +// Don't call this directly except in tests! +static __inline int WebRtcSpl_CountLeadingZeros32_NotBuiltin(uint32_t n) { + // Normalize n by rounding up to the nearest number that is a sequence of 0 + // bits followed by a sequence of 1 bits. This number has the same number of + // leading zeros as the original n. There are exactly 33 such values. + n |= n >> 1; + n |= n >> 2; + n |= n >> 4; + n |= n >> 8; + n |= n >> 16; + + // Multiply the modified n with a constant selected (by exhaustive search) + // such that each of the 33 possible values of n give a product whose 6 most + // significant bits are unique. Then look up the answer in the table. + return kWebRtcSpl_CountLeadingZeros32_Table[(n * 0x8c0b2891) >> 26]; +} + +// Don't call this directly except in tests! +static __inline int WebRtcSpl_CountLeadingZeros64_NotBuiltin(uint64_t n) { + const int leading_zeros = n >> 32 == 0 ? 32 : 0; + return leading_zeros + WebRtcSpl_CountLeadingZeros32_NotBuiltin( + (uint32_t)(n >> (32 - leading_zeros))); +} + +// Returns the number of leading zero bits in the argument. +static __inline int WebRtcSpl_CountLeadingZeros32(uint32_t n) { +#ifdef __GNUC__ + RTC_COMPILE_ASSERT(sizeof(unsigned int) == sizeof(uint32_t)); + return n == 0 ? 32 : __builtin_clz(n); +#else + return WebRtcSpl_CountLeadingZeros32_NotBuiltin(n); +#endif +} + +// Returns the number of leading zero bits in the argument. +static __inline int WebRtcSpl_CountLeadingZeros64(uint64_t n) { +#ifdef __GNUC__ + RTC_COMPILE_ASSERT(sizeof(unsigned long long) == sizeof(uint64_t)); // NOLINT + return n == 0 ? 64 : __builtin_clzll(n); +#else + return WebRtcSpl_CountLeadingZeros64_NotBuiltin(n); +#endif +} + +#ifdef WEBRTC_ARCH_ARM_V7 +#include "common_audio/signal_processing/include/spl_inl_armv7.h" +#else + +#if defined(MIPS32_LE) +#include "common_audio/signal_processing/include/spl_inl_mips.h" +#endif + +#if !defined(MIPS_DSP_R1_LE) +static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { + int16_t out16 = (int16_t)value32; + + if (value32 > 32767) + out16 = 32767; + else if (value32 < -32768) + out16 = -32768; + + return out16; +} + +static __inline int32_t WebRtcSpl_AddSatW32(int32_t a, int32_t b) { + // Do the addition in unsigned numbers, since signed overflow is undefined + // behavior. + const int32_t sum = (int32_t)((uint32_t)a + (uint32_t)b); + + // a + b can't overflow if a and b have different signs. If they have the + // same sign, a + b also has the same sign iff it didn't overflow. + if ((a < 0) == (b < 0) && (a < 0) != (sum < 0)) { + // The direction of the overflow is obvious from the sign of a + b. + return sum < 0 ? INT32_MAX : INT32_MIN; + } + return sum; +} + +static __inline int32_t WebRtcSpl_SubSatW32(int32_t a, int32_t b) { + // Do the subtraction in unsigned numbers, since signed overflow is undefined + // behavior. + const int32_t diff = (int32_t)((uint32_t)a - (uint32_t)b); + + // a - b can't overflow if a and b have the same sign. If they have different + // signs, a - b has the same sign as a iff it didn't overflow. + if ((a < 0) != (b < 0) && (a < 0) != (diff < 0)) { + // The direction of the overflow is obvious from the sign of a - b. + return diff < 0 ? INT32_MAX : INT32_MIN; + } + return diff; +} + +static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { + return WebRtcSpl_SatW32ToW16((int32_t)a + (int32_t)b); +} + +static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { + return WebRtcSpl_SatW32ToW16((int32_t)var1 - (int32_t)var2); +} +#endif // #if !defined(MIPS_DSP_R1_LE) + +#if !defined(MIPS32_LE) +static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { + return 32 - WebRtcSpl_CountLeadingZeros32(n); +} + +// Return the number of steps a can be left-shifted without overflow, +// or 0 if a == 0. +static __inline int16_t WebRtcSpl_NormW32(int32_t a) { + return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a : a) - 1; +} + +// Return the number of steps a can be left-shifted without overflow, +// or 0 if a == 0. +static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { + return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a); +} + +// Return the number of steps a can be left-shifted without overflow, +// or 0 if a == 0. +static __inline int16_t WebRtcSpl_NormW16(int16_t a) { + const int32_t a32 = a; + return a == 0 ? 0 : WebRtcSpl_CountLeadingZeros32(a < 0 ? ~a32 : a32) - 17; +} + +static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { + return (a * b + c); +} +#endif // #if !defined(MIPS32_LE) + +#endif // WEBRTC_ARCH_ARM_V7 + +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_H_ diff --git a/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl_armv7.h b/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl_armv7.h new file mode 100644 index 0000000000..6fc3e7c1b8 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl_armv7.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* This header file includes the inline functions for ARM processors in + * the fix point signal processing library. + */ + +#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ + +#include <stdint.h> + +/* TODO(kma): Replace some assembly code with GCC intrinsics + * (e.g. __builtin_clz). + */ + +/* This function produces result that is not bit exact with that by the generic + * C version in some cases, although the former is at least as accurate as the + * later. + */ +static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { + int32_t tmp = 0; + __asm __volatile("smulwb %0, %1, %2" : "=r"(tmp) : "r"(b), "r"(a)); + return tmp; +} + +static __inline int32_t WEBRTC_SPL_MUL_16_16(int16_t a, int16_t b) { + int32_t tmp = 0; + __asm __volatile("smulbb %0, %1, %2" : "=r"(tmp) : "r"(a), "r"(b)); + return tmp; +} + +// TODO(kma): add unit test. +static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { + int32_t tmp = 0; + __asm __volatile("smlabb %0, %1, %2, %3" + : "=r"(tmp) + : "r"(a), "r"(b), "r"(c)); + return tmp; +} + +static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { + int32_t s_sum = 0; + + __asm __volatile("qadd16 %0, %1, %2" : "=r"(s_sum) : "r"(a), "r"(b)); + + return (int16_t)s_sum; +} + +static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { + int32_t l_sum = 0; + + __asm __volatile("qadd %0, %1, %2" : "=r"(l_sum) : "r"(l_var1), "r"(l_var2)); + + return l_sum; +} + +static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { + int32_t l_sub = 0; + + __asm __volatile("qsub %0, %1, %2" : "=r"(l_sub) : "r"(l_var1), "r"(l_var2)); + + return l_sub; +} + +static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { + int32_t s_sub = 0; + + __asm __volatile("qsub16 %0, %1, %2" : "=r"(s_sub) : "r"(var1), "r"(var2)); + + return (int16_t)s_sub; +} + +static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { + int32_t tmp = 0; + + __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(n)); + + return (int16_t)(32 - tmp); +} + +static __inline int16_t WebRtcSpl_NormW32(int32_t a) { + int32_t tmp = 0; + + if (a == 0) { + return 0; + } else if (a < 0) { + a ^= 0xFFFFFFFF; + } + + __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); + + return (int16_t)(tmp - 1); +} + +static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { + int tmp = 0; + + if (a == 0) + return 0; + + __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a)); + + return (int16_t)tmp; +} + +static __inline int16_t WebRtcSpl_NormW16(int16_t a) { + int32_t tmp = 0; + int32_t a_32 = a; + + if (a_32 == 0) { + return 0; + } else if (a_32 < 0) { + a_32 ^= 0xFFFFFFFF; + } + + __asm __volatile("clz %0, %1" : "=r"(tmp) : "r"(a_32)); + + return (int16_t)(tmp - 17); +} + +// TODO(kma): add unit test. +static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { + int32_t out = 0; + + __asm __volatile("ssat %0, #16, %1" : "=r"(out) : "r"(value32)); + + return (int16_t)out; +} + +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_ARMV7_H_ diff --git a/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl_mips.h b/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl_mips.h new file mode 100644 index 0000000000..1db95e8254 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/include/spl_inl_mips.h @@ -0,0 +1,204 @@ +/* + * 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 includes the inline functions in +// the fix point signal processing library. + +#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ + +static __inline int32_t WEBRTC_SPL_MUL_16_16(int32_t a, int32_t b) { + int32_t value32 = 0; + int32_t a1 = 0, b1 = 0; + + __asm __volatile( +#if defined(MIPS32_R2_LE) + "seh %[a1], %[a] \n\t" + "seh %[b1], %[b] \n\t" +#else + "sll %[a1], %[a], 16 \n\t" + "sll %[b1], %[b], 16 \n\t" + "sra %[a1], %[a1], 16 \n\t" + "sra %[b1], %[b1], 16 \n\t" +#endif + "mul %[value32], %[a1], %[b1] \n\t" + : [value32] "=r"(value32), [a1] "=&r"(a1), [b1] "=&r"(b1) + : [a] "r"(a), [b] "r"(b) + : "hi", "lo"); + return value32; +} + +static __inline int32_t WEBRTC_SPL_MUL_16_32_RSFT16(int16_t a, int32_t b) { + int32_t value32 = 0, b1 = 0, b2 = 0; + int32_t a1 = 0; + + __asm __volatile( +#if defined(MIPS32_R2_LE) + "seh %[a1], %[a] \n\t" +#else + "sll %[a1], %[a], 16 \n\t" + "sra %[a1], %[a1], 16 \n\t" +#endif + "andi %[b2], %[b], 0xFFFF \n\t" + "sra %[b1], %[b], 16 \n\t" + "sra %[b2], %[b2], 1 \n\t" + "mul %[value32], %[a1], %[b1] \n\t" + "mul %[b2], %[a1], %[b2] \n\t" + "addiu %[b2], %[b2], 0x4000 \n\t" + "sra %[b2], %[b2], 15 \n\t" + "addu %[value32], %[value32], %[b2] \n\t" + : [value32] "=&r"(value32), [b1] "=&r"(b1), [b2] "=&r"(b2), [a1] "=&r"(a1) + : [a] "r"(a), [b] "r"(b) + : "hi", "lo"); + return value32; +} + +#if defined(MIPS_DSP_R1_LE) +static __inline int16_t WebRtcSpl_SatW32ToW16(int32_t value32) { + __asm __volatile( + "shll_s.w %[value32], %[value32], 16 \n\t" + "sra %[value32], %[value32], 16 \n\t" + : [value32] "+r"(value32) + :); + int16_t out16 = (int16_t)value32; + return out16; +} + +static __inline int16_t WebRtcSpl_AddSatW16(int16_t a, int16_t b) { + int32_t value32 = 0; + + __asm __volatile("addq_s.ph %[value32], %[a], %[b] \n\t" + : [value32] "=r"(value32) + : [a] "r"(a), [b] "r"(b)); + return (int16_t)value32; +} + +static __inline int32_t WebRtcSpl_AddSatW32(int32_t l_var1, int32_t l_var2) { + int32_t l_sum; + + __asm __volatile( + "addq_s.w %[l_sum], %[l_var1], %[l_var2] \n\t" + : [l_sum] "=r"(l_sum) + : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); + + return l_sum; +} + +static __inline int16_t WebRtcSpl_SubSatW16(int16_t var1, int16_t var2) { + int32_t value32; + + __asm __volatile("subq_s.ph %[value32], %[var1], %[var2] \n\t" + : [value32] "=r"(value32) + : [var1] "r"(var1), [var2] "r"(var2)); + + return (int16_t)value32; +} + +static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) { + int32_t l_diff; + + __asm __volatile( + "subq_s.w %[l_diff], %[l_var1], %[l_var2] \n\t" + : [l_diff] "=r"(l_diff) + : [l_var1] "r"(l_var1), [l_var2] "r"(l_var2)); + + return l_diff; +} +#endif + +static __inline int16_t WebRtcSpl_GetSizeInBits(uint32_t n) { + int bits = 0; + int i32 = 32; + + __asm __volatile( + "clz %[bits], %[n] \n\t" + "subu %[bits], %[i32], %[bits] \n\t" + : [bits] "=&r"(bits) + : [n] "r"(n), [i32] "r"(i32)); + + return (int16_t)bits; +} + +static __inline int16_t WebRtcSpl_NormW32(int32_t a) { + int zeros = 0; + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "bnez %[a], 1f \n\t" + " sra %[zeros], %[a], 31 \n\t" + "b 2f \n\t" + " move %[zeros], $zero \n\t" + "1: \n\t" + "xor %[zeros], %[a], %[zeros] \n\t" + "clz %[zeros], %[zeros] \n\t" + "addiu %[zeros], %[zeros], -1 \n\t" + "2: \n\t" + ".set pop \n\t" + : [zeros] "=&r"(zeros) + : [a] "r"(a)); + + return (int16_t)zeros; +} + +static __inline int16_t WebRtcSpl_NormU32(uint32_t a) { + int zeros = 0; + + __asm __volatile("clz %[zeros], %[a] \n\t" + : [zeros] "=r"(zeros) + : [a] "r"(a)); + + return (int16_t)(zeros & 0x1f); +} + +static __inline int16_t WebRtcSpl_NormW16(int16_t a) { + int zeros = 0; + int a0 = a << 16; + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "bnez %[a0], 1f \n\t" + " sra %[zeros], %[a0], 31 \n\t" + "b 2f \n\t" + " move %[zeros], $zero \n\t" + "1: \n\t" + "xor %[zeros], %[a0], %[zeros] \n\t" + "clz %[zeros], %[zeros] \n\t" + "addiu %[zeros], %[zeros], -1 \n\t" + "2: \n\t" + ".set pop \n\t" + : [zeros] "=&r"(zeros) + : [a0] "r"(a0)); + + return (int16_t)zeros; +} + +static __inline int32_t WebRtc_MulAccumW16(int16_t a, int16_t b, int32_t c) { + int32_t res = 0, c1 = 0; + __asm __volatile( +#if defined(MIPS32_R2_LE) + "seh %[a], %[a] \n\t" + "seh %[b], %[b] \n\t" +#else + "sll %[a], %[a], 16 \n\t" + "sll %[b], %[b], 16 \n\t" + "sra %[a], %[a], 16 \n\t" + "sra %[b], %[b], 16 \n\t" +#endif + "mul %[res], %[a], %[b] \n\t" + "addu %[c1], %[c], %[res] \n\t" + : [c1] "=r"(c1), [res] "=&r"(res) + : [a] "r"(a), [b] "r"(b), [c] "r"(c) + : "hi", "lo"); + return (c1); +} + +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_SPL_INL_MIPS_H_ diff --git a/third_party/libwebrtc/common_audio/signal_processing/levinson_durbin.c b/third_party/libwebrtc/common_audio/signal_processing/levinson_durbin.c new file mode 100644 index 0000000000..2c5cbaeeaa --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/levinson_durbin.c @@ -0,0 +1,249 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_LevinsonDurbin(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "rtc_base/sanitizer.h" + +#define SPL_LEVINSON_MAXORDER 20 + +int16_t RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 +WebRtcSpl_LevinsonDurbin(const int32_t* R, int16_t* A, int16_t* K, + size_t order) +{ + size_t i, j; + // Auto-correlation coefficients in high precision + int16_t R_hi[SPL_LEVINSON_MAXORDER + 1], R_low[SPL_LEVINSON_MAXORDER + 1]; + // LPC coefficients in high precision + int16_t A_hi[SPL_LEVINSON_MAXORDER + 1], A_low[SPL_LEVINSON_MAXORDER + 1]; + // LPC coefficients for next iteration + int16_t A_upd_hi[SPL_LEVINSON_MAXORDER + 1], A_upd_low[SPL_LEVINSON_MAXORDER + 1]; + // Reflection coefficient in high precision + int16_t K_hi, K_low; + // Prediction gain Alpha in high precision and with scale factor + int16_t Alpha_hi, Alpha_low, Alpha_exp; + int16_t tmp_hi, tmp_low; + int32_t temp1W32, temp2W32, temp3W32; + int16_t norm; + + // Normalize the autocorrelation R[0]...R[order+1] + + norm = WebRtcSpl_NormW32(R[0]); + + for (i = 0; i <= order; ++i) + { + temp1W32 = R[i] * (1 << norm); + // UBSan: 12 * 268435456 cannot be represented in type 'int' + + // Put R in hi and low format + R_hi[i] = (int16_t)(temp1W32 >> 16); + R_low[i] = (int16_t)((temp1W32 - ((int32_t)R_hi[i] * 65536)) >> 1); + } + + // K = A[1] = -R[1] / R[0] + + temp2W32 = R[1] * (1 << norm); // R[1] in Q31 + temp3W32 = WEBRTC_SPL_ABS_W32(temp2W32); // abs R[1] + temp1W32 = WebRtcSpl_DivW32HiLow(temp3W32, R_hi[0], R_low[0]); // abs(R[1])/R[0] in Q31 + // Put back the sign on R[1] + if (temp2W32 > 0) + { + temp1W32 = -temp1W32; + } + + // Put K in hi and low format + K_hi = (int16_t)(temp1W32 >> 16); + K_low = (int16_t)((temp1W32 - ((int32_t)K_hi * 65536)) >> 1); + + // Store first reflection coefficient + K[0] = K_hi; + + temp1W32 >>= 4; // A[1] in Q27. + + // Put A[1] in hi and low format + A_hi[1] = (int16_t)(temp1W32 >> 16); + A_low[1] = (int16_t)((temp1W32 - ((int32_t)A_hi[1] * 65536)) >> 1); + + // Alpha = R[0] * (1-K^2) + + temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) * 2; // = k^2 in Q31 + + temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0 + temp1W32 = (int32_t)0x7fffffffL - temp1W32; // temp1W32 = (1 - K[0]*K[0]) in Q31 + + // Store temp1W32 = 1 - K[0]*K[0] on hi and low format + tmp_hi = (int16_t)(temp1W32 >> 16); + tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1); + + // Calculate Alpha in Q31 + temp1W32 = (R_hi[0] * tmp_hi + (R_hi[0] * tmp_low >> 15) + + (R_low[0] * tmp_hi >> 15)) << 1; + + // Normalize Alpha and put it in hi and low format + + Alpha_exp = WebRtcSpl_NormW32(temp1W32); + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, Alpha_exp); + Alpha_hi = (int16_t)(temp1W32 >> 16); + Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1); + + // Perform the iterative calculations in the Levinson-Durbin algorithm + + for (i = 2; i <= order; i++) + { + /* ---- + temp1W32 = R[i] + > R[j]*A[i-j] + / + ---- + j=1..i-1 + */ + + temp1W32 = 0; + + for (j = 1; j < i; j++) + { + // temp1W32 is in Q31 + temp1W32 += (R_hi[j] * A_hi[i - j] * 2) + + (((R_hi[j] * A_low[i - j] >> 15) + + (R_low[j] * A_hi[i - j] >> 15)) * 2); + } + + temp1W32 = temp1W32 * 16; + temp1W32 += ((int32_t)R_hi[i] * 65536) + + WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[i], 1); + + // K = -temp1W32 / Alpha + temp2W32 = WEBRTC_SPL_ABS_W32(temp1W32); // abs(temp1W32) + temp3W32 = WebRtcSpl_DivW32HiLow(temp2W32, Alpha_hi, Alpha_low); // abs(temp1W32)/Alpha + + // Put the sign of temp1W32 back again + if (temp1W32 > 0) + { + temp3W32 = -temp3W32; + } + + // Use the Alpha shifts from earlier to de-normalize + norm = WebRtcSpl_NormW32(temp3W32); + if ((Alpha_exp <= norm) || (temp3W32 == 0)) + { + temp3W32 = temp3W32 * (1 << Alpha_exp); + } else + { + if (temp3W32 > 0) + { + temp3W32 = (int32_t)0x7fffffffL; + } else + { + temp3W32 = (int32_t)0x80000000L; + } + } + + // Put K on hi and low format + K_hi = (int16_t)(temp3W32 >> 16); + K_low = (int16_t)((temp3W32 - ((int32_t)K_hi * 65536)) >> 1); + + // Store Reflection coefficient in Q15 + K[i - 1] = K_hi; + + // Test for unstable filter. + // If unstable return 0 and let the user decide what to do in that case + + if ((int32_t)WEBRTC_SPL_ABS_W16(K_hi) > (int32_t)32750) + { + return 0; // Unstable filter + } + + /* + Compute updated LPC coefficient: Anew[i] + Anew[j]= A[j] + K*A[i-j] for j=1..i-1 + Anew[i]= K + */ + + for (j = 1; j < i; j++) + { + // temp1W32 = A[j] in Q27 + temp1W32 = (int32_t)A_hi[j] * 65536 + + WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[j],1); + + // temp1W32 += K*A[i-j] in Q27 + temp1W32 += (K_hi * A_hi[i - j] + (K_hi * A_low[i - j] >> 15) + + (K_low * A_hi[i - j] >> 15)) * 2; + + // Put Anew in hi and low format + A_upd_hi[j] = (int16_t)(temp1W32 >> 16); + A_upd_low[j] = (int16_t)( + (temp1W32 - ((int32_t)A_upd_hi[j] * 65536)) >> 1); + } + + // temp3W32 = K in Q27 (Convert from Q31 to Q27) + temp3W32 >>= 4; + + // Store Anew in hi and low format + A_upd_hi[i] = (int16_t)(temp3W32 >> 16); + A_upd_low[i] = (int16_t)( + (temp3W32 - ((int32_t)A_upd_hi[i] * 65536)) >> 1); + + // Alpha = Alpha * (1-K^2) + + temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) * 2; // K*K in Q31 + + temp1W32 = WEBRTC_SPL_ABS_W32(temp1W32); // Guard against <0 + temp1W32 = (int32_t)0x7fffffffL - temp1W32; // 1 - K*K in Q31 + + // Convert 1- K^2 in hi and low format + tmp_hi = (int16_t)(temp1W32 >> 16); + tmp_low = (int16_t)((temp1W32 - ((int32_t)tmp_hi << 16)) >> 1); + + // Calculate Alpha = Alpha * (1-K^2) in Q31 + temp1W32 = (Alpha_hi * tmp_hi + (Alpha_hi * tmp_low >> 15) + + (Alpha_low * tmp_hi >> 15)) << 1; + + // Normalize Alpha and store it on hi and low format + + norm = WebRtcSpl_NormW32(temp1W32); + temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, norm); + + Alpha_hi = (int16_t)(temp1W32 >> 16); + Alpha_low = (int16_t)((temp1W32 - ((int32_t)Alpha_hi << 16)) >> 1); + + // Update the total normalization of Alpha + Alpha_exp = Alpha_exp + norm; + + // Update A[] + + for (j = 1; j <= i; j++) + { + A_hi[j] = A_upd_hi[j]; + A_low[j] = A_upd_low[j]; + } + } + + /* + Set A[0] to 1.0 and store the A[i] i=1...order in Q12 + (Convert from Q27 and use rounding) + */ + + A[0] = 4096; + + for (i = 1; i <= order; i++) + { + // temp1W32 in Q27 + temp1W32 = (int32_t)A_hi[i] * 65536 + + WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1); + // Round and store upper word + A[i] = (int16_t)(((temp1W32 * 2) + 32768) >> 16); + } + return 1; // Stable filters +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/lpc_to_refl_coef.c b/third_party/libwebrtc/common_audio/signal_processing/lpc_to_refl_coef.c new file mode 100644 index 0000000000..7a5e25191b --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/lpc_to_refl_coef.c @@ -0,0 +1,56 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_LpcToReflCoef(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#define SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER 50 + +void WebRtcSpl_LpcToReflCoef(int16_t* a16, int use_order, int16_t* k16) +{ + int m, k; + int32_t tmp32[SPL_LPC_TO_REFL_COEF_MAX_AR_MODEL_ORDER]; + int32_t tmp_inv_denom32; + int16_t tmp_inv_denom16; + + k16[use_order - 1] = a16[use_order] << 3; // Q12<<3 => Q15 + for (m = use_order - 1; m > 0; m--) + { + // (1 - k^2) in Q30 + tmp_inv_denom32 = 1073741823 - k16[m] * k16[m]; + // (1 - k^2) in Q15 + tmp_inv_denom16 = (int16_t)(tmp_inv_denom32 >> 15); + + for (k = 1; k <= m; k++) + { + // tmp[k] = (a[k] - RC[m] * a[m-k+1]) / (1.0 - RC[m]*RC[m]); + + // [Q12<<16 - (Q15*Q12)<<1] = [Q28 - Q28] = Q28 + tmp32[k] = (a16[k] << 16) - (k16[m] * a16[m - k + 1] << 1); + + tmp32[k] = WebRtcSpl_DivW32W16(tmp32[k], tmp_inv_denom16); //Q28/Q15 = Q13 + } + + for (k = 1; k < m; k++) + { + a16[k] = (int16_t)(tmp32[k] >> 1); // Q13>>1 => Q12 + } + + tmp32[m] = WEBRTC_SPL_SAT(8191, tmp32[m], -8191); + k16[m - 1] = (int16_t)WEBRTC_SPL_LSHIFT_W32(tmp32[m], 2); //Q13<<2 => Q15 + } + return; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/min_max_operations.c b/third_party/libwebrtc/common_audio/signal_processing/min_max_operations.c new file mode 100644 index 0000000000..1b9542e7ef --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/min_max_operations.c @@ -0,0 +1,256 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * This file contains the implementation of functions + * WebRtcSpl_MaxAbsValueW16C() + * WebRtcSpl_MaxAbsValueW32C() + * WebRtcSpl_MaxValueW16C() + * WebRtcSpl_MaxValueW32C() + * WebRtcSpl_MinValueW16C() + * WebRtcSpl_MinValueW32C() + * WebRtcSpl_MaxAbsIndexW16() + * WebRtcSpl_MaxIndexW16() + * WebRtcSpl_MaxIndexW32() + * WebRtcSpl_MinIndexW16() + * WebRtcSpl_MinIndexW32() + * + */ + +#include <stdlib.h> + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// TODO(bjorn/kma): Consolidate function pairs (e.g. combine +// WebRtcSpl_MaxAbsValueW16C and WebRtcSpl_MaxAbsIndexW16 into a single one.) +// TODO(kma): Move the next six functions into min_max_operations_c.c. + +// Maximum absolute value of word16 vector. C version for generic platforms. +int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length) { + size_t i = 0; + int absolute = 0, maximum = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + absolute = abs((int)vector[i]); + + if (absolute > maximum) { + maximum = absolute; + } + } + + // Guard the case for abs(-32768). + if (maximum > WEBRTC_SPL_WORD16_MAX) { + maximum = WEBRTC_SPL_WORD16_MAX; + } + + return (int16_t)maximum; +} + +// Maximum absolute value of word32 vector. C version for generic platforms. +int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length) { + // Use uint32_t for the local variables, to accommodate the return value + // of abs(0x80000000), which is 0x80000000. + + uint32_t absolute = 0, maximum = 0; + size_t i = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + absolute = abs((int)vector[i]); + if (absolute > maximum) { + maximum = absolute; + } + } + + maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX); + + return (int32_t)maximum; +} + +// Maximum value of word16 vector. C version for generic platforms. +int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length) { + int16_t maximum = WEBRTC_SPL_WORD16_MIN; + size_t i = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] > maximum) + maximum = vector[i]; + } + return maximum; +} + +// Maximum value of word32 vector. C version for generic platforms. +int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length) { + int32_t maximum = WEBRTC_SPL_WORD32_MIN; + size_t i = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] > maximum) + maximum = vector[i]; + } + return maximum; +} + +// Minimum value of word16 vector. C version for generic platforms. +int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length) { + int16_t minimum = WEBRTC_SPL_WORD16_MAX; + size_t i = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] < minimum) + minimum = vector[i]; + } + return minimum; +} + +// Minimum value of word32 vector. C version for generic platforms. +int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length) { + int32_t minimum = WEBRTC_SPL_WORD32_MAX; + size_t i = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] < minimum) + minimum = vector[i]; + } + return minimum; +} + +// Index of maximum absolute value in a word16 vector. +size_t WebRtcSpl_MaxAbsIndexW16(const int16_t* vector, size_t length) { + // Use type int for local variables, to accomodate the value of abs(-32768). + + size_t i = 0, index = 0; + int absolute = 0, maximum = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + absolute = abs((int)vector[i]); + + if (absolute > maximum) { + maximum = absolute; + index = i; + } + } + + return index; +} + +int16_t WebRtcSpl_MaxAbsElementW16(const int16_t* vector, size_t length) { + int16_t min_val, max_val; + WebRtcSpl_MinMaxW16(vector, length, &min_val, &max_val); + if (min_val == max_val || min_val < -max_val) { + return min_val; + } + return max_val; +} + +// Index of maximum value in a word16 vector. +size_t WebRtcSpl_MaxIndexW16(const int16_t* vector, size_t length) { + size_t i = 0, index = 0; + int16_t maximum = WEBRTC_SPL_WORD16_MIN; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] > maximum) { + maximum = vector[i]; + index = i; + } + } + + return index; +} + +// Index of maximum value in a word32 vector. +size_t WebRtcSpl_MaxIndexW32(const int32_t* vector, size_t length) { + size_t i = 0, index = 0; + int32_t maximum = WEBRTC_SPL_WORD32_MIN; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] > maximum) { + maximum = vector[i]; + index = i; + } + } + + return index; +} + +// Index of minimum value in a word16 vector. +size_t WebRtcSpl_MinIndexW16(const int16_t* vector, size_t length) { + size_t i = 0, index = 0; + int16_t minimum = WEBRTC_SPL_WORD16_MAX; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] < minimum) { + minimum = vector[i]; + index = i; + } + } + + return index; +} + +// Index of minimum value in a word32 vector. +size_t WebRtcSpl_MinIndexW32(const int32_t* vector, size_t length) { + size_t i = 0, index = 0; + int32_t minimum = WEBRTC_SPL_WORD32_MAX; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] < minimum) { + minimum = vector[i]; + index = i; + } + } + + return index; +} + +// Finds both the minimum and maximum elements in an array of 16-bit integers. +void WebRtcSpl_MinMaxW16(const int16_t* vector, size_t length, + int16_t* min_val, int16_t* max_val) { +#if defined(WEBRTC_HAS_NEON) + return WebRtcSpl_MinMaxW16Neon(vector, length, min_val, max_val); +#else + int16_t minimum = WEBRTC_SPL_WORD16_MAX; + int16_t maximum = WEBRTC_SPL_WORD16_MIN; + size_t i = 0; + + RTC_DCHECK_GT(length, 0); + + for (i = 0; i < length; i++) { + if (vector[i] < minimum) + minimum = vector[i]; + if (vector[i] > maximum) + maximum = vector[i]; + } + *min_val = minimum; + *max_val = maximum; +#endif +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_mips.c b/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_mips.c new file mode 100644 index 0000000000..8a7fc65c42 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_mips.c @@ -0,0 +1,375 @@ +/* + * 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 file contains the implementation of function + * WebRtcSpl_MaxAbsValueW16() + * + * The description header can be found in signal_processing_library.h. + * + */ + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// Maximum absolute value of word16 vector. +int16_t WebRtcSpl_MaxAbsValueW16_mips(const int16_t* vector, size_t length) { + int32_t totMax = 0; + int32_t tmp32_0, tmp32_1, tmp32_2, tmp32_3; + size_t i, loop_size; + + RTC_DCHECK_GT(length, 0); + +#if defined(MIPS_DSP_R1) + const int32_t* tmpvec32 = (int32_t*)vector; + loop_size = length >> 4; + + for (i = 0; i < loop_size; i++) { + __asm__ volatile ( + "lw %[tmp32_0], 0(%[tmpvec32]) \n\t" + "lw %[tmp32_1], 4(%[tmpvec32]) \n\t" + "lw %[tmp32_2], 8(%[tmpvec32]) \n\t" + "lw %[tmp32_3], 12(%[tmpvec32]) \n\t" + + "absq_s.ph %[tmp32_0], %[tmp32_0] \n\t" + "absq_s.ph %[tmp32_1], %[tmp32_1] \n\t" + "cmp.lt.ph %[totMax], %[tmp32_0] \n\t" + "pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t" + + "lw %[tmp32_0], 16(%[tmpvec32]) \n\t" + "absq_s.ph %[tmp32_2], %[tmp32_2] \n\t" + "cmp.lt.ph %[totMax], %[tmp32_1] \n\t" + "pick.ph %[totMax], %[tmp32_1], %[totMax] \n\t" + + "lw %[tmp32_1], 20(%[tmpvec32]) \n\t" + "absq_s.ph %[tmp32_3], %[tmp32_3] \n\t" + "cmp.lt.ph %[totMax], %[tmp32_2] \n\t" + "pick.ph %[totMax], %[tmp32_2], %[totMax] \n\t" + + "lw %[tmp32_2], 24(%[tmpvec32]) \n\t" + "cmp.lt.ph %[totMax], %[tmp32_3] \n\t" + "pick.ph %[totMax], %[tmp32_3], %[totMax] \n\t" + + "lw %[tmp32_3], 28(%[tmpvec32]) \n\t" + "absq_s.ph %[tmp32_0], %[tmp32_0] \n\t" + "absq_s.ph %[tmp32_1], %[tmp32_1] \n\t" + "cmp.lt.ph %[totMax], %[tmp32_0] \n\t" + "pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t" + + "absq_s.ph %[tmp32_2], %[tmp32_2] \n\t" + "cmp.lt.ph %[totMax], %[tmp32_1] \n\t" + "pick.ph %[totMax], %[tmp32_1], %[totMax] \n\t" + "absq_s.ph %[tmp32_3], %[tmp32_3] \n\t" + "cmp.lt.ph %[totMax], %[tmp32_2] \n\t" + "pick.ph %[totMax], %[tmp32_2], %[totMax] \n\t" + + "cmp.lt.ph %[totMax], %[tmp32_3] \n\t" + "pick.ph %[totMax], %[tmp32_3], %[totMax] \n\t" + + "addiu %[tmpvec32], %[tmpvec32], 32 \n\t" + : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), + [tmp32_2] "=&r" (tmp32_2), [tmp32_3] "=&r" (tmp32_3), + [totMax] "+r" (totMax), [tmpvec32] "+r" (tmpvec32) + : + : "memory" + ); + } + __asm__ volatile ( + "rotr %[tmp32_0], %[totMax], 16 \n\t" + "cmp.lt.ph %[totMax], %[tmp32_0] \n\t" + "pick.ph %[totMax], %[tmp32_0], %[totMax] \n\t" + "packrl.ph %[totMax], $0, %[totMax] \n\t" + : [tmp32_0] "=&r" (tmp32_0), [totMax] "+r" (totMax) + : + ); + loop_size = length & 0xf; + for (i = 0; i < loop_size; i++) { + __asm__ volatile ( + "lh %[tmp32_0], 0(%[tmpvec32]) \n\t" + "addiu %[tmpvec32], %[tmpvec32], 2 \n\t" + "absq_s.w %[tmp32_0], %[tmp32_0] \n\t" + "slt %[tmp32_1], %[totMax], %[tmp32_0] \n\t" + "movn %[totMax], %[tmp32_0], %[tmp32_1] \n\t" + : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), + [tmpvec32] "+r" (tmpvec32), [totMax] "+r" (totMax) + : + : "memory" + ); + } +#else // #if defined(MIPS_DSP_R1) + int32_t v16MaxMax = WEBRTC_SPL_WORD16_MAX; + int32_t r, r1, r2, r3; + const int16_t* tmpvector = vector; + loop_size = length >> 4; + for (i = 0; i < loop_size; i++) { + __asm__ volatile ( + "lh %[tmp32_0], 0(%[tmpvector]) \n\t" + "lh %[tmp32_1], 2(%[tmpvector]) \n\t" + "lh %[tmp32_2], 4(%[tmpvector]) \n\t" + "lh %[tmp32_3], 6(%[tmpvector]) \n\t" + + "abs %[tmp32_0], %[tmp32_0] \n\t" + "abs %[tmp32_1], %[tmp32_1] \n\t" + "abs %[tmp32_2], %[tmp32_2] \n\t" + "abs %[tmp32_3], %[tmp32_3] \n\t" + + "slt %[r], %[totMax], %[tmp32_0] \n\t" + "movn %[totMax], %[tmp32_0], %[r] \n\t" + "slt %[r1], %[totMax], %[tmp32_1] \n\t" + "movn %[totMax], %[tmp32_1], %[r1] \n\t" + "slt %[r2], %[totMax], %[tmp32_2] \n\t" + "movn %[totMax], %[tmp32_2], %[r2] \n\t" + "slt %[r3], %[totMax], %[tmp32_3] \n\t" + "movn %[totMax], %[tmp32_3], %[r3] \n\t" + + "lh %[tmp32_0], 8(%[tmpvector]) \n\t" + "lh %[tmp32_1], 10(%[tmpvector]) \n\t" + "lh %[tmp32_2], 12(%[tmpvector]) \n\t" + "lh %[tmp32_3], 14(%[tmpvector]) \n\t" + + "abs %[tmp32_0], %[tmp32_0] \n\t" + "abs %[tmp32_1], %[tmp32_1] \n\t" + "abs %[tmp32_2], %[tmp32_2] \n\t" + "abs %[tmp32_3], %[tmp32_3] \n\t" + + "slt %[r], %[totMax], %[tmp32_0] \n\t" + "movn %[totMax], %[tmp32_0], %[r] \n\t" + "slt %[r1], %[totMax], %[tmp32_1] \n\t" + "movn %[totMax], %[tmp32_1], %[r1] \n\t" + "slt %[r2], %[totMax], %[tmp32_2] \n\t" + "movn %[totMax], %[tmp32_2], %[r2] \n\t" + "slt %[r3], %[totMax], %[tmp32_3] \n\t" + "movn %[totMax], %[tmp32_3], %[r3] \n\t" + + "lh %[tmp32_0], 16(%[tmpvector]) \n\t" + "lh %[tmp32_1], 18(%[tmpvector]) \n\t" + "lh %[tmp32_2], 20(%[tmpvector]) \n\t" + "lh %[tmp32_3], 22(%[tmpvector]) \n\t" + + "abs %[tmp32_0], %[tmp32_0] \n\t" + "abs %[tmp32_1], %[tmp32_1] \n\t" + "abs %[tmp32_2], %[tmp32_2] \n\t" + "abs %[tmp32_3], %[tmp32_3] \n\t" + + "slt %[r], %[totMax], %[tmp32_0] \n\t" + "movn %[totMax], %[tmp32_0], %[r] \n\t" + "slt %[r1], %[totMax], %[tmp32_1] \n\t" + "movn %[totMax], %[tmp32_1], %[r1] \n\t" + "slt %[r2], %[totMax], %[tmp32_2] \n\t" + "movn %[totMax], %[tmp32_2], %[r2] \n\t" + "slt %[r3], %[totMax], %[tmp32_3] \n\t" + "movn %[totMax], %[tmp32_3], %[r3] \n\t" + + "lh %[tmp32_0], 24(%[tmpvector]) \n\t" + "lh %[tmp32_1], 26(%[tmpvector]) \n\t" + "lh %[tmp32_2], 28(%[tmpvector]) \n\t" + "lh %[tmp32_3], 30(%[tmpvector]) \n\t" + + "abs %[tmp32_0], %[tmp32_0] \n\t" + "abs %[tmp32_1], %[tmp32_1] \n\t" + "abs %[tmp32_2], %[tmp32_2] \n\t" + "abs %[tmp32_3], %[tmp32_3] \n\t" + + "slt %[r], %[totMax], %[tmp32_0] \n\t" + "movn %[totMax], %[tmp32_0], %[r] \n\t" + "slt %[r1], %[totMax], %[tmp32_1] \n\t" + "movn %[totMax], %[tmp32_1], %[r1] \n\t" + "slt %[r2], %[totMax], %[tmp32_2] \n\t" + "movn %[totMax], %[tmp32_2], %[r2] \n\t" + "slt %[r3], %[totMax], %[tmp32_3] \n\t" + "movn %[totMax], %[tmp32_3], %[r3] \n\t" + + "addiu %[tmpvector], %[tmpvector], 32 \n\t" + : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), + [tmp32_2] "=&r" (tmp32_2), [tmp32_3] "=&r" (tmp32_3), + [totMax] "+r" (totMax), [r] "=&r" (r), [tmpvector] "+r" (tmpvector), + [r1] "=&r" (r1), [r2] "=&r" (r2), [r3] "=&r" (r3) + : + : "memory" + ); + } + loop_size = length & 0xf; + for (i = 0; i < loop_size; i++) { + __asm__ volatile ( + "lh %[tmp32_0], 0(%[tmpvector]) \n\t" + "addiu %[tmpvector], %[tmpvector], 2 \n\t" + "abs %[tmp32_0], %[tmp32_0] \n\t" + "slt %[tmp32_1], %[totMax], %[tmp32_0] \n\t" + "movn %[totMax], %[tmp32_0], %[tmp32_1] \n\t" + : [tmp32_0] "=&r" (tmp32_0), [tmp32_1] "=&r" (tmp32_1), + [tmpvector] "+r" (tmpvector), [totMax] "+r" (totMax) + : + : "memory" + ); + } + + __asm__ volatile ( + "slt %[r], %[v16MaxMax], %[totMax] \n\t" + "movn %[totMax], %[v16MaxMax], %[r] \n\t" + : [totMax] "+r" (totMax), [r] "=&r" (r) + : [v16MaxMax] "r" (v16MaxMax) + ); +#endif // #if defined(MIPS_DSP_R1) + return (int16_t)totMax; +} + +#if defined(MIPS_DSP_R1_LE) +// Maximum absolute value of word32 vector. Version for MIPS platform. +int32_t WebRtcSpl_MaxAbsValueW32_mips(const int32_t* vector, size_t length) { + // Use uint32_t for the local variables, to accommodate the return value + // of abs(0x80000000), which is 0x80000000. + + uint32_t absolute = 0, maximum = 0; + int tmp1 = 0, max_value = 0x7fffffff; + + RTC_DCHECK_GT(length, 0); + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + + "1: \n\t" + "lw %[absolute], 0(%[vector]) \n\t" + "absq_s.w %[absolute], %[absolute] \n\t" + "addiu %[length], %[length], -1 \n\t" + "slt %[tmp1], %[maximum], %[absolute] \n\t" + "movn %[maximum], %[absolute], %[tmp1] \n\t" + "bgtz %[length], 1b \n\t" + " addiu %[vector], %[vector], 4 \n\t" + "slt %[tmp1], %[max_value], %[maximum] \n\t" + "movn %[maximum], %[max_value], %[tmp1] \n\t" + + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [absolute] "+r" (absolute) + : [vector] "r" (vector), [length] "r" (length), [max_value] "r" (max_value) + : "memory" + ); + + return (int32_t)maximum; +} +#endif // #if defined(MIPS_DSP_R1_LE) + +// Maximum value of word16 vector. Version for MIPS platform. +int16_t WebRtcSpl_MaxValueW16_mips(const int16_t* vector, size_t length) { + int16_t maximum = WEBRTC_SPL_WORD16_MIN; + int tmp1; + int16_t value; + + RTC_DCHECK_GT(length, 0); + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + + "1: \n\t" + "lh %[value], 0(%[vector]) \n\t" + "addiu %[length], %[length], -1 \n\t" + "slt %[tmp1], %[maximum], %[value] \n\t" + "movn %[maximum], %[value], %[tmp1] \n\t" + "bgtz %[length], 1b \n\t" + " addiu %[vector], %[vector], 2 \n\t" + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [value] "=&r" (value) + : [vector] "r" (vector), [length] "r" (length) + : "memory" + ); + + return maximum; +} + +// Maximum value of word32 vector. Version for MIPS platform. +int32_t WebRtcSpl_MaxValueW32_mips(const int32_t* vector, size_t length) { + int32_t maximum = WEBRTC_SPL_WORD32_MIN; + int tmp1, value; + + RTC_DCHECK_GT(length, 0); + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + + "1: \n\t" + "lw %[value], 0(%[vector]) \n\t" + "addiu %[length], %[length], -1 \n\t" + "slt %[tmp1], %[maximum], %[value] \n\t" + "movn %[maximum], %[value], %[tmp1] \n\t" + "bgtz %[length], 1b \n\t" + " addiu %[vector], %[vector], 4 \n\t" + + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [maximum] "+r" (maximum), [value] "=&r" (value) + : [vector] "r" (vector), [length] "r" (length) + : "memory" + ); + + return maximum; +} + +// Minimum value of word16 vector. Version for MIPS platform. +int16_t WebRtcSpl_MinValueW16_mips(const int16_t* vector, size_t length) { + int16_t minimum = WEBRTC_SPL_WORD16_MAX; + int tmp1; + int16_t value; + + RTC_DCHECK_GT(length, 0); + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + + "1: \n\t" + "lh %[value], 0(%[vector]) \n\t" + "addiu %[length], %[length], -1 \n\t" + "slt %[tmp1], %[value], %[minimum] \n\t" + "movn %[minimum], %[value], %[tmp1] \n\t" + "bgtz %[length], 1b \n\t" + " addiu %[vector], %[vector], 2 \n\t" + + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [minimum] "+r" (minimum), [value] "=&r" (value) + : [vector] "r" (vector), [length] "r" (length) + : "memory" + ); + + return minimum; +} + +// Minimum value of word32 vector. Version for MIPS platform. +int32_t WebRtcSpl_MinValueW32_mips(const int32_t* vector, size_t length) { + int32_t minimum = WEBRTC_SPL_WORD32_MAX; + int tmp1, value; + + RTC_DCHECK_GT(length, 0); + + __asm__ volatile ( + ".set push \n\t" + ".set noreorder \n\t" + + "1: \n\t" + "lw %[value], 0(%[vector]) \n\t" + "addiu %[length], %[length], -1 \n\t" + "slt %[tmp1], %[value], %[minimum] \n\t" + "movn %[minimum], %[value], %[tmp1] \n\t" + "bgtz %[length], 1b \n\t" + " addiu %[vector], %[vector], 4 \n\t" + + ".set pop \n\t" + + : [tmp1] "=&r" (tmp1), [minimum] "+r" (minimum), [value] "=&r" (value) + : [vector] "r" (vector), [length] "r" (length) + : "memory" + ); + + return minimum; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_neon.c b/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_neon.c new file mode 100644 index 0000000000..e5b4b7c71b --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/min_max_operations_neon.c @@ -0,0 +1,333 @@ +/* + * 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 <arm_neon.h> +#include <stdlib.h> + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// Maximum absolute value of word16 vector. C version for generic platforms. +int16_t WebRtcSpl_MaxAbsValueW16Neon(const int16_t* vector, size_t length) { + int absolute = 0, maximum = 0; + + RTC_DCHECK_GT(length, 0); + + const int16_t* p_start = vector; + size_t rest = length & 7; + const int16_t* p_end = vector + length - rest; + + int16x8_t v; + uint16x8_t max_qv; + max_qv = vdupq_n_u16(0); + + while (p_start < p_end) { + v = vld1q_s16(p_start); + // Note vabs doesn't change the value of -32768. + v = vabsq_s16(v); + // Use u16 so we don't lose the value -32768. + max_qv = vmaxq_u16(max_qv, vreinterpretq_u16_s16(v)); + p_start += 8; + } + +#ifdef WEBRTC_ARCH_ARM64 + maximum = (int)vmaxvq_u16(max_qv); +#else + uint16x4_t max_dv; + max_dv = vmax_u16(vget_low_u16(max_qv), vget_high_u16(max_qv)); + max_dv = vpmax_u16(max_dv, max_dv); + max_dv = vpmax_u16(max_dv, max_dv); + + maximum = (int)vget_lane_u16(max_dv, 0); +#endif + + p_end = vector + length; + while (p_start < p_end) { + absolute = abs((int)(*p_start)); + + if (absolute > maximum) { + maximum = absolute; + } + p_start++; + } + + // Guard the case for abs(-32768). + if (maximum > WEBRTC_SPL_WORD16_MAX) { + maximum = WEBRTC_SPL_WORD16_MAX; + } + + return (int16_t)maximum; +} + +// Maximum absolute value of word32 vector. NEON intrinsics version for +// ARM 32-bit/64-bit platforms. +int32_t WebRtcSpl_MaxAbsValueW32Neon(const int32_t* vector, size_t length) { + // Use uint32_t for the local variables, to accommodate the return value + // of abs(0x80000000), which is 0x80000000. + + uint32_t absolute = 0, maximum = 0; + size_t i = 0; + size_t residual = length & 0x7; + + RTC_DCHECK_GT(length, 0); + + const int32_t* p_start = vector; + uint32x4_t max32x4_0 = vdupq_n_u32(0); + uint32x4_t max32x4_1 = vdupq_n_u32(0); + + // First part, unroll the loop 8 times. + for (i = 0; i < length - residual; i += 8) { + int32x4_t in32x4_0 = vld1q_s32(p_start); + p_start += 4; + int32x4_t in32x4_1 = vld1q_s32(p_start); + p_start += 4; + in32x4_0 = vabsq_s32(in32x4_0); + in32x4_1 = vabsq_s32(in32x4_1); + // vabs doesn't change the value of 0x80000000. + // Use u32 so we don't lose the value 0x80000000. + max32x4_0 = vmaxq_u32(max32x4_0, vreinterpretq_u32_s32(in32x4_0)); + max32x4_1 = vmaxq_u32(max32x4_1, vreinterpretq_u32_s32(in32x4_1)); + } + + uint32x4_t max32x4 = vmaxq_u32(max32x4_0, max32x4_1); +#if defined(WEBRTC_ARCH_ARM64) + maximum = vmaxvq_u32(max32x4); +#else + uint32x2_t max32x2 = vmax_u32(vget_low_u32(max32x4), vget_high_u32(max32x4)); + max32x2 = vpmax_u32(max32x2, max32x2); + + maximum = vget_lane_u32(max32x2, 0); +#endif + + // Second part, do the remaining iterations (if any). + for (i = residual; i > 0; i--) { + absolute = abs((int)(*p_start)); + if (absolute > maximum) { + maximum = absolute; + } + p_start++; + } + + // Guard against the case for 0x80000000. + maximum = WEBRTC_SPL_MIN(maximum, WEBRTC_SPL_WORD32_MAX); + + return (int32_t)maximum; +} + +// Maximum value of word16 vector. NEON intrinsics version for +// ARM 32-bit/64-bit platforms. +int16_t WebRtcSpl_MaxValueW16Neon(const int16_t* vector, size_t length) { + int16_t maximum = WEBRTC_SPL_WORD16_MIN; + size_t i = 0; + size_t residual = length & 0x7; + + RTC_DCHECK_GT(length, 0); + + const int16_t* p_start = vector; + int16x8_t max16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MIN); + + // First part, unroll the loop 8 times. + for (i = 0; i < length - residual; i += 8) { + int16x8_t in16x8 = vld1q_s16(p_start); + max16x8 = vmaxq_s16(max16x8, in16x8); + p_start += 8; + } + +#if defined(WEBRTC_ARCH_ARM64) + maximum = vmaxvq_s16(max16x8); +#else + int16x4_t max16x4 = vmax_s16(vget_low_s16(max16x8), vget_high_s16(max16x8)); + max16x4 = vpmax_s16(max16x4, max16x4); + max16x4 = vpmax_s16(max16x4, max16x4); + + maximum = vget_lane_s16(max16x4, 0); +#endif + + // Second part, do the remaining iterations (if any). + for (i = residual; i > 0; i--) { + if (*p_start > maximum) + maximum = *p_start; + p_start++; + } + return maximum; +} + +// Maximum value of word32 vector. NEON intrinsics version for +// ARM 32-bit/64-bit platforms. +int32_t WebRtcSpl_MaxValueW32Neon(const int32_t* vector, size_t length) { + int32_t maximum = WEBRTC_SPL_WORD32_MIN; + size_t i = 0; + size_t residual = length & 0x7; + + RTC_DCHECK_GT(length, 0); + + const int32_t* p_start = vector; + int32x4_t max32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MIN); + int32x4_t max32x4_1 = vdupq_n_s32(WEBRTC_SPL_WORD32_MIN); + + // First part, unroll the loop 8 times. + for (i = 0; i < length - residual; i += 8) { + int32x4_t in32x4_0 = vld1q_s32(p_start); + p_start += 4; + int32x4_t in32x4_1 = vld1q_s32(p_start); + p_start += 4; + max32x4_0 = vmaxq_s32(max32x4_0, in32x4_0); + max32x4_1 = vmaxq_s32(max32x4_1, in32x4_1); + } + + int32x4_t max32x4 = vmaxq_s32(max32x4_0, max32x4_1); +#if defined(WEBRTC_ARCH_ARM64) + maximum = vmaxvq_s32(max32x4); +#else + int32x2_t max32x2 = vmax_s32(vget_low_s32(max32x4), vget_high_s32(max32x4)); + max32x2 = vpmax_s32(max32x2, max32x2); + + maximum = vget_lane_s32(max32x2, 0); +#endif + + // Second part, do the remaining iterations (if any). + for (i = residual; i > 0; i--) { + if (*p_start > maximum) + maximum = *p_start; + p_start++; + } + return maximum; +} + +// Minimum value of word16 vector. NEON intrinsics version for +// ARM 32-bit/64-bit platforms. +int16_t WebRtcSpl_MinValueW16Neon(const int16_t* vector, size_t length) { + int16_t minimum = WEBRTC_SPL_WORD16_MAX; + size_t i = 0; + size_t residual = length & 0x7; + + RTC_DCHECK_GT(length, 0); + + const int16_t* p_start = vector; + int16x8_t min16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MAX); + + // First part, unroll the loop 8 times. + for (i = 0; i < length - residual; i += 8) { + int16x8_t in16x8 = vld1q_s16(p_start); + min16x8 = vminq_s16(min16x8, in16x8); + p_start += 8; + } + +#if defined(WEBRTC_ARCH_ARM64) + minimum = vminvq_s16(min16x8); +#else + int16x4_t min16x4 = vmin_s16(vget_low_s16(min16x8), vget_high_s16(min16x8)); + min16x4 = vpmin_s16(min16x4, min16x4); + min16x4 = vpmin_s16(min16x4, min16x4); + + minimum = vget_lane_s16(min16x4, 0); +#endif + + // Second part, do the remaining iterations (if any). + for (i = residual; i > 0; i--) { + if (*p_start < minimum) + minimum = *p_start; + p_start++; + } + return minimum; +} + +// Minimum value of word32 vector. NEON intrinsics version for +// ARM 32-bit/64-bit platforms. +int32_t WebRtcSpl_MinValueW32Neon(const int32_t* vector, size_t length) { + int32_t minimum = WEBRTC_SPL_WORD32_MAX; + size_t i = 0; + size_t residual = length & 0x7; + + RTC_DCHECK_GT(length, 0); + + const int32_t* p_start = vector; + int32x4_t min32x4_0 = vdupq_n_s32(WEBRTC_SPL_WORD32_MAX); + int32x4_t min32x4_1 = vdupq_n_s32(WEBRTC_SPL_WORD32_MAX); + + // First part, unroll the loop 8 times. + for (i = 0; i < length - residual; i += 8) { + int32x4_t in32x4_0 = vld1q_s32(p_start); + p_start += 4; + int32x4_t in32x4_1 = vld1q_s32(p_start); + p_start += 4; + min32x4_0 = vminq_s32(min32x4_0, in32x4_0); + min32x4_1 = vminq_s32(min32x4_1, in32x4_1); + } + + int32x4_t min32x4 = vminq_s32(min32x4_0, min32x4_1); +#if defined(WEBRTC_ARCH_ARM64) + minimum = vminvq_s32(min32x4); +#else + int32x2_t min32x2 = vmin_s32(vget_low_s32(min32x4), vget_high_s32(min32x4)); + min32x2 = vpmin_s32(min32x2, min32x2); + + minimum = vget_lane_s32(min32x2, 0); +#endif + + // Second part, do the remaining iterations (if any). + for (i = residual; i > 0; i--) { + if (*p_start < minimum) + minimum = *p_start; + p_start++; + } + return minimum; +} + +// Finds both the minimum and maximum elements in an array of 16-bit integers. +void WebRtcSpl_MinMaxW16Neon(const int16_t* vector, size_t length, + int16_t* min_val, int16_t* max_val) { + int16_t minimum = WEBRTC_SPL_WORD16_MAX; + int16_t maximum = WEBRTC_SPL_WORD16_MIN; + size_t i = 0; + size_t residual = length & 0x7; + + RTC_DCHECK_GT(length, 0); + + const int16_t* p_start = vector; + int16x8_t min16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MAX); + int16x8_t max16x8 = vdupq_n_s16(WEBRTC_SPL_WORD16_MIN); + + // First part, unroll the loop 8 times. + for (i = 0; i < length - residual; i += 8) { + int16x8_t in16x8 = vld1q_s16(p_start); + min16x8 = vminq_s16(min16x8, in16x8); + max16x8 = vmaxq_s16(max16x8, in16x8); + p_start += 8; + } + +#if defined(WEBRTC_ARCH_ARM64) + minimum = vminvq_s16(min16x8); + maximum = vmaxvq_s16(max16x8); +#else + int16x4_t min16x4 = vmin_s16(vget_low_s16(min16x8), vget_high_s16(min16x8)); + min16x4 = vpmin_s16(min16x4, min16x4); + min16x4 = vpmin_s16(min16x4, min16x4); + + minimum = vget_lane_s16(min16x4, 0); + + int16x4_t max16x4 = vmax_s16(vget_low_s16(max16x8), vget_high_s16(max16x8)); + max16x4 = vpmax_s16(max16x4, max16x4); + max16x4 = vpmax_s16(max16x4, max16x4); + + maximum = vget_lane_s16(max16x4, 0); +#endif + + // Second part, do the remaining iterations (if any). + for (i = residual; i > 0; i--) { + if (*p_start < minimum) + minimum = *p_start; + if (*p_start > maximum) + maximum = *p_start; + p_start++; + } + *min_val = minimum; + *max_val = maximum; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/randomization_functions.c b/third_party/libwebrtc/common_audio/signal_processing/randomization_functions.c new file mode 100644 index 0000000000..a445c572c7 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/randomization_functions.c @@ -0,0 +1,115 @@ +/* + * 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. + */ + + +/* + * This file contains implementations of the randomization functions + * WebRtcSpl_RandU() + * WebRtcSpl_RandN() + * WebRtcSpl_RandUArray() + * + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +static const uint32_t kMaxSeedUsed = 0x80000000; + +static const int16_t kRandNTable[] = { + 9178, -7260, 40, 10189, 4894, -3531, -13779, 14764, + -4008, -8884, -8990, 1008, 7368, 5184, 3251, -5817, + -9786, 5963, 1770, 8066, -7135, 10772, -2298, 1361, + 6484, 2241, -8633, 792, 199, -3344, 6553, -10079, + -15040, 95, 11608, -12469, 14161, -4176, 2476, 6403, + 13685, -16005, 6646, 2239, 10916, -3004, -602, -3141, + 2142, 14144, -5829, 5305, 8209, 4713, 2697, -5112, + 16092, -1210, -2891, -6631, -5360, -11878, -6781, -2739, + -6392, 536, 10923, 10872, 5059, -4748, -7770, 5477, + 38, -1025, -2892, 1638, 6304, 14375, -11028, 1553, + -1565, 10762, -393, 4040, 5257, 12310, 6554, -4799, + 4899, -6354, 1603, -1048, -2220, 8247, -186, -8944, + -12004, 2332, 4801, -4933, 6371, 131, 8614, -5927, + -8287, -22760, 4033, -15162, 3385, 3246, 3153, -5250, + 3766, 784, 6494, -62, 3531, -1582, 15572, 662, + -3952, -330, -3196, 669, 7236, -2678, -6569, 23319, + -8645, -741, 14830, -15976, 4903, 315, -11342, 10311, + 1858, -7777, 2145, 5436, 5677, -113, -10033, 826, + -1353, 17210, 7768, 986, -1471, 8291, -4982, 8207, + -14911, -6255, -2449, -11881, -7059, -11703, -4338, 8025, + 7538, -2823, -12490, 9470, -1613, -2529, -10092, -7807, + 9480, 6970, -12844, 5123, 3532, 4816, 4803, -8455, + -5045, 14032, -4378, -1643, 5756, -11041, -2732, -16618, + -6430, -18375, -3320, 6098, 5131, -4269, -8840, 2482, + -7048, 1547, -21890, -6505, -7414, -424, -11722, 7955, + 1653, -17299, 1823, 473, -9232, 3337, 1111, 873, + 4018, -8982, 9889, 3531, -11763, -3799, 7373, -4539, + 3231, 7054, -8537, 7616, 6244, 16635, 447, -2915, + 13967, 705, -2669, -1520, -1771, -16188, 5956, 5117, + 6371, -9936, -1448, 2480, 5128, 7550, -8130, 5236, + 8213, -6443, 7707, -1950, -13811, 7218, 7031, -3883, + 67, 5731, -2874, 13480, -3743, 9298, -3280, 3552, + -4425, -18, -3785, -9988, -5357, 5477, -11794, 2117, + 1416, -9935, 3376, 802, -5079, -8243, 12652, 66, + 3653, -2368, 6781, -21895, -7227, 2487, 7839, -385, + 6646, -7016, -4658, 5531, -1705, 834, 129, 3694, + -1343, 2238, -22640, -6417, -11139, 11301, -2945, -3494, + -5626, 185, -3615, -2041, -7972, -3106, -60, -23497, + -1566, 17064, 3519, 2518, 304, -6805, -10269, 2105, + 1936, -426, -736, -8122, -1467, 4238, -6939, -13309, + 360, 7402, -7970, 12576, 3287, 12194, -6289, -16006, + 9171, 4042, -9193, 9123, -2512, 6388, -4734, -8739, + 1028, -5406, -1696, 5889, -666, -4736, 4971, 3565, + 9362, -6292, 3876, -3652, -19666, 7523, -4061, 391, + -11773, 7502, -3763, 4929, -9478, 13278, 2805, 4496, + 7814, 16419, 12455, -14773, 2127, -2746, 3763, 4847, + 3698, 6978, 4751, -6957, -3581, -45, 6252, 1513, + -4797, -7925, 11270, 16188, -2359, -5269, 9376, -10777, + 7262, 20031, -6515, -2208, -5353, 8085, -1341, -1303, + 7333, 5576, 3625, 5763, -7931, 9833, -3371, -10305, + 6534, -13539, -9971, 997, 8464, -4064, -1495, 1857, + 13624, 5458, 9490, -11086, -4524, 12022, -550, -198, + 408, -8455, -7068, 10289, 9712, -3366, 9028, -7621, + -5243, 2362, 6909, 4672, -4933, -1799, 4709, -4563, + -62, -566, 1624, -7010, 14730, -17791, -3697, -2344, + -1741, 7099, -9509, -6855, -1989, 3495, -2289, 2031, + 12784, 891, 14189, -3963, -5683, 421, -12575, 1724, + -12682, -5970, -8169, 3143, -1824, -5488, -5130, 8536, + 12799, 794, 5738, 3459, -11689, -258, -3738, -3775, + -8742, 2333, 8312, -9383, 10331, 13119, 8398, 10644, + -19433, -6446, -16277, -11793, 16284, 9345, 15222, 15834, + 2009, -7349, 130, -14547, 338, -5998, 3337, 21492, + 2406, 7703, -951, 11196, -564, 3406, 2217, 4806, + 2374, -5797, 11839, 8940, -11874, 18213, 2855, 10492 +}; + +static uint32_t IncreaseSeed(uint32_t* seed) { + seed[0] = (seed[0] * ((int32_t)69069) + 1) & (kMaxSeedUsed - 1); + return seed[0]; +} + +int16_t WebRtcSpl_RandU(uint32_t* seed) { + return (int16_t)(IncreaseSeed(seed) >> 16); +} + +int16_t WebRtcSpl_RandN(uint32_t* seed) { + return kRandNTable[IncreaseSeed(seed) >> 23]; +} + +// Creates an array of uniformly distributed variables. +int16_t WebRtcSpl_RandUArray(int16_t* vector, + int16_t vector_length, + uint32_t* seed) { + int i; + for (i = 0; i < vector_length; i++) { + vector[i] = WebRtcSpl_RandU(seed); + } + return vector_length; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/real_fft.c b/third_party/libwebrtc/common_audio/signal_processing/real_fft.c new file mode 100644 index 0000000000..780e517a15 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/real_fft.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/real_fft.h" + +#include <stdlib.h> + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +struct RealFFT { + int order; +}; + +struct RealFFT* WebRtcSpl_CreateRealFFT(int order) { + struct RealFFT* self = NULL; + + if (order > kMaxFFTOrder || order < 0) { + return NULL; + } + + self = malloc(sizeof(struct RealFFT)); + if (self == NULL) { + return NULL; + } + self->order = order; + + return self; +} + +void WebRtcSpl_FreeRealFFT(struct RealFFT* self) { + if (self != NULL) { + free(self); + } +} + +// The C version FFT functions (i.e. WebRtcSpl_RealForwardFFT and +// WebRtcSpl_RealInverseFFT) are real-valued FFT wrappers for complex-valued +// FFT implementation in SPL. + +int WebRtcSpl_RealForwardFFT(struct RealFFT* self, + const int16_t* real_data_in, + int16_t* complex_data_out) { + int i = 0; + int j = 0; + int result = 0; + int n = 1 << self->order; + // The complex-value FFT implementation needs a buffer to hold 2^order + // 16-bit COMPLEX numbers, for both time and frequency data. + int16_t complex_buffer[2 << kMaxFFTOrder]; + + // Insert zeros to the imaginary parts for complex forward FFT input. + for (i = 0, j = 0; i < n; i += 1, j += 2) { + complex_buffer[j] = real_data_in[i]; + complex_buffer[j + 1] = 0; + }; + + WebRtcSpl_ComplexBitReverse(complex_buffer, self->order); + result = WebRtcSpl_ComplexFFT(complex_buffer, self->order, 1); + + // For real FFT output, use only the first N + 2 elements from + // complex forward FFT. + memcpy(complex_data_out, complex_buffer, sizeof(int16_t) * (n + 2)); + + return result; +} + +int WebRtcSpl_RealInverseFFT(struct RealFFT* self, + const int16_t* complex_data_in, + int16_t* real_data_out) { + int i = 0; + int j = 0; + int result = 0; + int n = 1 << self->order; + // Create the buffer specific to complex-valued FFT implementation. + int16_t complex_buffer[2 << kMaxFFTOrder]; + + // For n-point FFT, first copy the first n + 2 elements into complex + // FFT, then construct the remaining n - 2 elements by real FFT's + // conjugate-symmetric properties. + memcpy(complex_buffer, complex_data_in, sizeof(int16_t) * (n + 2)); + for (i = n + 2; i < 2 * n; i += 2) { + complex_buffer[i] = complex_data_in[2 * n - i]; + complex_buffer[i + 1] = -complex_data_in[2 * n - i + 1]; + } + + WebRtcSpl_ComplexBitReverse(complex_buffer, self->order); + result = WebRtcSpl_ComplexIFFT(complex_buffer, self->order, 1); + + // Strip out the imaginary parts of the complex inverse FFT output. + for (i = 0, j = 0; i < n; i += 1, j += 2) { + real_data_out[i] = complex_buffer[j]; + } + + return result; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/real_fft_unittest.cc b/third_party/libwebrtc/common_audio/signal_processing/real_fft_unittest.cc new file mode 100644 index 0000000000..7cabe7d9fe --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/real_fft_unittest.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/signal_processing/include/real_fft.h" + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "test/gtest.h" + +namespace webrtc { +namespace { + +// FFT order. +const int kOrder = 5; +// Lengths for real FFT's time and frequency bufffers. +// For N-point FFT, the length requirements from API are N and N+2 respectively. +const int kTimeDataLength = 1 << kOrder; +const int kFreqDataLength = (1 << kOrder) + 2; +// For complex FFT's time and freq buffer. The implementation requires +// 2*N 16-bit words. +const int kComplexFftDataLength = 2 << kOrder; +// Reference data for time signal. +const int16_t kRefData[kTimeDataLength] = { + 11739, 6848, -8688, 31980, -30295, 25242, 27085, 19410, + -26299, 15607, -10791, 11778, -23819, 14498, -25772, 10076, + 1173, 6848, -8688, 31980, -30295, 2522, 27085, 19410, + -2629, 5607, -3, 1178, -23819, 1498, -25772, 10076}; + +TEST(RealFFTTest, CreateFailsOnBadInput) { + RealFFT* fft = WebRtcSpl_CreateRealFFT(11); + EXPECT_TRUE(fft == nullptr); + fft = WebRtcSpl_CreateRealFFT(-1); + EXPECT_TRUE(fft == nullptr); +} + +TEST(RealFFTTest, RealAndComplexMatch) { + int i = 0; + int j = 0; + int16_t real_fft_time[kTimeDataLength] = {0}; + int16_t real_fft_freq[kFreqDataLength] = {0}; + // One common buffer for complex FFT's time and frequency data. + int16_t complex_fft_buff[kComplexFftDataLength] = {0}; + + // Prepare the inputs to forward FFT's. + memcpy(real_fft_time, kRefData, sizeof(kRefData)); + for (i = 0, j = 0; i < kTimeDataLength; i += 1, j += 2) { + complex_fft_buff[j] = kRefData[i]; + complex_fft_buff[j + 1] = 0; // Insert zero's to imaginary parts. + } + + // Create and run real forward FFT. + RealFFT* fft = WebRtcSpl_CreateRealFFT(kOrder); + EXPECT_TRUE(fft != nullptr); + EXPECT_EQ(0, WebRtcSpl_RealForwardFFT(fft, real_fft_time, real_fft_freq)); + + // Run complex forward FFT. + WebRtcSpl_ComplexBitReverse(complex_fft_buff, kOrder); + EXPECT_EQ(0, WebRtcSpl_ComplexFFT(complex_fft_buff, kOrder, 1)); + + // Verify the results between complex and real forward FFT. + for (i = 0; i < kFreqDataLength; i++) { + EXPECT_EQ(real_fft_freq[i], complex_fft_buff[i]); + } + + // Prepare the inputs to inverse real FFT. + // We use whatever data in complex_fft_buff[] since we don't care + // about data contents. Only kFreqDataLength 16-bit words are copied + // from complex_fft_buff to real_fft_freq since remaining words (2nd half) + // are conjugate-symmetric to the first half in theory. + memcpy(real_fft_freq, complex_fft_buff, sizeof(real_fft_freq)); + + // Run real inverse FFT. + int real_scale = WebRtcSpl_RealInverseFFT(fft, real_fft_freq, real_fft_time); + EXPECT_GE(real_scale, 0); + + // Run complex inverse FFT. + WebRtcSpl_ComplexBitReverse(complex_fft_buff, kOrder); + int complex_scale = WebRtcSpl_ComplexIFFT(complex_fft_buff, kOrder, 1); + + // Verify the results between complex and real inverse FFT. + // They are not bit-exact, since complex IFFT doesn't produce + // exactly conjugate-symmetric data (between first and second half). + EXPECT_EQ(real_scale, complex_scale); + for (i = 0, j = 0; i < kTimeDataLength; i += 1, j += 2) { + EXPECT_LE(abs(real_fft_time[i] - complex_fft_buff[j]), 1); + } + + WebRtcSpl_FreeRealFFT(fft); +} + +} // namespace +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/signal_processing/refl_coef_to_lpc.c b/third_party/libwebrtc/common_audio/signal_processing/refl_coef_to_lpc.c new file mode 100644 index 0000000000..b0858b2b0e --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/refl_coef_to_lpc.c @@ -0,0 +1,59 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_ReflCoefToLpc(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +void WebRtcSpl_ReflCoefToLpc(const int16_t *k, int use_order, int16_t *a) +{ + int16_t any[WEBRTC_SPL_MAX_LPC_ORDER + 1]; + int16_t *aptr, *aptr2, *anyptr; + const int16_t *kptr; + int m, i; + + kptr = k; + *a = 4096; // i.e., (Word16_MAX >> 3)+1. + *any = *a; + a[1] = *k >> 3; + + for (m = 1; m < use_order; m++) + { + kptr++; + aptr = a; + aptr++; + aptr2 = &a[m]; + anyptr = any; + anyptr++; + + any[m + 1] = *kptr >> 3; + for (i = 0; i < m; i++) + { + *anyptr = *aptr + (int16_t)((*aptr2 * *kptr) >> 15); + anyptr++; + aptr++; + aptr2--; + } + + aptr = a; + anyptr = any; + for (i = 0; i < (m + 2); i++) + { + *aptr = *anyptr; + aptr++; + anyptr++; + } + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/resample.c b/third_party/libwebrtc/common_audio/signal_processing/resample.c new file mode 100644 index 0000000000..d4b2736476 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/resample.c @@ -0,0 +1,505 @@ +/* + * 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. + */ + + +/* + * This file contains the resampling functions for 22 kHz. + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "common_audio/signal_processing/resample_by_2_internal.h" + +// Declaration of internally used functions +static void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In, int16_t *Out, + int32_t K); + +void WebRtcSpl_32khzTo22khzIntToInt(const int32_t *In, int32_t *Out, + int32_t K); + +// interpolation coefficients +static const int16_t kCoefficients32To22[5][9] = { + {127, -712, 2359, -6333, 23456, 16775, -3695, 945, -154}, + {-39, 230, -830, 2785, 32366, -2324, 760, -218, 38}, + {117, -663, 2222, -6133, 26634, 13070, -3174, 831, -137}, + {-77, 457, -1677, 5958, 31175, -4136, 1405, -408, 71}, + { 98, -560, 1900, -5406, 29240, 9423, -2480, 663, -110} +}; + +////////////////////// +// 22 kHz -> 16 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 4, 5, 10 +#define SUB_BLOCKS_22_16 5 + +// 22 -> 16 resampler +void WebRtcSpl_Resample22khzTo16khz(const int16_t* in, int16_t* out, + WebRtcSpl_State22khzTo16khz* state, int32_t* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_22_16 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_22_16; k++) + { + ///// 22 --> 44 ///// + // int16_t in[220/SUB_BLOCKS_22_16] + // int32_t out[440/SUB_BLOCKS_22_16] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 220 / SUB_BLOCKS_22_16, tmpmem + 16, state->S_22_44); + + ///// 44 --> 32 ///// + // int32_t in[440/SUB_BLOCKS_22_16] + // int32_t out[320/SUB_BLOCKS_22_16] + ///// + // copy state to and from input array + tmpmem[8] = state->S_44_32[0]; + tmpmem[9] = state->S_44_32[1]; + tmpmem[10] = state->S_44_32[2]; + tmpmem[11] = state->S_44_32[3]; + tmpmem[12] = state->S_44_32[4]; + tmpmem[13] = state->S_44_32[5]; + tmpmem[14] = state->S_44_32[6]; + tmpmem[15] = state->S_44_32[7]; + state->S_44_32[0] = tmpmem[440 / SUB_BLOCKS_22_16 + 8]; + state->S_44_32[1] = tmpmem[440 / SUB_BLOCKS_22_16 + 9]; + state->S_44_32[2] = tmpmem[440 / SUB_BLOCKS_22_16 + 10]; + state->S_44_32[3] = tmpmem[440 / SUB_BLOCKS_22_16 + 11]; + state->S_44_32[4] = tmpmem[440 / SUB_BLOCKS_22_16 + 12]; + state->S_44_32[5] = tmpmem[440 / SUB_BLOCKS_22_16 + 13]; + state->S_44_32[6] = tmpmem[440 / SUB_BLOCKS_22_16 + 14]; + state->S_44_32[7] = tmpmem[440 / SUB_BLOCKS_22_16 + 15]; + + WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 40 / SUB_BLOCKS_22_16); + + ///// 32 --> 16 ///// + // int32_t in[320/SUB_BLOCKS_22_16] + // int32_t out[160/SUB_BLOCKS_22_16] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 320 / SUB_BLOCKS_22_16, out, state->S_32_16); + + // move input/output pointers 10/SUB_BLOCKS_22_16 ms seconds ahead + in += 220 / SUB_BLOCKS_22_16; + out += 160 / SUB_BLOCKS_22_16; + } +} + +// initialize state of 22 -> 16 resampler +void WebRtcSpl_ResetResample22khzTo16khz(WebRtcSpl_State22khzTo16khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_22_44[k] = 0; + state->S_44_32[k] = 0; + state->S_32_16[k] = 0; + } +} + +////////////////////// +// 16 kHz -> 22 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 4, 5, 10 +#define SUB_BLOCKS_16_22 4 + +// 16 -> 22 resampler +void WebRtcSpl_Resample16khzTo22khz(const int16_t* in, int16_t* out, + WebRtcSpl_State16khzTo22khz* state, int32_t* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_16_22 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_16_22; k++) + { + ///// 16 --> 32 ///// + // int16_t in[160/SUB_BLOCKS_16_22] + // int32_t out[320/SUB_BLOCKS_16_22] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 160 / SUB_BLOCKS_16_22, tmpmem + 8, state->S_16_32); + + ///// 32 --> 22 ///// + // int32_t in[320/SUB_BLOCKS_16_22] + // int32_t out[220/SUB_BLOCKS_16_22] + ///// + // copy state to and from input array + tmpmem[0] = state->S_32_22[0]; + tmpmem[1] = state->S_32_22[1]; + tmpmem[2] = state->S_32_22[2]; + tmpmem[3] = state->S_32_22[3]; + tmpmem[4] = state->S_32_22[4]; + tmpmem[5] = state->S_32_22[5]; + tmpmem[6] = state->S_32_22[6]; + tmpmem[7] = state->S_32_22[7]; + state->S_32_22[0] = tmpmem[320 / SUB_BLOCKS_16_22]; + state->S_32_22[1] = tmpmem[320 / SUB_BLOCKS_16_22 + 1]; + state->S_32_22[2] = tmpmem[320 / SUB_BLOCKS_16_22 + 2]; + state->S_32_22[3] = tmpmem[320 / SUB_BLOCKS_16_22 + 3]; + state->S_32_22[4] = tmpmem[320 / SUB_BLOCKS_16_22 + 4]; + state->S_32_22[5] = tmpmem[320 / SUB_BLOCKS_16_22 + 5]; + state->S_32_22[6] = tmpmem[320 / SUB_BLOCKS_16_22 + 6]; + state->S_32_22[7] = tmpmem[320 / SUB_BLOCKS_16_22 + 7]; + + WebRtcSpl_32khzTo22khzIntToShort(tmpmem, out, 20 / SUB_BLOCKS_16_22); + + // move input/output pointers 10/SUB_BLOCKS_16_22 ms seconds ahead + in += 160 / SUB_BLOCKS_16_22; + out += 220 / SUB_BLOCKS_16_22; + } +} + +// initialize state of 16 -> 22 resampler +void WebRtcSpl_ResetResample16khzTo22khz(WebRtcSpl_State16khzTo22khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_16_32[k] = 0; + state->S_32_22[k] = 0; + } +} + +////////////////////// +// 22 kHz -> 8 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 5, 10 +#define SUB_BLOCKS_22_8 2 + +// 22 -> 8 resampler +void WebRtcSpl_Resample22khzTo8khz(const int16_t* in, int16_t* out, + WebRtcSpl_State22khzTo8khz* state, int32_t* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_22_8 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_22_8; k++) + { + ///// 22 --> 22 lowpass ///// + // int16_t in[220/SUB_BLOCKS_22_8] + // int32_t out[220/SUB_BLOCKS_22_8] + ///// + WebRtcSpl_LPBy2ShortToInt(in, 220 / SUB_BLOCKS_22_8, tmpmem + 16, state->S_22_22); + + ///// 22 --> 16 ///// + // int32_t in[220/SUB_BLOCKS_22_8] + // int32_t out[160/SUB_BLOCKS_22_8] + ///// + // copy state to and from input array + tmpmem[8] = state->S_22_16[0]; + tmpmem[9] = state->S_22_16[1]; + tmpmem[10] = state->S_22_16[2]; + tmpmem[11] = state->S_22_16[3]; + tmpmem[12] = state->S_22_16[4]; + tmpmem[13] = state->S_22_16[5]; + tmpmem[14] = state->S_22_16[6]; + tmpmem[15] = state->S_22_16[7]; + state->S_22_16[0] = tmpmem[220 / SUB_BLOCKS_22_8 + 8]; + state->S_22_16[1] = tmpmem[220 / SUB_BLOCKS_22_8 + 9]; + state->S_22_16[2] = tmpmem[220 / SUB_BLOCKS_22_8 + 10]; + state->S_22_16[3] = tmpmem[220 / SUB_BLOCKS_22_8 + 11]; + state->S_22_16[4] = tmpmem[220 / SUB_BLOCKS_22_8 + 12]; + state->S_22_16[5] = tmpmem[220 / SUB_BLOCKS_22_8 + 13]; + state->S_22_16[6] = tmpmem[220 / SUB_BLOCKS_22_8 + 14]; + state->S_22_16[7] = tmpmem[220 / SUB_BLOCKS_22_8 + 15]; + + WebRtcSpl_Resample44khzTo32khz(tmpmem + 8, tmpmem, 20 / SUB_BLOCKS_22_8); + + ///// 16 --> 8 ///// + // int32_t in[160/SUB_BLOCKS_22_8] + // int32_t out[80/SUB_BLOCKS_22_8] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 160 / SUB_BLOCKS_22_8, out, state->S_16_8); + + // move input/output pointers 10/SUB_BLOCKS_22_8 ms seconds ahead + in += 220 / SUB_BLOCKS_22_8; + out += 80 / SUB_BLOCKS_22_8; + } +} + +// initialize state of 22 -> 8 resampler +void WebRtcSpl_ResetResample22khzTo8khz(WebRtcSpl_State22khzTo8khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_22_22[k] = 0; + state->S_22_22[k + 8] = 0; + state->S_22_16[k] = 0; + state->S_16_8[k] = 0; + } +} + +////////////////////// +// 8 kHz -> 22 kHz // +////////////////////// + +// number of subblocks; options: 1, 2, 5, 10 +#define SUB_BLOCKS_8_22 2 + +// 8 -> 22 resampler +void WebRtcSpl_Resample8khzTo22khz(const int16_t* in, int16_t* out, + WebRtcSpl_State8khzTo22khz* state, int32_t* tmpmem) +{ + int k; + + // process two blocks of 10/SUB_BLOCKS_8_22 ms (to reduce temp buffer size) + for (k = 0; k < SUB_BLOCKS_8_22; k++) + { + ///// 8 --> 16 ///// + // int16_t in[80/SUB_BLOCKS_8_22] + // int32_t out[160/SUB_BLOCKS_8_22] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 80 / SUB_BLOCKS_8_22, tmpmem + 18, state->S_8_16); + + ///// 16 --> 11 ///// + // int32_t in[160/SUB_BLOCKS_8_22] + // int32_t out[110/SUB_BLOCKS_8_22] + ///// + // copy state to and from input array + tmpmem[10] = state->S_16_11[0]; + tmpmem[11] = state->S_16_11[1]; + tmpmem[12] = state->S_16_11[2]; + tmpmem[13] = state->S_16_11[3]; + tmpmem[14] = state->S_16_11[4]; + tmpmem[15] = state->S_16_11[5]; + tmpmem[16] = state->S_16_11[6]; + tmpmem[17] = state->S_16_11[7]; + state->S_16_11[0] = tmpmem[160 / SUB_BLOCKS_8_22 + 10]; + state->S_16_11[1] = tmpmem[160 / SUB_BLOCKS_8_22 + 11]; + state->S_16_11[2] = tmpmem[160 / SUB_BLOCKS_8_22 + 12]; + state->S_16_11[3] = tmpmem[160 / SUB_BLOCKS_8_22 + 13]; + state->S_16_11[4] = tmpmem[160 / SUB_BLOCKS_8_22 + 14]; + state->S_16_11[5] = tmpmem[160 / SUB_BLOCKS_8_22 + 15]; + state->S_16_11[6] = tmpmem[160 / SUB_BLOCKS_8_22 + 16]; + state->S_16_11[7] = tmpmem[160 / SUB_BLOCKS_8_22 + 17]; + + WebRtcSpl_32khzTo22khzIntToInt(tmpmem + 10, tmpmem, 10 / SUB_BLOCKS_8_22); + + ///// 11 --> 22 ///// + // int32_t in[110/SUB_BLOCKS_8_22] + // int16_t out[220/SUB_BLOCKS_8_22] + ///// + WebRtcSpl_UpBy2IntToShort(tmpmem, 110 / SUB_BLOCKS_8_22, out, state->S_11_22); + + // move input/output pointers 10/SUB_BLOCKS_8_22 ms seconds ahead + in += 80 / SUB_BLOCKS_8_22; + out += 220 / SUB_BLOCKS_8_22; + } +} + +// initialize state of 8 -> 22 resampler +void WebRtcSpl_ResetResample8khzTo22khz(WebRtcSpl_State8khzTo22khz* state) +{ + int k; + for (k = 0; k < 8; k++) + { + state->S_8_16[k] = 0; + state->S_16_11[k] = 0; + state->S_11_22[k] = 0; + } +} + +// compute two inner-products and store them to output array +static void WebRtcSpl_DotProdIntToInt(const int32_t* in1, const int32_t* in2, + const int16_t* coef_ptr, int32_t* out1, + int32_t* out2) +{ + int32_t tmp1 = 16384; + int32_t tmp2 = 16384; + int16_t coef; + + coef = coef_ptr[0]; + tmp1 += coef * in1[0]; + tmp2 += coef * in2[-0]; + + coef = coef_ptr[1]; + tmp1 += coef * in1[1]; + tmp2 += coef * in2[-1]; + + coef = coef_ptr[2]; + tmp1 += coef * in1[2]; + tmp2 += coef * in2[-2]; + + coef = coef_ptr[3]; + tmp1 += coef * in1[3]; + tmp2 += coef * in2[-3]; + + coef = coef_ptr[4]; + tmp1 += coef * in1[4]; + tmp2 += coef * in2[-4]; + + coef = coef_ptr[5]; + tmp1 += coef * in1[5]; + tmp2 += coef * in2[-5]; + + coef = coef_ptr[6]; + tmp1 += coef * in1[6]; + tmp2 += coef * in2[-6]; + + coef = coef_ptr[7]; + tmp1 += coef * in1[7]; + tmp2 += coef * in2[-7]; + + coef = coef_ptr[8]; + *out1 = tmp1 + coef * in1[8]; + *out2 = tmp2 + coef * in2[-8]; +} + +// compute two inner-products and store them to output array +static void WebRtcSpl_DotProdIntToShort(const int32_t* in1, const int32_t* in2, + const int16_t* coef_ptr, int16_t* out1, + int16_t* out2) +{ + int32_t tmp1 = 16384; + int32_t tmp2 = 16384; + int16_t coef; + + coef = coef_ptr[0]; + tmp1 += coef * in1[0]; + tmp2 += coef * in2[-0]; + + coef = coef_ptr[1]; + tmp1 += coef * in1[1]; + tmp2 += coef * in2[-1]; + + coef = coef_ptr[2]; + tmp1 += coef * in1[2]; + tmp2 += coef * in2[-2]; + + coef = coef_ptr[3]; + tmp1 += coef * in1[3]; + tmp2 += coef * in2[-3]; + + coef = coef_ptr[4]; + tmp1 += coef * in1[4]; + tmp2 += coef * in2[-4]; + + coef = coef_ptr[5]; + tmp1 += coef * in1[5]; + tmp2 += coef * in2[-5]; + + coef = coef_ptr[6]; + tmp1 += coef * in1[6]; + tmp2 += coef * in2[-6]; + + coef = coef_ptr[7]; + tmp1 += coef * in1[7]; + tmp2 += coef * in2[-7]; + + coef = coef_ptr[8]; + tmp1 += coef * in1[8]; + tmp2 += coef * in2[-8]; + + // scale down, round and saturate + tmp1 >>= 15; + if (tmp1 > (int32_t)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (int32_t)0xFFFF8000) + tmp1 = 0xFFFF8000; + tmp2 >>= 15; + if (tmp2 > (int32_t)0x00007FFF) + tmp2 = 0x00007FFF; + if (tmp2 < (int32_t)0xFFFF8000) + tmp2 = 0xFFFF8000; + *out1 = (int16_t)tmp1; + *out2 = (int16_t)tmp2; +} + +// Resampling ratio: 11/16 +// input: int32_t (normalized, not saturated) :: size 16 * K +// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 11 * K +// K: Number of blocks + +void WebRtcSpl_32khzTo22khzIntToInt(const int32_t* In, + int32_t* Out, + int32_t K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (16 input samples -> 11 output samples); + // process in sub blocks of size 16 samples. + int32_t m; + + for (m = 0; m < K; m++) + { + // first output sample + Out[0] = ((int32_t)In[3] << 15) + (1 << 14); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToInt(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]); + + // update pointers + In += 16; + Out += 11; + } +} + +// Resampling ratio: 11/16 +// input: int32_t (normalized, not saturated) :: size 16 * K +// output: int16_t (saturated) :: size 11 * K +// K: Number of blocks + +void WebRtcSpl_32khzTo22khzIntToShort(const int32_t *In, + int16_t *Out, + int32_t K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (16 input samples -> 11 output samples); + // process in sub blocks of size 16 samples. + int32_t tmp; + int32_t m; + + for (m = 0; m < K; m++) + { + // first output sample + tmp = In[3]; + if (tmp > (int32_t)0x00007FFF) + tmp = 0x00007FFF; + if (tmp < (int32_t)0xFFFF8000) + tmp = 0xFFFF8000; + Out[0] = (int16_t)tmp; + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[0], &In[22], kCoefficients32To22[0], &Out[1], &Out[10]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[2], &In[20], kCoefficients32To22[1], &Out[2], &Out[9]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[3], &In[19], kCoefficients32To22[2], &Out[3], &Out[8]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[5], &In[17], kCoefficients32To22[3], &Out[4], &Out[7]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_DotProdIntToShort(&In[6], &In[16], kCoefficients32To22[4], &Out[5], &Out[6]); + + // update pointers + In += 16; + Out += 11; + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/resample_48khz.c b/third_party/libwebrtc/common_audio/signal_processing/resample_48khz.c new file mode 100644 index 0000000000..8518e7b1ce --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/resample_48khz.c @@ -0,0 +1,186 @@ +/* + * 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. + */ + + +/* + * This file contains resampling functions between 48 kHz and nb/wb. + * The description header can be found in signal_processing_library.h + * + */ + +#include <string.h> +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "common_audio/signal_processing/resample_by_2_internal.h" + +//////////////////////////// +///// 48 kHz -> 16 kHz ///// +//////////////////////////// + +// 48 -> 16 resampler +void WebRtcSpl_Resample48khzTo16khz(const int16_t* in, int16_t* out, + WebRtcSpl_State48khzTo16khz* state, int32_t* tmpmem) +{ + ///// 48 --> 48(LP) ///// + // int16_t in[480] + // int32_t out[480] + ///// + WebRtcSpl_LPBy2ShortToInt(in, 480, tmpmem + 16, state->S_48_48); + + ///// 48 --> 32 ///// + // int32_t in[480] + // int32_t out[320] + ///// + // copy state to and from input array + memcpy(tmpmem + 8, state->S_48_32, 8 * sizeof(int32_t)); + memcpy(state->S_48_32, tmpmem + 488, 8 * sizeof(int32_t)); + WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 160); + + ///// 32 --> 16 ///// + // int32_t in[320] + // int16_t out[160] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 320, out, state->S_32_16); +} + +// initialize state of 48 -> 16 resampler +void WebRtcSpl_ResetResample48khzTo16khz(WebRtcSpl_State48khzTo16khz* state) +{ + memset(state->S_48_48, 0, 16 * sizeof(int32_t)); + memset(state->S_48_32, 0, 8 * sizeof(int32_t)); + memset(state->S_32_16, 0, 8 * sizeof(int32_t)); +} + +//////////////////////////// +///// 16 kHz -> 48 kHz ///// +//////////////////////////// + +// 16 -> 48 resampler +void WebRtcSpl_Resample16khzTo48khz(const int16_t* in, int16_t* out, + WebRtcSpl_State16khzTo48khz* state, int32_t* tmpmem) +{ + ///// 16 --> 32 ///// + // int16_t in[160] + // int32_t out[320] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 160, tmpmem + 16, state->S_16_32); + + ///// 32 --> 24 ///// + // int32_t in[320] + // int32_t out[240] + // copy state to and from input array + ///// + memcpy(tmpmem + 8, state->S_32_24, 8 * sizeof(int32_t)); + memcpy(state->S_32_24, tmpmem + 328, 8 * sizeof(int32_t)); + WebRtcSpl_Resample32khzTo24khz(tmpmem + 8, tmpmem, 80); + + ///// 24 --> 48 ///// + // int32_t in[240] + // int16_t out[480] + ///// + WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48); +} + +// initialize state of 16 -> 48 resampler +void WebRtcSpl_ResetResample16khzTo48khz(WebRtcSpl_State16khzTo48khz* state) +{ + memset(state->S_16_32, 0, 8 * sizeof(int32_t)); + memset(state->S_32_24, 0, 8 * sizeof(int32_t)); + memset(state->S_24_48, 0, 8 * sizeof(int32_t)); +} + +//////////////////////////// +///// 48 kHz -> 8 kHz ///// +//////////////////////////// + +// 48 -> 8 resampler +void WebRtcSpl_Resample48khzTo8khz(const int16_t* in, int16_t* out, + WebRtcSpl_State48khzTo8khz* state, int32_t* tmpmem) +{ + ///// 48 --> 24 ///// + // int16_t in[480] + // int32_t out[240] + ///// + WebRtcSpl_DownBy2ShortToInt(in, 480, tmpmem + 256, state->S_48_24); + + ///// 24 --> 24(LP) ///// + // int32_t in[240] + // int32_t out[240] + ///// + WebRtcSpl_LPBy2IntToInt(tmpmem + 256, 240, tmpmem + 16, state->S_24_24); + + ///// 24 --> 16 ///// + // int32_t in[240] + // int32_t out[160] + ///// + // copy state to and from input array + memcpy(tmpmem + 8, state->S_24_16, 8 * sizeof(int32_t)); + memcpy(state->S_24_16, tmpmem + 248, 8 * sizeof(int32_t)); + WebRtcSpl_Resample48khzTo32khz(tmpmem + 8, tmpmem, 80); + + ///// 16 --> 8 ///// + // int32_t in[160] + // int16_t out[80] + ///// + WebRtcSpl_DownBy2IntToShort(tmpmem, 160, out, state->S_16_8); +} + +// initialize state of 48 -> 8 resampler +void WebRtcSpl_ResetResample48khzTo8khz(WebRtcSpl_State48khzTo8khz* state) +{ + memset(state->S_48_24, 0, 8 * sizeof(int32_t)); + memset(state->S_24_24, 0, 16 * sizeof(int32_t)); + memset(state->S_24_16, 0, 8 * sizeof(int32_t)); + memset(state->S_16_8, 0, 8 * sizeof(int32_t)); +} + +//////////////////////////// +///// 8 kHz -> 48 kHz ///// +//////////////////////////// + +// 8 -> 48 resampler +void WebRtcSpl_Resample8khzTo48khz(const int16_t* in, int16_t* out, + WebRtcSpl_State8khzTo48khz* state, int32_t* tmpmem) +{ + ///// 8 --> 16 ///// + // int16_t in[80] + // int32_t out[160] + ///// + WebRtcSpl_UpBy2ShortToInt(in, 80, tmpmem + 264, state->S_8_16); + + ///// 16 --> 12 ///// + // int32_t in[160] + // int32_t out[120] + ///// + // copy state to and from input array + memcpy(tmpmem + 256, state->S_16_12, 8 * sizeof(int32_t)); + memcpy(state->S_16_12, tmpmem + 416, 8 * sizeof(int32_t)); + WebRtcSpl_Resample32khzTo24khz(tmpmem + 256, tmpmem + 240, 40); + + ///// 12 --> 24 ///// + // int32_t in[120] + // int16_t out[240] + ///// + WebRtcSpl_UpBy2IntToInt(tmpmem + 240, 120, tmpmem, state->S_12_24); + + ///// 24 --> 48 ///// + // int32_t in[240] + // int16_t out[480] + ///// + WebRtcSpl_UpBy2IntToShort(tmpmem, 240, out, state->S_24_48); +} + +// initialize state of 8 -> 48 resampler +void WebRtcSpl_ResetResample8khzTo48khz(WebRtcSpl_State8khzTo48khz* state) +{ + memset(state->S_8_16, 0, 8 * sizeof(int32_t)); + memset(state->S_16_12, 0, 8 * sizeof(int32_t)); + memset(state->S_12_24, 0, 8 * sizeof(int32_t)); + memset(state->S_24_48, 0, 8 * sizeof(int32_t)); +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/resample_by_2.c b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2.c new file mode 100644 index 0000000000..73e1950654 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2.c @@ -0,0 +1,183 @@ +/* + * 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. + */ + + +/* + * This file contains the resampling by two functions. + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#ifdef WEBRTC_ARCH_ARM_V7 + +// allpass filter coefficients. +static const uint32_t kResampleAllpass1[3] = {3284, 24441, 49528 << 15}; +static const uint32_t kResampleAllpass2[3] = + {12199, 37471 << 15, 60255 << 15}; + +// Multiply two 32-bit values and accumulate to another input value. +// Return: state + ((diff * tbl_value) >> 16) + +static __inline int32_t MUL_ACCUM_1(int32_t tbl_value, + int32_t diff, + int32_t state) { + int32_t result; + __asm __volatile ("smlawb %0, %1, %2, %3": "=r"(result): "r"(diff), + "r"(tbl_value), "r"(state)); + return result; +} + +// Multiply two 32-bit values and accumulate to another input value. +// Return: Return: state + (((diff << 1) * tbl_value) >> 32) +// +// The reason to introduce this function is that, in case we can't use smlawb +// instruction (in MUL_ACCUM_1) due to input value range, we can still use +// smmla to save some cycles. + +static __inline int32_t MUL_ACCUM_2(int32_t tbl_value, + int32_t diff, + int32_t state) { + int32_t result; + __asm __volatile ("smmla %0, %1, %2, %3": "=r"(result): "r"(diff << 1), + "r"(tbl_value), "r"(state)); + return result; +} + +#else + +// allpass filter coefficients. +static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528}; +static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255}; + +// Multiply a 32-bit value with a 16-bit value and accumulate to another input: +#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) +#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) + +#endif // WEBRTC_ARCH_ARM_V7 + + +// decimator +#if !defined(MIPS32_LE) +void WebRtcSpl_DownsampleBy2(const int16_t* in, size_t len, + int16_t* out, int32_t* filtState) { + int32_t tmp1, tmp2, diff, in32, out32; + size_t i; + + register int32_t state0 = filtState[0]; + register int32_t state1 = filtState[1]; + register int32_t state2 = filtState[2]; + register int32_t state3 = filtState[3]; + register int32_t state4 = filtState[4]; + register int32_t state5 = filtState[5]; + register int32_t state6 = filtState[6]; + register int32_t state7 = filtState[7]; + + for (i = (len >> 1); i > 0; i--) { + // lower allpass filter + in32 = (int32_t)(*in++) * (1 << 10); + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); + state2 = tmp2; + + // upper allpass filter + in32 = (int32_t)(*in++) * (1 << 10); + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); + state6 = tmp2; + + // add two allpass outputs, divide by two and round + out32 = (state3 + state7 + 1024) >> 11; + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + } + + filtState[0] = state0; + filtState[1] = state1; + filtState[2] = state2; + filtState[3] = state3; + filtState[4] = state4; + filtState[5] = state5; + filtState[6] = state6; + filtState[7] = state7; +} +#endif // #if defined(MIPS32_LE) + + +void WebRtcSpl_UpsampleBy2(const int16_t* in, size_t len, + int16_t* out, int32_t* filtState) { + int32_t tmp1, tmp2, diff, in32, out32; + size_t i; + + register int32_t state0 = filtState[0]; + register int32_t state1 = filtState[1]; + register int32_t state2 = filtState[2]; + register int32_t state3 = filtState[3]; + register int32_t state4 = filtState[4]; + register int32_t state5 = filtState[5]; + register int32_t state6 = filtState[6]; + register int32_t state7 = filtState[7]; + + for (i = len; i > 0; i--) { + // lower allpass filter + in32 = (int32_t)(*in++) * (1 << 10); + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state2); + state2 = tmp2; + + // round; limit amplitude to prevent wrap-around; write to output array + out32 = (state3 + 512) >> 10; + *out++ = WebRtcSpl_SatW32ToW16(out32); + + // upper allpass filter + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state6); + state6 = tmp2; + + // round; limit amplitude to prevent wrap-around; write to output array + out32 = (state7 + 512) >> 10; + *out++ = WebRtcSpl_SatW32ToW16(out32); + } + + filtState[0] = state0; + filtState[1] = state1; + filtState[2] = state2; + filtState[3] = state3; + filtState[4] = state4; + filtState[5] = state5; + filtState[6] = state6; + filtState[7] = state7; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_internal.c b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_internal.c new file mode 100644 index 0000000000..99592b20b5 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_internal.c @@ -0,0 +1,689 @@ +/* + * 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. + */ + + +/* + * This header file contains some internal resampling functions. + * + */ + +#include "common_audio/signal_processing/resample_by_2_internal.h" +#include "rtc_base/sanitizer.h" + +// allpass filter coefficients. +static const int16_t kResampleAllpass[2][3] = { + {821, 6110, 12382}, + {3050, 9368, 15063} +}; + +// +// decimator +// input: int32_t (shifted 15 positions to the left, + offset 16384) OVERWRITTEN! +// output: int16_t (saturated) (of length len/2) +// state: filter state array; length = 8 + +void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 +WebRtcSpl_DownBy2IntToShort(int32_t *in, int32_t len, int16_t *out, + int32_t *state) +{ + int32_t tmp0, tmp1, diff; + int32_t i; + + len >>= 1; + + // lower allpass filter (operates on even input samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[1]; + // UBSan: -1771017321 - 999586185 cannot be represented in type 'int' + + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // divide by two and store temporarily + in[i << 1] = (state[3] >> 1); + } + + in++; + + // upper allpass filter (operates on odd input samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // divide by two and store temporarily + in[i << 1] = (state[7] >> 1); + } + + in--; + + // combine allpass outputs + for (i = 0; i < len; i += 2) + { + // divide by two, add both allpass outputs and round + tmp0 = (in[i << 1] + in[(i << 1) + 1]) >> 15; + tmp1 = (in[(i << 1) + 2] + in[(i << 1) + 3]) >> 15; + if (tmp0 > (int32_t)0x00007FFF) + tmp0 = 0x00007FFF; + if (tmp0 < (int32_t)0xFFFF8000) + tmp0 = 0xFFFF8000; + out[i] = (int16_t)tmp0; + if (tmp1 > (int32_t)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (int32_t)0xFFFF8000) + tmp1 = 0xFFFF8000; + out[i + 1] = (int16_t)tmp1; + } +} + +// +// decimator +// input: int16_t +// output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len/2) +// state: filter state array; length = 8 + +void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 +WebRtcSpl_DownBy2ShortToInt(const int16_t *in, + int32_t len, + int32_t *out, + int32_t *state) +{ + int32_t tmp0, tmp1, diff; + int32_t i; + + len >>= 1; + + // lower allpass filter (operates on even input samples) + for (i = 0; i < len; i++) + { + tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // UBSan: -1379909682 - 834099714 cannot be represented in type 'int' + + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // divide by two and store temporarily + out[i] = (state[3] >> 1); + } + + in++; + + // upper allpass filter (operates on odd input samples) + for (i = 0; i < len; i++) + { + tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // divide by two and store temporarily + out[i] += (state[7] >> 1); + } + + in--; +} + +// +// interpolator +// input: int16_t +// output: int32_t (normalized, not saturated) (of length len*2) +// state: filter state array; length = 8 +void WebRtcSpl_UpBy2ShortToInt(const int16_t *in, int32_t len, int32_t *out, + int32_t *state) +{ + int32_t tmp0, tmp1, diff; + int32_t i; + + // upper allpass filter (generates odd output samples) + for (i = 0; i < len; i++) + { + tmp0 = ((int32_t)in[i] << 15) + (1 << 14); + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // scale down, round and store + out[i << 1] = state[7] >> 15; + } + + out++; + + // lower allpass filter (generates even output samples) + for (i = 0; i < len; i++) + { + tmp0 = ((int32_t)in[i] << 15) + (1 << 14); + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3] >> 15; + } +} + +// +// interpolator +// input: int32_t (shifted 15 positions to the left, + offset 16384) +// output: int32_t (shifted 15 positions to the left, + offset 16384) (of length len*2) +// state: filter state array; length = 8 +void WebRtcSpl_UpBy2IntToInt(const int32_t *in, int32_t len, int32_t *out, + int32_t *state) +{ + int32_t tmp0, tmp1, diff; + int32_t i; + + // upper allpass filter (generates odd output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // scale down, round and store + out[i << 1] = state[7]; + } + + out++; + + // lower allpass filter (generates even output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3]; + } +} + +// +// interpolator +// input: int32_t (shifted 15 positions to the left, + offset 16384) +// output: int16_t (saturated) (of length len*2) +// state: filter state array; length = 8 +void WebRtcSpl_UpBy2IntToShort(const int32_t *in, int32_t len, int16_t *out, + int32_t *state) +{ + int32_t tmp0, tmp1, diff; + int32_t i; + + // upper allpass filter (generates odd output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // scale down, saturate and store + tmp1 = state[7] >> 15; + if (tmp1 > (int32_t)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (int32_t)0xFFFF8000) + tmp1 = 0xFFFF8000; + out[i << 1] = (int16_t)tmp1; + } + + out++; + + // lower allpass filter (generates even output samples) + for (i = 0; i < len; i++) + { + tmp0 = in[i]; + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, saturate and store + tmp1 = state[3] >> 15; + if (tmp1 > (int32_t)0x00007FFF) + tmp1 = 0x00007FFF; + if (tmp1 < (int32_t)0xFFFF8000) + tmp1 = 0xFFFF8000; + out[i << 1] = (int16_t)tmp1; + } +} + +// lowpass filter +// input: int16_t +// output: int32_t (normalized, not saturated) +// state: filter state array; length = 8 +void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, int32_t len, int32_t* out, + int32_t* state) +{ + int32_t tmp0, tmp1, diff; + int32_t i; + + len >>= 1; + + // lower allpass filter: odd input -> even output samples + in++; + // initial state of polyphase delay element + tmp0 = state[12]; + for (i = 0; i < len; i++) + { + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3] >> 1; + tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); + } + in--; + + // upper allpass filter: even input -> even output samples + for (i = 0; i < len; i++) + { + tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[5]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15; + } + + // switch to odd output samples + out++; + + // lower allpass filter: even input -> odd output samples + for (i = 0; i < len; i++) + { + tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[9]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[8] + diff * kResampleAllpass[1][0]; + state[8] = tmp0; + diff = tmp1 - state[10]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[9] + diff * kResampleAllpass[1][1]; + state[9] = tmp1; + diff = tmp0 - state[11]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[11] = state[10] + diff * kResampleAllpass[1][2]; + state[10] = tmp0; + + // scale down, round and store + out[i << 1] = state[11] >> 1; + } + + // upper allpass filter: odd input -> odd output samples + in++; + for (i = 0; i < len; i++) + { + tmp0 = ((int32_t)in[i << 1] << 15) + (1 << 14); + diff = tmp0 - state[13]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[12] + diff * kResampleAllpass[0][0]; + state[12] = tmp0; + diff = tmp1 - state[14]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[13] + diff * kResampleAllpass[0][1]; + state[13] = tmp1; + diff = tmp0 - state[15]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[15] = state[14] + diff * kResampleAllpass[0][2]; + state[14] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15; + } +} + +// lowpass filter +// input: int32_t (shifted 15 positions to the left, + offset 16384) +// output: int32_t (normalized, not saturated) +// state: filter state array; length = 8 +void RTC_NO_SANITIZE("signed-integer-overflow") // bugs.webrtc.org/5486 +WebRtcSpl_LPBy2IntToInt(const int32_t* in, int32_t len, int32_t* out, + int32_t* state) +{ + int32_t tmp0, tmp1, diff; + int32_t i; + + len >>= 1; + + // lower allpass filter: odd input -> even output samples + in++; + // initial state of polyphase delay element + tmp0 = state[12]; + for (i = 0; i < len; i++) + { + diff = tmp0 - state[1]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[0] + diff * kResampleAllpass[1][0]; + state[0] = tmp0; + diff = tmp1 - state[2]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[1] + diff * kResampleAllpass[1][1]; + state[1] = tmp1; + diff = tmp0 - state[3]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[3] = state[2] + diff * kResampleAllpass[1][2]; + state[2] = tmp0; + + // scale down, round and store + out[i << 1] = state[3] >> 1; + tmp0 = in[i << 1]; + } + in--; + + // upper allpass filter: even input -> even output samples + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[5]; + // UBSan: -794814117 - 1566149201 cannot be represented in type 'int' + + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[4] + diff * kResampleAllpass[0][0]; + state[4] = tmp0; + diff = tmp1 - state[6]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[5] + diff * kResampleAllpass[0][1]; + state[5] = tmp1; + diff = tmp0 - state[7]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[7] = state[6] + diff * kResampleAllpass[0][2]; + state[6] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[7] >> 1)) >> 15; + } + + // switch to odd output samples + out++; + + // lower allpass filter: even input -> odd output samples + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[9]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[8] + diff * kResampleAllpass[1][0]; + state[8] = tmp0; + diff = tmp1 - state[10]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[9] + diff * kResampleAllpass[1][1]; + state[9] = tmp1; + diff = tmp0 - state[11]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[11] = state[10] + diff * kResampleAllpass[1][2]; + state[10] = tmp0; + + // scale down, round and store + out[i << 1] = state[11] >> 1; + } + + // upper allpass filter: odd input -> odd output samples + in++; + for (i = 0; i < len; i++) + { + tmp0 = in[i << 1]; + diff = tmp0 - state[13]; + // scale down and round + diff = (diff + (1 << 13)) >> 14; + tmp1 = state[12] + diff * kResampleAllpass[0][0]; + state[12] = tmp0; + diff = tmp1 - state[14]; + // scale down and round + diff = diff >> 14; + if (diff < 0) + diff += 1; + tmp0 = state[13] + diff * kResampleAllpass[0][1]; + state[13] = tmp1; + diff = tmp0 - state[15]; + // scale down and truncate + diff = diff >> 14; + if (diff < 0) + diff += 1; + state[15] = state[14] + diff * kResampleAllpass[0][2]; + state[14] = tmp0; + + // average the two allpass outputs, scale down and store + out[i << 1] = (out[i << 1] + (state[15] >> 1)) >> 15; + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_internal.h b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_internal.h new file mode 100644 index 0000000000..145395a4cb --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_internal.h @@ -0,0 +1,60 @@ +/* + * 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. + */ + +/* + * This header file contains some internal resampling functions. + * + */ + +#ifndef COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ +#define COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ + +#include <stdint.h> + +/******************************************************************* + * resample_by_2_fast.c + * Functions for internal use in the other resample functions + ******************************************************************/ +void WebRtcSpl_DownBy2IntToShort(int32_t* in, + int32_t len, + int16_t* out, + int32_t* state); + +void WebRtcSpl_DownBy2ShortToInt(const int16_t* in, + int32_t len, + int32_t* out, + int32_t* state); + +void WebRtcSpl_UpBy2ShortToInt(const int16_t* in, + int32_t len, + int32_t* out, + int32_t* state); + +void WebRtcSpl_UpBy2IntToInt(const int32_t* in, + int32_t len, + int32_t* out, + int32_t* state); + +void WebRtcSpl_UpBy2IntToShort(const int32_t* in, + int32_t len, + int16_t* out, + int32_t* state); + +void WebRtcSpl_LPBy2ShortToInt(const int16_t* in, + int32_t len, + int32_t* out, + int32_t* state); + +void WebRtcSpl_LPBy2IntToInt(const int32_t* in, + int32_t len, + int32_t* out, + int32_t* state); + +#endif // COMMON_AUDIO_SIGNAL_PROCESSING_RESAMPLE_BY_2_INTERNAL_H_ diff --git a/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_mips.c b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_mips.c new file mode 100644 index 0000000000..f41bab7519 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/resample_by_2_mips.c @@ -0,0 +1,292 @@ +/* + * 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 file contains the resampling by two functions. + * The description header can be found in signal_processing_library.h + * + */ + +#if defined(MIPS32_LE) + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +#if !defined(MIPS_DSP_R2_LE) +// allpass filter coefficients. +static const uint16_t kResampleAllpass1[3] = {3284, 24441, 49528}; +static const uint16_t kResampleAllpass2[3] = {12199, 37471, 60255}; +#endif + +// Multiply a 32-bit value with a 16-bit value and accumulate to another input: +#define MUL_ACCUM_1(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) +#define MUL_ACCUM_2(a, b, c) WEBRTC_SPL_SCALEDIFF32(a, b, c) + +// decimator +void WebRtcSpl_DownsampleBy2(const int16_t* in, + size_t len, + int16_t* out, + int32_t* filtState) { + int32_t out32; + size_t i, len1; + + register int32_t state0 = filtState[0]; + register int32_t state1 = filtState[1]; + register int32_t state2 = filtState[2]; + register int32_t state3 = filtState[3]; + register int32_t state4 = filtState[4]; + register int32_t state5 = filtState[5]; + register int32_t state6 = filtState[6]; + register int32_t state7 = filtState[7]; + +#if defined(MIPS_DSP_R2_LE) + int32_t k1Res0, k1Res1, k1Res2, k2Res0, k2Res1, k2Res2; + + k1Res0= 3284; + k1Res1= 24441; + k1Res2= 49528; + k2Res0= 12199; + k2Res1= 37471; + k2Res2= 60255; + len1 = (len >> 1); + + const int32_t* inw = (int32_t*)in; + int32_t tmp11, tmp12, tmp21, tmp22; + int32_t in322, in321; + int32_t diff1, diff2; + for (i = len1; i > 0; i--) { + __asm__ volatile ( + "lh %[in321], 0(%[inw]) \n\t" + "lh %[in322], 2(%[inw]) \n\t" + + "sll %[in321], %[in321], 10 \n\t" + "sll %[in322], %[in322], 10 \n\t" + + "addiu %[inw], %[inw], 4 \n\t" + + "subu %[diff1], %[in321], %[state1] \n\t" + "subu %[diff2], %[in322], %[state5] \n\t" + + : [in322] "=&r" (in322), [in321] "=&r" (in321), + [diff1] "=&r" (diff1), [diff2] "=r" (diff2), [inw] "+r" (inw) + : [state1] "r" (state1), [state5] "r" (state5) + : "memory" + ); + + __asm__ volatile ( + "mult $ac0, %[diff1], %[k2Res0] \n\t" + "mult $ac1, %[diff2], %[k1Res0] \n\t" + + "extr.w %[tmp11], $ac0, 16 \n\t" + "extr.w %[tmp12], $ac1, 16 \n\t" + + "addu %[tmp11], %[state0], %[tmp11] \n\t" + "addu %[tmp12], %[state4], %[tmp12] \n\t" + + "addiu %[state0], %[in321], 0 \n\t" + "addiu %[state4], %[in322], 0 \n\t" + + "subu %[diff1], %[tmp11], %[state2] \n\t" + "subu %[diff2], %[tmp12], %[state6] \n\t" + + "mult $ac0, %[diff1], %[k2Res1] \n\t" + "mult $ac1, %[diff2], %[k1Res1] \n\t" + + "extr.w %[tmp21], $ac0, 16 \n\t" + "extr.w %[tmp22], $ac1, 16 \n\t" + + "addu %[tmp21], %[state1], %[tmp21] \n\t" + "addu %[tmp22], %[state5], %[tmp22] \n\t" + + "addiu %[state1], %[tmp11], 0 \n\t" + "addiu %[state5], %[tmp12], 0 \n\t" + : [tmp22] "=r" (tmp22), [tmp21] "=&r" (tmp21), + [tmp11] "=&r" (tmp11), [state0] "+r" (state0), + [state1] "+r" (state1), + [state2] "+r" (state2), + [state4] "+r" (state4), [tmp12] "=&r" (tmp12), + [state6] "+r" (state6), [state5] "+r" (state5) + : [k1Res1] "r" (k1Res1), [k2Res1] "r" (k2Res1), [k2Res0] "r" (k2Res0), + [diff2] "r" (diff2), [diff1] "r" (diff1), [in322] "r" (in322), + [in321] "r" (in321), [k1Res0] "r" (k1Res0) + : "hi", "lo", "$ac1hi", "$ac1lo" + ); + + // upper allpass filter + __asm__ volatile ( + "subu %[diff1], %[tmp21], %[state3] \n\t" + "subu %[diff2], %[tmp22], %[state7] \n\t" + + "mult $ac0, %[diff1], %[k2Res2] \n\t" + "mult $ac1, %[diff2], %[k1Res2] \n\t" + "extr.w %[state3], $ac0, 16 \n\t" + "extr.w %[state7], $ac1, 16 \n\t" + "addu %[state3], %[state2], %[state3] \n\t" + "addu %[state7], %[state6], %[state7] \n\t" + + "addiu %[state2], %[tmp21], 0 \n\t" + "addiu %[state6], %[tmp22], 0 \n\t" + + // add two allpass outputs, divide by two and round + "addu %[out32], %[state3], %[state7] \n\t" + "addiu %[out32], %[out32], 1024 \n\t" + "sra %[out32], %[out32], 11 \n\t" + : [state3] "+r" (state3), [state6] "+r" (state6), + [state2] "+r" (state2), [diff2] "=&r" (diff2), + [out32] "=r" (out32), [diff1] "=&r" (diff1), [state7] "+r" (state7) + : [tmp22] "r" (tmp22), [tmp21] "r" (tmp21), + [k1Res2] "r" (k1Res2), [k2Res2] "r" (k2Res2) + : "hi", "lo", "$ac1hi", "$ac1lo" + ); + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + } +#else // #if defined(MIPS_DSP_R2_LE) + int32_t tmp1, tmp2, diff; + int32_t in32; + len1 = (len >> 1)/4; + for (i = len1; i > 0; i--) { + // lower allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); + state2 = tmp2; + + // upper allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); + state6 = tmp2; + + // add two allpass outputs, divide by two and round + out32 = (state3 + state7 + 1024) >> 11; + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + // lower allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); + state2 = tmp2; + + // upper allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); + state6 = tmp2; + + // add two allpass outputs, divide by two and round + out32 = (state3 + state7 + 1024) >> 11; + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + // lower allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); + state2 = tmp2; + + // upper allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); + state6 = tmp2; + + // add two allpass outputs, divide by two and round + out32 = (state3 + state7 + 1024) >> 11; + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + // lower allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state1; + tmp1 = MUL_ACCUM_1(kResampleAllpass2[0], diff, state0); + state0 = in32; + diff = tmp1 - state2; + tmp2 = MUL_ACCUM_2(kResampleAllpass2[1], diff, state1); + state1 = tmp1; + diff = tmp2 - state3; + state3 = MUL_ACCUM_2(kResampleAllpass2[2], diff, state2); + state2 = tmp2; + + // upper allpass filter + in32 = (int32_t)(*in++) << 10; + diff = in32 - state5; + tmp1 = MUL_ACCUM_1(kResampleAllpass1[0], diff, state4); + state4 = in32; + diff = tmp1 - state6; + tmp2 = MUL_ACCUM_1(kResampleAllpass1[1], diff, state5); + state5 = tmp1; + diff = tmp2 - state7; + state7 = MUL_ACCUM_2(kResampleAllpass1[2], diff, state6); + state6 = tmp2; + + // add two allpass outputs, divide by two and round + out32 = (state3 + state7 + 1024) >> 11; + + // limit amplitude to prevent wrap-around, and write to output array + *out++ = WebRtcSpl_SatW32ToW16(out32); + } +#endif // #if defined(MIPS_DSP_R2_LE) + __asm__ volatile ( + "sw %[state0], 0(%[filtState]) \n\t" + "sw %[state1], 4(%[filtState]) \n\t" + "sw %[state2], 8(%[filtState]) \n\t" + "sw %[state3], 12(%[filtState]) \n\t" + "sw %[state4], 16(%[filtState]) \n\t" + "sw %[state5], 20(%[filtState]) \n\t" + "sw %[state6], 24(%[filtState]) \n\t" + "sw %[state7], 28(%[filtState]) \n\t" + : + : [state0] "r" (state0), [state1] "r" (state1), [state2] "r" (state2), + [state3] "r" (state3), [state4] "r" (state4), [state5] "r" (state5), + [state6] "r" (state6), [state7] "r" (state7), [filtState] "r" (filtState) + : "memory" + ); +} + +#endif // #if defined(MIPS32_LE) diff --git a/third_party/libwebrtc/common_audio/signal_processing/resample_fractional.c b/third_party/libwebrtc/common_audio/signal_processing/resample_fractional.c new file mode 100644 index 0000000000..9ffe0aca60 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/resample_fractional.c @@ -0,0 +1,239 @@ +/* + * 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. + */ + + +/* + * This file contains the resampling functions between 48, 44, 32 and 24 kHz. + * The description headers can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// interpolation coefficients +static const int16_t kCoefficients48To32[2][8] = { + {778, -2050, 1087, 23285, 12903, -3783, 441, 222}, + {222, 441, -3783, 12903, 23285, 1087, -2050, 778} +}; + +static const int16_t kCoefficients32To24[3][8] = { + {767, -2362, 2434, 24406, 10620, -3838, 721, 90}, + {386, -381, -2646, 19062, 19062, -2646, -381, 386}, + {90, 721, -3838, 10620, 24406, 2434, -2362, 767} +}; + +static const int16_t kCoefficients44To32[4][9] = { + {117, -669, 2245, -6183, 26267, 13529, -3245, 845, -138}, + {-101, 612, -2283, 8532, 29790, -5138, 1789, -524, 91}, + {50, -292, 1016, -3064, 32010, 3933, -1147, 315, -53}, + {-156, 974, -3863, 18603, 21691, -6246, 2353, -712, 126} +}; + +// Resampling ratio: 2/3 +// input: int32_t (normalized, not saturated) :: size 3 * K +// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 2 * K +// K: number of blocks + +void WebRtcSpl_Resample48khzTo32khz(const int32_t *In, int32_t *Out, size_t K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (3 input samples -> 2 output samples); + // process in sub blocks of size 3 samples. + int32_t tmp; + size_t m; + + for (m = 0; m < K; m++) + { + tmp = 1 << 14; + tmp += kCoefficients48To32[0][0] * In[0]; + tmp += kCoefficients48To32[0][1] * In[1]; + tmp += kCoefficients48To32[0][2] * In[2]; + tmp += kCoefficients48To32[0][3] * In[3]; + tmp += kCoefficients48To32[0][4] * In[4]; + tmp += kCoefficients48To32[0][5] * In[5]; + tmp += kCoefficients48To32[0][6] * In[6]; + tmp += kCoefficients48To32[0][7] * In[7]; + Out[0] = tmp; + + tmp = 1 << 14; + tmp += kCoefficients48To32[1][0] * In[1]; + tmp += kCoefficients48To32[1][1] * In[2]; + tmp += kCoefficients48To32[1][2] * In[3]; + tmp += kCoefficients48To32[1][3] * In[4]; + tmp += kCoefficients48To32[1][4] * In[5]; + tmp += kCoefficients48To32[1][5] * In[6]; + tmp += kCoefficients48To32[1][6] * In[7]; + tmp += kCoefficients48To32[1][7] * In[8]; + Out[1] = tmp; + + // update pointers + In += 3; + Out += 2; + } +} + +// Resampling ratio: 3/4 +// input: int32_t (normalized, not saturated) :: size 4 * K +// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 3 * K +// K: number of blocks + +void WebRtcSpl_Resample32khzTo24khz(const int32_t *In, int32_t *Out, size_t K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (4 input samples -> 3 output samples); + // process in sub blocks of size 4 samples. + size_t m; + int32_t tmp; + + for (m = 0; m < K; m++) + { + tmp = 1 << 14; + tmp += kCoefficients32To24[0][0] * In[0]; + tmp += kCoefficients32To24[0][1] * In[1]; + tmp += kCoefficients32To24[0][2] * In[2]; + tmp += kCoefficients32To24[0][3] * In[3]; + tmp += kCoefficients32To24[0][4] * In[4]; + tmp += kCoefficients32To24[0][5] * In[5]; + tmp += kCoefficients32To24[0][6] * In[6]; + tmp += kCoefficients32To24[0][7] * In[7]; + Out[0] = tmp; + + tmp = 1 << 14; + tmp += kCoefficients32To24[1][0] * In[1]; + tmp += kCoefficients32To24[1][1] * In[2]; + tmp += kCoefficients32To24[1][2] * In[3]; + tmp += kCoefficients32To24[1][3] * In[4]; + tmp += kCoefficients32To24[1][4] * In[5]; + tmp += kCoefficients32To24[1][5] * In[6]; + tmp += kCoefficients32To24[1][6] * In[7]; + tmp += kCoefficients32To24[1][7] * In[8]; + Out[1] = tmp; + + tmp = 1 << 14; + tmp += kCoefficients32To24[2][0] * In[2]; + tmp += kCoefficients32To24[2][1] * In[3]; + tmp += kCoefficients32To24[2][2] * In[4]; + tmp += kCoefficients32To24[2][3] * In[5]; + tmp += kCoefficients32To24[2][4] * In[6]; + tmp += kCoefficients32To24[2][5] * In[7]; + tmp += kCoefficients32To24[2][6] * In[8]; + tmp += kCoefficients32To24[2][7] * In[9]; + Out[2] = tmp; + + // update pointers + In += 4; + Out += 3; + } +} + +// +// fractional resampling filters +// Fout = 11/16 * Fin +// Fout = 8/11 * Fin +// + +// compute two inner-products and store them to output array +static void WebRtcSpl_ResampDotProduct(const int32_t *in1, const int32_t *in2, + const int16_t *coef_ptr, int32_t *out1, + int32_t *out2) +{ + int32_t tmp1 = 16384; + int32_t tmp2 = 16384; + int16_t coef; + + coef = coef_ptr[0]; + tmp1 += coef * in1[0]; + tmp2 += coef * in2[-0]; + + coef = coef_ptr[1]; + tmp1 += coef * in1[1]; + tmp2 += coef * in2[-1]; + + coef = coef_ptr[2]; + tmp1 += coef * in1[2]; + tmp2 += coef * in2[-2]; + + coef = coef_ptr[3]; + tmp1 += coef * in1[3]; + tmp2 += coef * in2[-3]; + + coef = coef_ptr[4]; + tmp1 += coef * in1[4]; + tmp2 += coef * in2[-4]; + + coef = coef_ptr[5]; + tmp1 += coef * in1[5]; + tmp2 += coef * in2[-5]; + + coef = coef_ptr[6]; + tmp1 += coef * in1[6]; + tmp2 += coef * in2[-6]; + + coef = coef_ptr[7]; + tmp1 += coef * in1[7]; + tmp2 += coef * in2[-7]; + + coef = coef_ptr[8]; + *out1 = tmp1 + coef * in1[8]; + *out2 = tmp2 + coef * in2[-8]; +} + +// Resampling ratio: 8/11 +// input: int32_t (normalized, not saturated) :: size 11 * K +// output: int32_t (shifted 15 positions to the left, + offset 16384) :: size 8 * K +// K: number of blocks + +void WebRtcSpl_Resample44khzTo32khz(const int32_t *In, int32_t *Out, size_t K) +{ + ///////////////////////////////////////////////////////////// + // Filter operation: + // + // Perform resampling (11 input samples -> 8 output samples); + // process in sub blocks of size 11 samples. + int32_t tmp; + size_t m; + + for (m = 0; m < K; m++) + { + tmp = 1 << 14; + + // first output sample + Out[0] = ((int32_t)In[3] << 15) + tmp; + + // sum and accumulate filter coefficients and input samples + tmp += kCoefficients44To32[3][0] * In[5]; + tmp += kCoefficients44To32[3][1] * In[6]; + tmp += kCoefficients44To32[3][2] * In[7]; + tmp += kCoefficients44To32[3][3] * In[8]; + tmp += kCoefficients44To32[3][4] * In[9]; + tmp += kCoefficients44To32[3][5] * In[10]; + tmp += kCoefficients44To32[3][6] * In[11]; + tmp += kCoefficients44To32[3][7] * In[12]; + tmp += kCoefficients44To32[3][8] * In[13]; + Out[4] = tmp; + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_ResampDotProduct(&In[0], &In[17], kCoefficients44To32[0], &Out[1], &Out[7]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_ResampDotProduct(&In[2], &In[15], kCoefficients44To32[1], &Out[2], &Out[6]); + + // sum and accumulate filter coefficients and input samples + WebRtcSpl_ResampDotProduct(&In[3], &In[14], kCoefficients44To32[2], &Out[3], &Out[5]); + + // update pointers + In += 11; + Out += 8; + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/signal_processing_unittest.cc b/third_party/libwebrtc/common_audio/signal_processing/signal_processing_unittest.cc new file mode 100644 index 0000000000..80d605bc0b --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/signal_processing_unittest.cc @@ -0,0 +1,668 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <algorithm> + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "rtc_base/strings/string_builder.h" +#include "test/gtest.h" + +static const size_t kVector16Size = 9; +static const int16_t vector16[kVector16Size] = {1, + -15511, + 4323, + 1963, + WEBRTC_SPL_WORD16_MAX, + 0, + WEBRTC_SPL_WORD16_MIN + 5, + -3333, + 345}; + +TEST(SplTest, MacroTest) { + // Macros with inputs. + int A = 10; + int B = 21; + int a = -3; + int b = WEBRTC_SPL_WORD32_MAX; + + EXPECT_EQ(10, WEBRTC_SPL_MIN(A, B)); + EXPECT_EQ(21, WEBRTC_SPL_MAX(A, B)); + + EXPECT_EQ(3, WEBRTC_SPL_ABS_W16(a)); + EXPECT_EQ(3, WEBRTC_SPL_ABS_W32(a)); + + EXPECT_EQ(-63, WEBRTC_SPL_MUL(a, B)); + EXPECT_EQ(2147483651u, WEBRTC_SPL_UMUL(a, b)); + b = WEBRTC_SPL_WORD16_MAX >> 1; + EXPECT_EQ(4294918147u, WEBRTC_SPL_UMUL_32_16(a, b)); + EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_U16(a, b)); + + a = b; + b = -3; + + EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT16(a, b)); + EXPECT_EQ(-1, WEBRTC_SPL_MUL_16_32_RSFT15(a, b)); + EXPECT_EQ(-3, WEBRTC_SPL_MUL_16_32_RSFT14(a, b)); + EXPECT_EQ(-24, WEBRTC_SPL_MUL_16_32_RSFT11(a, b)); + + EXPECT_EQ(-12288, WEBRTC_SPL_MUL_16_16_RSFT(a, b, 2)); + EXPECT_EQ(-12287, WEBRTC_SPL_MUL_16_16_RSFT_WITH_ROUND(a, b, 2)); + + EXPECT_EQ(21, WEBRTC_SPL_SAT(a, A, B)); + EXPECT_EQ(21, WEBRTC_SPL_SAT(a, B, A)); + + // Shifting with negative numbers allowed + int shift_amount = 1; // Workaround compiler warning using variable here. + // Positive means left shift + EXPECT_EQ(32766, WEBRTC_SPL_SHIFT_W32(a, shift_amount)); + + // Shifting with negative numbers not allowed + // We cannot do casting here due to signed/unsigned problem + EXPECT_EQ(32766, WEBRTC_SPL_LSHIFT_W32(a, 1)); + + EXPECT_EQ(8191u, WEBRTC_SPL_RSHIFT_U32(a, 1)); + + EXPECT_EQ(1470, WEBRTC_SPL_RAND(A)); + + EXPECT_EQ(-49149, WEBRTC_SPL_MUL_16_16(a, b)); + EXPECT_EQ(1073676289, + WEBRTC_SPL_MUL_16_16(WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MAX)); + EXPECT_EQ(1073709055, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MAX, + WEBRTC_SPL_WORD32_MAX)); + EXPECT_EQ(1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, + WEBRTC_SPL_WORD32_MIN)); +#ifdef WEBRTC_ARCH_ARM_V7 + EXPECT_EQ(-1073741824, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, + WEBRTC_SPL_WORD32_MAX)); +#else + EXPECT_EQ(-1073741823, WEBRTC_SPL_MUL_16_32_RSFT16(WEBRTC_SPL_WORD16_MIN, + WEBRTC_SPL_WORD32_MAX)); +#endif +} + +TEST(SplTest, InlineTest) { + int16_t a16 = 121; + int16_t b16 = -17; + int32_t a32 = 111121; + int32_t b32 = -1711; + + EXPECT_EQ(17, WebRtcSpl_GetSizeInBits(a32)); + + EXPECT_EQ(0, WebRtcSpl_NormW32(0)); + EXPECT_EQ(31, WebRtcSpl_NormW32(-1)); + EXPECT_EQ(0, WebRtcSpl_NormW32(WEBRTC_SPL_WORD32_MIN)); + EXPECT_EQ(14, WebRtcSpl_NormW32(a32)); + + EXPECT_EQ(0, WebRtcSpl_NormW16(0)); + EXPECT_EQ(15, WebRtcSpl_NormW16(-1)); + EXPECT_EQ(0, WebRtcSpl_NormW16(WEBRTC_SPL_WORD16_MIN)); + EXPECT_EQ(4, WebRtcSpl_NormW16(b32)); + for (int ii = 0; ii < 15; ++ii) { + int16_t value = 1 << ii; + EXPECT_EQ(14 - ii, WebRtcSpl_NormW16(value)); + EXPECT_EQ(15 - ii, WebRtcSpl_NormW16(-value)); + } + + EXPECT_EQ(0, WebRtcSpl_NormU32(0u)); + EXPECT_EQ(0, WebRtcSpl_NormU32(0xffffffff)); + EXPECT_EQ(15, WebRtcSpl_NormU32(static_cast<uint32_t>(a32))); + + EXPECT_EQ(104, WebRtcSpl_AddSatW16(a16, b16)); + EXPECT_EQ(138, WebRtcSpl_SubSatW16(a16, b16)); +} + +TEST(SplTest, AddSubSatW32) { + static constexpr int32_t kAddSubArgs[] = { + INT32_MIN, INT32_MIN + 1, -3, -2, -1, 0, 1, -1, 2, + 3, INT32_MAX - 1, INT32_MAX}; + for (int32_t a : kAddSubArgs) { + for (int32_t b : kAddSubArgs) { + const int64_t sum = std::max<int64_t>( + INT32_MIN, std::min<int64_t>(INT32_MAX, static_cast<int64_t>(a) + b)); + const int64_t diff = std::max<int64_t>( + INT32_MIN, std::min<int64_t>(INT32_MAX, static_cast<int64_t>(a) - b)); + rtc::StringBuilder ss; + ss << a << " +/- " << b << ": sum " << sum << ", diff " << diff; + SCOPED_TRACE(ss.str()); + EXPECT_EQ(sum, WebRtcSpl_AddSatW32(a, b)); + EXPECT_EQ(diff, WebRtcSpl_SubSatW32(a, b)); + } + } +} + +TEST(SplTest, CountLeadingZeros32) { + EXPECT_EQ(32, WebRtcSpl_CountLeadingZeros32(0)); + EXPECT_EQ(32, WebRtcSpl_CountLeadingZeros32_NotBuiltin(0)); + for (int i = 0; i < 32; ++i) { + const uint32_t single_one = uint32_t{1} << i; + const uint32_t all_ones = 2 * single_one - 1; + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32(single_one)); + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32_NotBuiltin(single_one)); + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32(all_ones)); + EXPECT_EQ(31 - i, WebRtcSpl_CountLeadingZeros32_NotBuiltin(all_ones)); + } +} + +TEST(SplTest, CountLeadingZeros64) { + EXPECT_EQ(64, WebRtcSpl_CountLeadingZeros64(0)); + EXPECT_EQ(64, WebRtcSpl_CountLeadingZeros64_NotBuiltin(0)); + for (int i = 0; i < 64; ++i) { + const uint64_t single_one = uint64_t{1} << i; + const uint64_t all_ones = 2 * single_one - 1; + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64(single_one)); + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64_NotBuiltin(single_one)); + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64(all_ones)); + EXPECT_EQ(63 - i, WebRtcSpl_CountLeadingZeros64_NotBuiltin(all_ones)); + } +} + +TEST(SplTest, MathOperationsTest) { + int A = 1134567892; + int32_t num = 117; + int32_t den = -5; + uint16_t denU = 5; + EXPECT_EQ(33700, WebRtcSpl_Sqrt(A)); + EXPECT_EQ(33683, WebRtcSpl_SqrtFloor(A)); + + EXPECT_EQ(-91772805, WebRtcSpl_DivResultInQ31(den, num)); + EXPECT_EQ(-23, WebRtcSpl_DivW32W16ResW16(num, (int16_t)den)); + EXPECT_EQ(-23, WebRtcSpl_DivW32W16(num, (int16_t)den)); + EXPECT_EQ(23u, WebRtcSpl_DivU32U16(num, denU)); + EXPECT_EQ(0, WebRtcSpl_DivW32HiLow(128, 0, 256)); +} + +TEST(SplTest, BasicArrayOperationsTest) { + const size_t kVectorSize = 4; + int B[] = {4, 12, 133, 1100}; + int16_t b16[kVectorSize]; + int32_t b32[kVectorSize]; + + int16_t bTmp16[kVectorSize]; + int32_t bTmp32[kVectorSize]; + + WebRtcSpl_MemSetW16(b16, 3, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(3, b16[kk]); + } + WebRtcSpl_ZerosArrayW16(b16, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(0, b16[kk]); + } + WebRtcSpl_MemSetW32(b32, 3, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(3, b32[kk]); + } + WebRtcSpl_ZerosArrayW32(b32, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(0, b32[kk]); + } + for (size_t kk = 0; kk < kVectorSize; ++kk) { + bTmp16[kk] = (int16_t)kk; + bTmp32[kk] = (int32_t)kk; + } + WEBRTC_SPL_MEMCPY_W16(b16, bTmp16, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(b16[kk], bTmp16[kk]); + } + // WEBRTC_SPL_MEMCPY_W32(b32, bTmp32, kVectorSize); + // for (int kk = 0; kk < kVectorSize; ++kk) { + // EXPECT_EQ(b32[kk], bTmp32[kk]); + // } + WebRtcSpl_CopyFromEndW16(b16, kVectorSize, 2, bTmp16); + for (size_t kk = 0; kk < 2; ++kk) { + EXPECT_EQ(static_cast<int16_t>(kk + 2), bTmp16[kk]); + } + + for (size_t kk = 0; kk < kVectorSize; ++kk) { + b32[kk] = B[kk]; + b16[kk] = (int16_t)B[kk]; + } + WebRtcSpl_VectorBitShiftW32ToW16(bTmp16, kVectorSize, b32, 1); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((B[kk] >> 1), bTmp16[kk]); + } + WebRtcSpl_VectorBitShiftW16(bTmp16, kVectorSize, b16, 1); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((B[kk] >> 1), bTmp16[kk]); + } + WebRtcSpl_VectorBitShiftW32(bTmp32, kVectorSize, b32, 1); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((B[kk] >> 1), bTmp32[kk]); + } + + WebRtcSpl_MemCpyReversedOrder(&bTmp16[3], b16, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(b16[3 - kk], bTmp16[kk]); + } +} + +TEST(SplTest, MinMaxOperationsTest) { + const size_t kVectorSize = 17; + + // Vectors to test the cases where minimum values have to be caught + // outside of the unrolled loops in ARM-Neon. + int16_t vector16[kVectorSize] = {-1, + 7485, + 0, + 3333, + -18283, + 0, + 12334, + -29871, + 988, + -3333, + 345, + -456, + 222, + 999, + 888, + 8774, + WEBRTC_SPL_WORD16_MIN}; + int32_t vector32[kVectorSize] = {-1, + 0, + 283211, + 3333, + 8712345, + 0, + -3333, + 89345, + -374585456, + 222, + 999, + 122345334, + -12389756, + -987329871, + 888, + -2, + WEBRTC_SPL_WORD32_MIN}; + + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, + WebRtcSpl_MinValueW16(vector16, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD32_MIN, + WebRtcSpl_MinValueW32(vector32, kVectorSize)); + EXPECT_EQ(kVectorSize - 1, WebRtcSpl_MinIndexW16(vector16, kVectorSize)); + EXPECT_EQ(kVectorSize - 1, WebRtcSpl_MinIndexW32(vector32, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, + WebRtcSpl_MaxAbsElementW16(vector16, kVectorSize)); + int16_t min_value, max_value; + WebRtcSpl_MinMaxW16(vector16, kVectorSize, &min_value, &max_value); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, min_value); + EXPECT_EQ(12334, max_value); + + // Test the cases where maximum values have to be caught + // outside of the unrolled loops in ARM-Neon. + vector16[kVectorSize - 1] = WEBRTC_SPL_WORD16_MAX; + vector32[kVectorSize - 1] = WEBRTC_SPL_WORD32_MAX; + + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, + WebRtcSpl_MaxAbsValueW16(vector16, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, + WebRtcSpl_MaxValueW16(vector16, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD32_MAX, + WebRtcSpl_MaxAbsValueW32(vector32, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD32_MAX, + WebRtcSpl_MaxValueW32(vector32, kVectorSize)); + EXPECT_EQ(kVectorSize - 1, WebRtcSpl_MaxAbsIndexW16(vector16, kVectorSize)); + EXPECT_EQ(kVectorSize - 1, WebRtcSpl_MaxIndexW16(vector16, kVectorSize)); + EXPECT_EQ(kVectorSize - 1, WebRtcSpl_MaxIndexW32(vector32, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, + WebRtcSpl_MaxAbsElementW16(vector16, kVectorSize)); + WebRtcSpl_MinMaxW16(vector16, kVectorSize, &min_value, &max_value); + EXPECT_EQ(-29871, min_value); + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, max_value); + + // Test the cases where multiple maximum and minimum values are present. + vector16[1] = WEBRTC_SPL_WORD16_MAX; + vector16[6] = WEBRTC_SPL_WORD16_MIN; + vector16[11] = WEBRTC_SPL_WORD16_MIN; + vector32[1] = WEBRTC_SPL_WORD32_MAX; + vector32[6] = WEBRTC_SPL_WORD32_MIN; + vector32[11] = WEBRTC_SPL_WORD32_MIN; + + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, + WebRtcSpl_MaxAbsValueW16(vector16, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, + WebRtcSpl_MaxValueW16(vector16, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, + WebRtcSpl_MinValueW16(vector16, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD32_MAX, + WebRtcSpl_MaxAbsValueW32(vector32, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD32_MAX, + WebRtcSpl_MaxValueW32(vector32, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD32_MIN, + WebRtcSpl_MinValueW32(vector32, kVectorSize)); + EXPECT_EQ(6u, WebRtcSpl_MaxAbsIndexW16(vector16, kVectorSize)); + EXPECT_EQ(1u, WebRtcSpl_MaxIndexW16(vector16, kVectorSize)); + EXPECT_EQ(1u, WebRtcSpl_MaxIndexW32(vector32, kVectorSize)); + EXPECT_EQ(6u, WebRtcSpl_MinIndexW16(vector16, kVectorSize)); + EXPECT_EQ(6u, WebRtcSpl_MinIndexW32(vector32, kVectorSize)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, + WebRtcSpl_MaxAbsElementW16(vector16, kVectorSize)); + WebRtcSpl_MinMaxW16(vector16, kVectorSize, &min_value, &max_value); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, min_value); + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, max_value); + + // Test a one-element vector. + int16_t single_element_vector = 0; + EXPECT_EQ(0, WebRtcSpl_MaxAbsValueW16(&single_element_vector, 1)); + EXPECT_EQ(0, WebRtcSpl_MaxValueW16(&single_element_vector, 1)); + EXPECT_EQ(0, WebRtcSpl_MinValueW16(&single_element_vector, 1)); + EXPECT_EQ(0u, WebRtcSpl_MaxAbsIndexW16(&single_element_vector, 1)); + EXPECT_EQ(0u, WebRtcSpl_MaxIndexW16(&single_element_vector, 1)); + EXPECT_EQ(0u, WebRtcSpl_MinIndexW16(&single_element_vector, 1)); + EXPECT_EQ(0, WebRtcSpl_MaxAbsElementW16(&single_element_vector, 1)); + WebRtcSpl_MinMaxW16(&single_element_vector, 1, &min_value, &max_value); + EXPECT_EQ(0, min_value); + EXPECT_EQ(0, max_value); + + // Test a two-element vector with the values WEBRTC_SPL_WORD16_MIN and + // WEBRTC_SPL_WORD16_MAX. + int16_t two_element_vector[2] = {WEBRTC_SPL_WORD16_MIN, + WEBRTC_SPL_WORD16_MAX}; + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, + WebRtcSpl_MaxAbsValueW16(two_element_vector, 2)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, + WebRtcSpl_MaxValueW16(two_element_vector, 2)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, + WebRtcSpl_MinValueW16(two_element_vector, 2)); + EXPECT_EQ(0u, WebRtcSpl_MaxAbsIndexW16(two_element_vector, 2)); + EXPECT_EQ(1u, WebRtcSpl_MaxIndexW16(two_element_vector, 2)); + EXPECT_EQ(0u, WebRtcSpl_MinIndexW16(two_element_vector, 2)); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, + WebRtcSpl_MaxAbsElementW16(two_element_vector, 2)); + WebRtcSpl_MinMaxW16(two_element_vector, 2, &min_value, &max_value); + EXPECT_EQ(WEBRTC_SPL_WORD16_MIN, min_value); + EXPECT_EQ(WEBRTC_SPL_WORD16_MAX, max_value); +} + +TEST(SplTest, VectorOperationsTest) { + const size_t kVectorSize = 4; + int B[] = {4, 12, 133, 1100}; + int16_t a16[kVectorSize]; + int16_t b16[kVectorSize]; + int16_t bTmp16[kVectorSize]; + + for (size_t kk = 0; kk < kVectorSize; ++kk) { + a16[kk] = B[kk]; + b16[kk] = B[kk]; + } + + WebRtcSpl_AffineTransformVector(bTmp16, b16, 3, 7, 2, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((B[kk] * 3 + 7) >> 2, bTmp16[kk]); + } + WebRtcSpl_ScaleAndAddVectorsWithRound(b16, 3, b16, 2, 2, bTmp16, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((B[kk] * 3 + B[kk] * 2 + 2) >> 2, bTmp16[kk]); + } + + WebRtcSpl_AddAffineVectorToVector(bTmp16, b16, 3, 7, 2, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(((B[kk] * 3 + B[kk] * 2 + 2) >> 2) + ((b16[kk] * 3 + 7) >> 2), + bTmp16[kk]); + } + + WebRtcSpl_ScaleVector(b16, bTmp16, 13, kVectorSize, 2); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((b16[kk] * 13) >> 2, bTmp16[kk]); + } + WebRtcSpl_ScaleVectorWithSat(b16, bTmp16, 13, kVectorSize, 2); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((b16[kk] * 13) >> 2, bTmp16[kk]); + } + WebRtcSpl_ScaleAndAddVectors(a16, 13, 2, b16, 7, 2, bTmp16, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(((a16[kk] * 13) >> 2) + ((b16[kk] * 7) >> 2), bTmp16[kk]); + } + + WebRtcSpl_AddVectorsAndShift(bTmp16, a16, b16, kVectorSize, 2); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(B[kk] >> 1, bTmp16[kk]); + } + WebRtcSpl_ReverseOrderMultArrayElements(bTmp16, a16, &b16[3], kVectorSize, 2); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((a16[kk] * b16[3 - kk]) >> 2, bTmp16[kk]); + } + WebRtcSpl_ElementwiseVectorMult(bTmp16, a16, b16, kVectorSize, 6); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ((a16[kk] * b16[kk]) >> 6, bTmp16[kk]); + } + + WebRtcSpl_SqrtOfOneMinusXSquared(b16, kVectorSize, bTmp16); + for (size_t kk = 0; kk < kVectorSize - 1; ++kk) { + EXPECT_EQ(32767, bTmp16[kk]); + } + EXPECT_EQ(32749, bTmp16[kVectorSize - 1]); + + EXPECT_EQ(0, WebRtcSpl_GetScalingSquare(b16, kVectorSize, 1)); +} + +TEST(SplTest, EstimatorsTest) { + const size_t kOrder = 2; + const int32_t unstable_filter[] = {4, 12, 133, 1100}; + const int32_t stable_filter[] = {1100, 133, 12, 4}; + int16_t lpc[kOrder + 2] = {0}; + int16_t refl[kOrder + 2] = {0}; + int16_t lpc_result[] = {4096, -497, 15, 0}; + int16_t refl_result[] = {-3962, 123, 0, 0}; + + EXPECT_EQ(0, WebRtcSpl_LevinsonDurbin(unstable_filter, lpc, refl, kOrder)); + EXPECT_EQ(1, WebRtcSpl_LevinsonDurbin(stable_filter, lpc, refl, kOrder)); + for (size_t i = 0; i < kOrder + 2; ++i) { + EXPECT_EQ(lpc_result[i], lpc[i]); + EXPECT_EQ(refl_result[i], refl[i]); + } +} + +TEST(SplTest, FilterTest) { + const size_t kVectorSize = 4; + const size_t kFilterOrder = 3; + int16_t A[] = {1, 2, 33, 100}; + int16_t A5[] = {1, 2, 33, 100, -5}; + int16_t B[] = {4, 12, 133, 110}; + int16_t data_in[kVectorSize]; + int16_t data_out[kVectorSize]; + int16_t bTmp16Low[kVectorSize]; + int16_t bState[kVectorSize]; + int16_t bStateLow[kVectorSize]; + + WebRtcSpl_ZerosArrayW16(bState, kVectorSize); + WebRtcSpl_ZerosArrayW16(bStateLow, kVectorSize); + + for (size_t kk = 0; kk < kVectorSize; ++kk) { + data_in[kk] = A[kk]; + data_out[kk] = 0; + } + + // MA filters. + // Note that the input data has `kFilterOrder` states before the actual + // data (one sample). + WebRtcSpl_FilterMAFastQ12(&data_in[kFilterOrder], data_out, B, + kFilterOrder + 1, 1); + EXPECT_EQ(0, data_out[0]); + // AR filters. + // Note that the output data has `kFilterOrder` states before the actual + // data (one sample). + WebRtcSpl_FilterARFastQ12(data_in, &data_out[kFilterOrder], A, + kFilterOrder + 1, 1); + EXPECT_EQ(0, data_out[kFilterOrder]); + + EXPECT_EQ(kVectorSize, WebRtcSpl_FilterAR(A5, 5, data_in, kVectorSize, bState, + kVectorSize, bStateLow, kVectorSize, + data_out, bTmp16Low, kVectorSize)); +} + +TEST(SplTest, RandTest) { + const int kVectorSize = 4; + int16_t BU[] = {3653, 12446, 8525, 30691}; + int16_t b16[kVectorSize]; + uint32_t bSeed = 100000; + + EXPECT_EQ(7086, WebRtcSpl_RandU(&bSeed)); + EXPECT_EQ(31565, WebRtcSpl_RandU(&bSeed)); + EXPECT_EQ(-9786, WebRtcSpl_RandN(&bSeed)); + EXPECT_EQ(kVectorSize, WebRtcSpl_RandUArray(b16, kVectorSize, &bSeed)); + for (int kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(BU[kk], b16[kk]); + } +} + +TEST(SplTest, DotProductWithScaleTest) { + EXPECT_EQ(605362796, WebRtcSpl_DotProductWithScale(vector16, vector16, + kVector16Size, 2)); +} + +TEST(SplTest, CrossCorrelationTest) { + // Note the function arguments relation specificed by API. + const size_t kCrossCorrelationDimension = 3; + const int kShift = 2; + const int kStep = 1; + const size_t kSeqDimension = 6; + + const int16_t kVector16[kVector16Size] = { + 1, 4323, 1963, WEBRTC_SPL_WORD16_MAX, WEBRTC_SPL_WORD16_MIN + 5, -3333, + -876, 8483, 142}; + int32_t vector32[kCrossCorrelationDimension] = {0}; + + WebRtcSpl_CrossCorrelation(vector32, vector16, kVector16, kSeqDimension, + kCrossCorrelationDimension, kShift, kStep); + + // WebRtcSpl_CrossCorrelationC() and WebRtcSpl_CrossCorrelationNeon() + // are not bit-exact. + const int32_t kExpected[kCrossCorrelationDimension] = {-266947903, -15579555, + -171282001}; + const int32_t* expected = kExpected; +#if !defined(MIPS32_LE) + const int32_t kExpectedNeon[kCrossCorrelationDimension] = { + -266947901, -15579553, -171281999}; + if (WebRtcSpl_CrossCorrelation != WebRtcSpl_CrossCorrelationC) { + expected = kExpectedNeon; + } +#endif + for (size_t i = 0; i < kCrossCorrelationDimension; ++i) { + EXPECT_EQ(expected[i], vector32[i]); + } +} + +TEST(SplTest, AutoCorrelationTest) { + int scale = 0; + int32_t vector32[kVector16Size]; + const int32_t expected[kVector16Size] = {302681398, 14223410, -121705063, + -85221647, -17104971, 61806945, + 6644603, -669329, 43}; + + EXPECT_EQ(kVector16Size, + WebRtcSpl_AutoCorrelation(vector16, kVector16Size, + kVector16Size - 1, vector32, &scale)); + EXPECT_EQ(3, scale); + for (size_t i = 0; i < kVector16Size; ++i) { + EXPECT_EQ(expected[i], vector32[i]); + } +} + +TEST(SplTest, SignalProcessingTest) { + const size_t kVectorSize = 4; + int A[] = {1, 2, 33, 100}; + const int16_t kHanning[4] = {2399, 8192, 13985, 16384}; + int16_t b16[kVectorSize]; + + int16_t bTmp16[kVectorSize]; + + int bScale = 0; + + for (size_t kk = 0; kk < kVectorSize; ++kk) { + b16[kk] = A[kk]; + } + + // TODO(bjornv): Activate the Reflection Coefficient tests when refactoring. + // WebRtcSpl_ReflCoefToLpc(b16, kVectorSize, bTmp16); + //// for (int kk = 0; kk < kVectorSize; ++kk) { + //// EXPECT_EQ(aTmp16[kk], bTmp16[kk]); + //// } + // WebRtcSpl_LpcToReflCoef(bTmp16, kVectorSize, b16); + //// for (int kk = 0; kk < kVectorSize; ++kk) { + //// EXPECT_EQ(a16[kk], b16[kk]); + //// } + // WebRtcSpl_AutoCorrToReflCoef(b32, kVectorSize, bTmp16); + //// for (int kk = 0; kk < kVectorSize; ++kk) { + //// EXPECT_EQ(aTmp16[kk], bTmp16[kk]); + //// } + + WebRtcSpl_GetHanningWindow(bTmp16, kVectorSize); + for (size_t kk = 0; kk < kVectorSize; ++kk) { + EXPECT_EQ(kHanning[kk], bTmp16[kk]); + } + + for (size_t kk = 0; kk < kVectorSize; ++kk) { + b16[kk] = A[kk]; + } + EXPECT_EQ(11094, WebRtcSpl_Energy(b16, kVectorSize, &bScale)); + EXPECT_EQ(0, bScale); +} + +TEST(SplTest, FFTTest) { + int16_t B[] = {1, 2, 33, 100, 2, 3, 34, 101, 3, 4, 35, 102, 4, 5, 36, 103}; + + EXPECT_EQ(0, WebRtcSpl_ComplexFFT(B, 3, 1)); + // for (int kk = 0; kk < 16; ++kk) { + // EXPECT_EQ(A[kk], B[kk]); + // } + EXPECT_EQ(0, WebRtcSpl_ComplexIFFT(B, 3, 1)); + // for (int kk = 0; kk < 16; ++kk) { + // EXPECT_EQ(A[kk], B[kk]); + // } + WebRtcSpl_ComplexBitReverse(B, 3); + for (int kk = 0; kk < 16; ++kk) { + // EXPECT_EQ(A[kk], B[kk]); + } +} + +TEST(SplTest, Resample48WithSaturationTest) { + // The test resamples 3*kBlockSize number of samples to 2*kBlockSize number + // of samples. + const size_t kBlockSize = 16; + + // Saturated input vector of 48 samples. + const int32_t kVectorSaturated[3 * kBlockSize + 7] = { + -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, + -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, + -32768, -32768, -32768, -32768, -32768, -32768, -32768, -32768, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767, 32767, + 32767, 32767, 32767, 32767, 32767, 32767, 32767}; + + // All values in `out_vector` should be `kRefValue32kHz`. + const int32_t kRefValue32kHz1 = -1077493760; + const int32_t kRefValue32kHz2 = 1077493645; + + // After bit shift with saturation, `out_vector_w16` is saturated. + + const int16_t kRefValue16kHz1 = -32768; + const int16_t kRefValue16kHz2 = 32767; + // Vector for storing output. + int32_t out_vector[2 * kBlockSize]; + int16_t out_vector_w16[2 * kBlockSize]; + + WebRtcSpl_Resample48khzTo32khz(kVectorSaturated, out_vector, kBlockSize); + WebRtcSpl_VectorBitShiftW32ToW16(out_vector_w16, 2 * kBlockSize, out_vector, + 15); + + // Comparing output values against references. The values at position + // 12-15 are skipped to account for the filter lag. + for (size_t i = 0; i < 12; ++i) { + EXPECT_EQ(kRefValue32kHz1, out_vector[i]); + EXPECT_EQ(kRefValue16kHz1, out_vector_w16[i]); + } + for (size_t i = 16; i < 2 * kBlockSize; ++i) { + EXPECT_EQ(kRefValue32kHz2, out_vector[i]); + EXPECT_EQ(kRefValue16kHz2, out_vector_w16[i]); + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/spl_init.c b/third_party/libwebrtc/common_audio/signal_processing/spl_init.c new file mode 100644 index 0000000000..cf37d47bec --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/spl_init.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +// Some code came from common/rtcd.c in the WebM project. + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// TODO(bugs.webrtc.org/9553): These function pointers are useless. Refactor +// things so that we simply have a bunch of regular functions with different +// implementations for different platforms. + +#if defined(WEBRTC_HAS_NEON) + +const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon; +const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon; +const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon; +const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon; +const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon; +const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon; +const CrossCorrelation WebRtcSpl_CrossCorrelation = + WebRtcSpl_CrossCorrelationNeon; +const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon; +const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound = + WebRtcSpl_ScaleAndAddVectorsWithRoundC; + +#elif defined(MIPS32_LE) + +const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips; +const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = +#ifdef MIPS_DSP_R1_LE + WebRtcSpl_MaxAbsValueW32_mips; +#else + WebRtcSpl_MaxAbsValueW32C; +#endif +const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips; +const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips; +const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips; +const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips; +const CrossCorrelation WebRtcSpl_CrossCorrelation = + WebRtcSpl_CrossCorrelation_mips; +const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips; +const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound = +#ifdef MIPS_DSP_R1_LE + WebRtcSpl_ScaleAndAddVectorsWithRound_mips; +#else + WebRtcSpl_ScaleAndAddVectorsWithRoundC; +#endif + +#else + +const MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C; +const MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C; +const MaxValueW16 WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C; +const MaxValueW32 WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C; +const MinValueW16 WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C; +const MinValueW32 WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C; +const CrossCorrelation WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC; +const DownsampleFast WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC; +const ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound = + WebRtcSpl_ScaleAndAddVectorsWithRoundC; + +#endif diff --git a/third_party/libwebrtc/common_audio/signal_processing/spl_inl.c b/third_party/libwebrtc/common_audio/signal_processing/spl_inl.c new file mode 100644 index 0000000000..d09e308ed3 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/spl_inl.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdint.h> + +#include "common_audio/signal_processing/include/spl_inl.h" + +// Table used by WebRtcSpl_CountLeadingZeros32_NotBuiltin. For each uint32_t n +// that's a sequence of 0 bits followed by a sequence of 1 bits, the entry at +// index (n * 0x8c0b2891) >> 26 in this table gives the number of zero bits in +// n. +const int8_t kWebRtcSpl_CountLeadingZeros32_Table[64] = { + 32, 8, 17, -1, -1, 14, -1, -1, -1, 20, -1, -1, -1, 28, -1, 18, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 26, 25, 24, + 4, 11, 23, 31, 3, 7, 10, 16, 22, 30, -1, -1, 2, 6, 13, 9, + -1, 15, -1, 21, -1, 29, 19, -1, -1, -1, -1, -1, 1, 27, 5, 12, +}; diff --git a/third_party/libwebrtc/common_audio/signal_processing/spl_sqrt.c b/third_party/libwebrtc/common_audio/signal_processing/spl_sqrt.c new file mode 100644 index 0000000000..cf9448ac97 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/spl_sqrt.c @@ -0,0 +1,194 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_Sqrt(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +int32_t WebRtcSpl_SqrtLocal(int32_t in); + +int32_t WebRtcSpl_SqrtLocal(int32_t in) +{ + + int16_t x_half, t16; + int32_t A, B, x2; + + /* The following block performs: + y=in/2 + x=y-2^30 + x_half=x/2^31 + t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4) + + 0.875*((x_half)^5) + */ + + B = in / 2; + + B = B - ((int32_t)0x40000000); // B = in/2 - 1/2 + x_half = (int16_t)(B >> 16); // x_half = x/2 = (in-1)/2 + B = B + ((int32_t)0x40000000); // B = 1 + x/2 + B = B + ((int32_t)0x40000000); // Add 0.5 twice (since 1.0 does not exist in Q31) + + x2 = ((int32_t)x_half) * ((int32_t)x_half) * 2; // A = (x/2)^2 + A = -x2; // A = -(x/2)^2 + B = B + (A >> 1); // B = 1 + x/2 - 0.5*(x/2)^2 + + A >>= 16; + A = A * A * 2; // A = (x/2)^4 + t16 = (int16_t)(A >> 16); + B += -20480 * t16 * 2; // B = B - 0.625*A + // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + + A = x_half * t16 * 2; // A = (x/2)^5 + t16 = (int16_t)(A >> 16); + B += 28672 * t16 * 2; // B = B + 0.875*A + // After this, B = 1 + x/2 - 0.5*(x/2)^2 - 0.625*(x/2)^4 + 0.875*(x/2)^5 + + t16 = (int16_t)(x2 >> 16); + A = x_half * t16 * 2; // A = x/2^3 + + B = B + (A >> 1); // B = B + 0.5*A + // After this, B = 1 + x/2 - 0.5*(x/2)^2 + 0.5*(x/2)^3 - 0.625*(x/2)^4 + 0.875*(x/2)^5 + + B = B + ((int32_t)32768); // Round off bit + + return B; +} + +int32_t WebRtcSpl_Sqrt(int32_t value) +{ + /* + Algorithm: + + Six term Taylor Series is used here to compute the square root of a number + y^0.5 = (1+x)^0.5 where x = y-1 + = 1+(x/2)-0.5*((x/2)^2+0.5*((x/2)^3-0.625*((x/2)^4+0.875*((x/2)^5) + 0.5 <= x < 1 + + Example of how the algorithm works, with ut=sqrt(in), and + with in=73632 and ut=271 (even shift value case): + + in=73632 + y= in/131072 + x=y-1 + t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5) + ut=t*(1/sqrt(2))*512 + + or: + + in=73632 + in2=73632*2^14 + y= in2/2^31 + x=y-1 + t = 1 + (x/2) - 0.5*((x/2)^2) + 0.5*((x/2)^3) - 0.625*((x/2)^4) + 0.875*((x/2)^5) + ut=t*(1/sqrt(2)) + ut2=ut*2^9 + + which gives: + + in = 73632 + in2 = 1206386688 + y = 0.56176757812500 + x = -0.43823242187500 + t = 0.74973506527313 + ut = 0.53014274874797 + ut2 = 2.714330873589594e+002 + + or: + + in=73632 + in2=73632*2^14 + y=in2/2 + x=y-2^30 + x_half=x/2^31 + t = 1 + (x_half) - 0.5*((x_half)^2) + 0.5*((x_half)^3) - 0.625*((x_half)^4) + + 0.875*((x_half)^5) + ut=t*(1/sqrt(2)) + ut2=ut*2^9 + + which gives: + + in = 73632 + in2 = 1206386688 + y = 603193344 + x = -470548480 + x_half = -0.21911621093750 + t = 0.74973506527313 + ut = 0.53014274874797 + ut2 = 2.714330873589594e+002 + + */ + + int16_t x_norm, nshift, t16, sh; + int32_t A; + + int16_t k_sqrt_2 = 23170; // 1/sqrt2 (==5a82) + + A = value; + + // The convention in this function is to calculate sqrt(abs(A)). Negate the + // input if it is negative. + if (A < 0) { + if (A == WEBRTC_SPL_WORD32_MIN) { + // This number cannot be held in an int32_t after negating. + // Map it to the maximum positive value. + A = WEBRTC_SPL_WORD32_MAX; + } else { + A = -A; + } + } else if (A == 0) { + return 0; // sqrt(0) = 0 + } + + sh = WebRtcSpl_NormW32(A); // # shifts to normalize A + A = WEBRTC_SPL_LSHIFT_W32(A, sh); // Normalize A + if (A < (WEBRTC_SPL_WORD32_MAX - 32767)) + { + A = A + ((int32_t)32768); // Round off bit + } else + { + A = WEBRTC_SPL_WORD32_MAX; + } + + x_norm = (int16_t)(A >> 16); // x_norm = AH + + nshift = (sh / 2); + RTC_DCHECK_GE(nshift, 0); + + A = (int32_t)WEBRTC_SPL_LSHIFT_W32((int32_t)x_norm, 16); + A = WEBRTC_SPL_ABS_W32(A); // A = abs(x_norm<<16) + A = WebRtcSpl_SqrtLocal(A); // A = sqrt(A) + + if (2 * nshift == sh) { + // Even shift value case + + t16 = (int16_t)(A >> 16); // t16 = AH + + A = k_sqrt_2 * t16 * 2; // A = 1/sqrt(2)*t16 + A = A + ((int32_t)32768); // Round off + A = A & ((int32_t)0x7fff0000); // Round off + + A >>= 15; // A = A>>16 + + } else + { + A >>= 16; // A = A>>16 + } + + A = A & ((int32_t)0x0000ffff); + A >>= nshift; // De-normalize the result. + + return A; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/splitting_filter.c b/third_party/libwebrtc/common_audio/signal_processing/splitting_filter.c new file mode 100644 index 0000000000..27a0a2a8c9 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/splitting_filter.c @@ -0,0 +1,211 @@ +/* + * 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. + */ + +/* + * This file contains the splitting filter functions. + * + */ + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// Maximum number of samples in a low/high-band frame. +enum +{ + kMaxBandFrameLength = 320 // 10 ms at 64 kHz. +}; + +// QMF filter coefficients in Q16. +static const uint16_t WebRtcSpl_kAllPassFilter1[3] = {6418, 36982, 57261}; +static const uint16_t WebRtcSpl_kAllPassFilter2[3] = {21333, 49062, 63010}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +// WebRtcSpl_AllPassQMF(...) +// +// Allpass filter used by the analysis and synthesis parts of the QMF filter. +// +// Input: +// - in_data : Input data sequence (Q10) +// - data_length : Length of data sequence (>2) +// - filter_coefficients : Filter coefficients (length 3, Q16) +// +// Input & Output: +// - filter_state : Filter state (length 6, Q10). +// +// Output: +// - out_data : Output data sequence (Q10), length equal to +// `data_length` +// + +static void WebRtcSpl_AllPassQMF(int32_t* in_data, + size_t data_length, + int32_t* out_data, + const uint16_t* filter_coefficients, + int32_t* filter_state) +{ + // The procedure is to filter the input with three first order all pass + // filters (cascade operations). + // + // a_3 + q^-1 a_2 + q^-1 a_1 + q^-1 + // y[n] = ----------- ----------- ----------- x[n] + // 1 + a_3q^-1 1 + a_2q^-1 1 + a_1q^-1 + // + // The input vector `filter_coefficients` includes these three filter + // coefficients. The filter state contains the in_data state, in_data[-1], + // followed by the out_data state, out_data[-1]. This is repeated for each + // cascade. The first cascade filter will filter the `in_data` and store + // the output in `out_data`. The second will the take the `out_data` as + // input and make an intermediate storage in `in_data`, to save memory. The + // third, and final, cascade filter operation takes the `in_data` (which is + // the output from the previous cascade filter) and store the output in + // `out_data`. Note that the input vector values are changed during the + // process. + size_t k; + int32_t diff; + // First all-pass cascade; filter from in_data to out_data. + + // Let y_i[n] indicate the output of cascade filter i (with filter + // coefficient a_i) at vector position n. Then the final output will be + // y[n] = y_3[n] + + // First loop, use the states stored in memory. + // "diff" should be safe from wrap around since max values are 2^25 + // diff = (x[0] - y_1[-1]) + diff = WebRtcSpl_SubSatW32(in_data[0], filter_state[1]); + // y_1[0] = x[-1] + a_1 * (x[0] - y_1[-1]) + out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, filter_state[0]); + + // For the remaining loops, use previous values. + for (k = 1; k < data_length; k++) + { + // diff = (x[n] - y_1[n-1]) + diff = WebRtcSpl_SubSatW32(in_data[k], out_data[k - 1]); + // y_1[n] = x[n-1] + a_1 * (x[n] - y_1[n-1]) + out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[0], diff, in_data[k - 1]); + } + + // Update states. + filter_state[0] = in_data[data_length - 1]; // x[N-1], becomes x[-1] next time + filter_state[1] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time + + // Second all-pass cascade; filter from out_data to in_data. + // diff = (y_1[0] - y_2[-1]) + diff = WebRtcSpl_SubSatW32(out_data[0], filter_state[3]); + // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) + in_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, filter_state[2]); + for (k = 1; k < data_length; k++) + { + // diff = (y_1[n] - y_2[n-1]) + diff = WebRtcSpl_SubSatW32(out_data[k], in_data[k - 1]); + // y_2[0] = y_1[-1] + a_2 * (y_1[0] - y_2[-1]) + in_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[1], diff, out_data[k-1]); + } + + filter_state[2] = out_data[data_length - 1]; // y_1[N-1], becomes y_1[-1] next time + filter_state[3] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time + + // Third all-pass cascade; filter from in_data to out_data. + // diff = (y_2[0] - y[-1]) + diff = WebRtcSpl_SubSatW32(in_data[0], filter_state[5]); + // y[0] = y_2[-1] + a_3 * (y_2[0] - y[-1]) + out_data[0] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, filter_state[4]); + for (k = 1; k < data_length; k++) + { + // diff = (y_2[n] - y[n-1]) + diff = WebRtcSpl_SubSatW32(in_data[k], out_data[k - 1]); + // y[n] = y_2[n-1] + a_3 * (y_2[n] - y[n-1]) + out_data[k] = WEBRTC_SPL_SCALEDIFF32(filter_coefficients[2], diff, in_data[k-1]); + } + filter_state[4] = in_data[data_length - 1]; // y_2[N-1], becomes y_2[-1] next time + filter_state[5] = out_data[data_length - 1]; // y[N-1], becomes y[-1] next time +} + +void WebRtcSpl_AnalysisQMF(const int16_t* in_data, size_t in_data_length, + int16_t* low_band, int16_t* high_band, + int32_t* filter_state1, int32_t* filter_state2) +{ + size_t i; + int16_t k; + int32_t tmp; + int32_t half_in1[kMaxBandFrameLength]; + int32_t half_in2[kMaxBandFrameLength]; + int32_t filter1[kMaxBandFrameLength]; + int32_t filter2[kMaxBandFrameLength]; + const size_t band_length = in_data_length / 2; + RTC_DCHECK_EQ(0, in_data_length % 2); + RTC_DCHECK_LE(band_length, kMaxBandFrameLength); + + // Split even and odd samples. Also shift them to Q10. + for (i = 0, k = 0; i < band_length; i++, k += 2) + { + half_in2[i] = ((int32_t)in_data[k]) * (1 << 10); + half_in1[i] = ((int32_t)in_data[k + 1]) * (1 << 10); + } + + // All pass filter even and odd samples, independently. + WebRtcSpl_AllPassQMF(half_in1, band_length, filter1, + WebRtcSpl_kAllPassFilter1, filter_state1); + WebRtcSpl_AllPassQMF(half_in2, band_length, filter2, + WebRtcSpl_kAllPassFilter2, filter_state2); + + // Take the sum and difference of filtered version of odd and even + // branches to get upper & lower band. + for (i = 0; i < band_length; i++) + { + tmp = (filter1[i] + filter2[i] + 1024) >> 11; + low_band[i] = WebRtcSpl_SatW32ToW16(tmp); + + tmp = (filter1[i] - filter2[i] + 1024) >> 11; + high_band[i] = WebRtcSpl_SatW32ToW16(tmp); + } +} + +void WebRtcSpl_SynthesisQMF(const int16_t* low_band, const int16_t* high_band, + size_t band_length, int16_t* out_data, + int32_t* filter_state1, int32_t* filter_state2) +{ + int32_t tmp; + int32_t half_in1[kMaxBandFrameLength]; + int32_t half_in2[kMaxBandFrameLength]; + int32_t filter1[kMaxBandFrameLength]; + int32_t filter2[kMaxBandFrameLength]; + size_t i; + int16_t k; + RTC_DCHECK_LE(band_length, kMaxBandFrameLength); + + // Obtain the sum and difference channels out of upper and lower-band channels. + // Also shift to Q10 domain. + for (i = 0; i < band_length; i++) + { + tmp = (int32_t)low_band[i] + (int32_t)high_band[i]; + half_in1[i] = tmp * (1 << 10); + tmp = (int32_t)low_band[i] - (int32_t)high_band[i]; + half_in2[i] = tmp * (1 << 10); + } + + // all-pass filter the sum and difference channels + WebRtcSpl_AllPassQMF(half_in1, band_length, filter1, + WebRtcSpl_kAllPassFilter2, filter_state1); + WebRtcSpl_AllPassQMF(half_in2, band_length, filter2, + WebRtcSpl_kAllPassFilter1, filter_state2); + + // The filtered signals are even and odd samples of the output. Combine + // them. The signals are Q10 should shift them back to Q0 and take care of + // saturation. + for (i = 0, k = 0; i < band_length; i++) + { + tmp = (filter2[i] + 512) >> 10; + out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); + + tmp = (filter1[i] + 512) >> 10; + out_data[k++] = WebRtcSpl_SatW32ToW16(tmp); + } + +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c b/third_party/libwebrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c new file mode 100644 index 0000000000..a77fd4063f --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c @@ -0,0 +1,35 @@ +/* + * 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. + */ + + +/* + * This file contains the function WebRtcSpl_SqrtOfOneMinusXSquared(). + * The description header can be found in signal_processing_library.h + * + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +void WebRtcSpl_SqrtOfOneMinusXSquared(int16_t *xQ15, size_t vector_length, + int16_t *yQ15) +{ + int32_t sq; + size_t m; + int16_t tmp; + + for (m = 0; m < vector_length; m++) + { + tmp = xQ15[m]; + sq = tmp * tmp; // x^2 in Q30 + sq = 1073741823 - sq; // 1-x^2, where 1 ~= 0.99999999906 is 1073741823 in Q30 + sq = WebRtcSpl_Sqrt(sq); // sqrt(1-x^2) in Q15 + yQ15[m] = (int16_t)sq; + } +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/vector_scaling_operations.c b/third_party/libwebrtc/common_audio/signal_processing/vector_scaling_operations.c new file mode 100644 index 0000000000..7307dc78ff --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/vector_scaling_operations.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + + +/* + * This file contains implementations of the functions + * WebRtcSpl_VectorBitShiftW16() + * WebRtcSpl_VectorBitShiftW32() + * WebRtcSpl_VectorBitShiftW32ToW16() + * WebRtcSpl_ScaleVector() + * WebRtcSpl_ScaleVectorWithSat() + * WebRtcSpl_ScaleAndAddVectors() + * WebRtcSpl_ScaleAndAddVectorsWithRoundC() + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +void WebRtcSpl_VectorBitShiftW16(int16_t *res, size_t length, + const int16_t *in, int16_t right_shifts) +{ + size_t i; + + if (right_shifts > 0) + { + for (i = length; i > 0; i--) + { + (*res++) = ((*in++) >> right_shifts); + } + } else + { + for (i = length; i > 0; i--) + { + (*res++) = ((*in++) * (1 << (-right_shifts))); + } + } +} + +void WebRtcSpl_VectorBitShiftW32(int32_t *out_vector, + size_t vector_length, + const int32_t *in_vector, + int16_t right_shifts) +{ + size_t i; + + if (right_shifts > 0) + { + for (i = vector_length; i > 0; i--) + { + (*out_vector++) = ((*in_vector++) >> right_shifts); + } + } else + { + for (i = vector_length; i > 0; i--) + { + (*out_vector++) = ((*in_vector++) << (-right_shifts)); + } + } +} + +void WebRtcSpl_VectorBitShiftW32ToW16(int16_t* out, size_t length, + const int32_t* in, int right_shifts) { + size_t i; + int32_t tmp_w32; + + if (right_shifts >= 0) { + for (i = length; i > 0; i--) { + tmp_w32 = (*in++) >> right_shifts; + (*out++) = WebRtcSpl_SatW32ToW16(tmp_w32); + } + } else { + int left_shifts = -right_shifts; + for (i = length; i > 0; i--) { + tmp_w32 = (*in++) << left_shifts; + (*out++) = WebRtcSpl_SatW32ToW16(tmp_w32); + } + } +} + +void WebRtcSpl_ScaleVector(const int16_t *in_vector, int16_t *out_vector, + int16_t gain, size_t in_vector_length, + int16_t right_shifts) +{ + // Performs vector operation: out_vector = (gain*in_vector)>>right_shifts + size_t i; + const int16_t *inptr; + int16_t *outptr; + + inptr = in_vector; + outptr = out_vector; + + for (i = 0; i < in_vector_length; i++) + { + *outptr++ = (int16_t)((*inptr++ * gain) >> right_shifts); + } +} + +void WebRtcSpl_ScaleVectorWithSat(const int16_t *in_vector, int16_t *out_vector, + int16_t gain, size_t in_vector_length, + int16_t right_shifts) +{ + // Performs vector operation: out_vector = (gain*in_vector)>>right_shifts + size_t i; + const int16_t *inptr; + int16_t *outptr; + + inptr = in_vector; + outptr = out_vector; + + for (i = 0; i < in_vector_length; i++) { + *outptr++ = WebRtcSpl_SatW32ToW16((*inptr++ * gain) >> right_shifts); + } +} + +void WebRtcSpl_ScaleAndAddVectors(const int16_t *in1, int16_t gain1, int shift1, + const int16_t *in2, int16_t gain2, int shift2, + int16_t *out, size_t vector_length) +{ + // Performs vector operation: out = (gain1*in1)>>shift1 + (gain2*in2)>>shift2 + size_t i; + const int16_t *in1ptr; + const int16_t *in2ptr; + int16_t *outptr; + + in1ptr = in1; + in2ptr = in2; + outptr = out; + + for (i = 0; i < vector_length; i++) + { + *outptr++ = (int16_t)((gain1 * *in1ptr++) >> shift1) + + (int16_t)((gain2 * *in2ptr++) >> shift2); + } +} + +// C version of WebRtcSpl_ScaleAndAddVectorsWithRound() for generic platforms. +int WebRtcSpl_ScaleAndAddVectorsWithRoundC(const int16_t* in_vector1, + int16_t in_vector1_scale, + const int16_t* in_vector2, + int16_t in_vector2_scale, + int right_shifts, + int16_t* out_vector, + size_t length) { + size_t i = 0; + int round_value = (1 << right_shifts) >> 1; + + if (in_vector1 == NULL || in_vector2 == NULL || out_vector == NULL || + length == 0 || right_shifts < 0) { + return -1; + } + + for (i = 0; i < length; i++) { + out_vector[i] = (int16_t)(( + in_vector1[i] * in_vector1_scale + in_vector2[i] * in_vector2_scale + + round_value) >> right_shifts); + } + + return 0; +} diff --git a/third_party/libwebrtc/common_audio/signal_processing/vector_scaling_operations_mips.c b/third_party/libwebrtc/common_audio/signal_processing/vector_scaling_operations_mips.c new file mode 100644 index 0000000000..ba2d26d422 --- /dev/null +++ b/third_party/libwebrtc/common_audio/signal_processing/vector_scaling_operations_mips.c @@ -0,0 +1,57 @@ +/* + * 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 file contains implementations of the functions + * WebRtcSpl_ScaleAndAddVectorsWithRound_mips() + */ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +int WebRtcSpl_ScaleAndAddVectorsWithRound_mips(const int16_t* in_vector1, + int16_t in_vector1_scale, + const int16_t* in_vector2, + int16_t in_vector2_scale, + int right_shifts, + int16_t* out_vector, + size_t length) { + int16_t r0 = 0, r1 = 0; + int16_t *in1 = (int16_t*)in_vector1; + int16_t *in2 = (int16_t*)in_vector2; + int16_t *out = out_vector; + size_t i = 0; + int value32 = 0; + + if (in_vector1 == NULL || in_vector2 == NULL || out_vector == NULL || + length == 0 || right_shifts < 0) { + return -1; + } + for (i = 0; i < length; i++) { + __asm __volatile ( + "lh %[r0], 0(%[in1]) \n\t" + "lh %[r1], 0(%[in2]) \n\t" + "mult %[r0], %[in_vector1_scale] \n\t" + "madd %[r1], %[in_vector2_scale] \n\t" + "extrv_r.w %[value32], $ac0, %[right_shifts] \n\t" + "addiu %[in1], %[in1], 2 \n\t" + "addiu %[in2], %[in2], 2 \n\t" + "sh %[value32], 0(%[out]) \n\t" + "addiu %[out], %[out], 2 \n\t" + : [value32] "=&r" (value32), [out] "+r" (out), [in1] "+r" (in1), + [in2] "+r" (in2), [r0] "=&r" (r0), [r1] "=&r" (r1) + : [in_vector1_scale] "r" (in_vector1_scale), + [in_vector2_scale] "r" (in_vector2_scale), + [right_shifts] "r" (right_shifts) + : "hi", "lo", "memory" + ); + } + return 0; +} diff --git a/third_party/libwebrtc/common_audio/sinc_resampler_gn/moz.build b/third_party/libwebrtc/common_audio/sinc_resampler_gn/moz.build new file mode 100644 index 0000000000..57e889cebd --- /dev/null +++ b/third_party/libwebrtc/common_audio/sinc_resampler_gn/moz.build @@ -0,0 +1,216 @@ +# 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 + + 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": + + 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("sinc_resampler_gn") diff --git a/third_party/libwebrtc/common_audio/smoothing_filter.cc b/third_party/libwebrtc/common_audio/smoothing_filter.cc new file mode 100644 index 0000000000..eaaf3a0033 --- /dev/null +++ b/third_party/libwebrtc/common_audio/smoothing_filter.cc @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/smoothing_filter.h" + +#include <math.h> + +#include <cmath> + +#include "rtc_base/checks.h" +#include "rtc_base/time_utils.h" + +namespace webrtc { + +SmoothingFilterImpl::SmoothingFilterImpl(int init_time_ms) + : init_time_ms_(init_time_ms), + // Duing the initalization time, we use an increasing alpha. Specifically, + // alpha(n) = exp(-powf(init_factor_, n)), + // where `init_factor_` is chosen such that + // alpha(init_time_ms_) = exp(-1.0f / init_time_ms_), + init_factor_(init_time_ms_ == 0 + ? 0.0f + : powf(init_time_ms_, -1.0f / init_time_ms_)), + // `init_const_` is to a factor to help the calculation during + // initialization phase. + init_const_(init_time_ms_ == 0 + ? 0.0f + : init_time_ms_ - + powf(init_time_ms_, 1.0f - 1.0f / init_time_ms_)) { + UpdateAlpha(init_time_ms_); +} + +SmoothingFilterImpl::~SmoothingFilterImpl() = default; + +void SmoothingFilterImpl::AddSample(float sample) { + const int64_t now_ms = rtc::TimeMillis(); + + if (!init_end_time_ms_) { + // This is equivalent to assuming the filter has been receiving the same + // value as the first sample since time -infinity. + state_ = last_sample_ = sample; + init_end_time_ms_ = now_ms + init_time_ms_; + last_state_time_ms_ = now_ms; + return; + } + + ExtrapolateLastSample(now_ms); + last_sample_ = sample; +} + +absl::optional<float> SmoothingFilterImpl::GetAverage() { + if (!init_end_time_ms_) { + // `init_end_time_ms_` undefined since we have not received any sample. + return absl::nullopt; + } + ExtrapolateLastSample(rtc::TimeMillis()); + return state_; +} + +bool SmoothingFilterImpl::SetTimeConstantMs(int time_constant_ms) { + if (!init_end_time_ms_ || last_state_time_ms_ < *init_end_time_ms_) { + return false; + } + UpdateAlpha(time_constant_ms); + return true; +} + +void SmoothingFilterImpl::UpdateAlpha(int time_constant_ms) { + alpha_ = time_constant_ms == 0 ? 0.0f : std::exp(-1.0f / time_constant_ms); +} + +void SmoothingFilterImpl::ExtrapolateLastSample(int64_t time_ms) { + RTC_DCHECK_GE(time_ms, last_state_time_ms_); + RTC_DCHECK(init_end_time_ms_); + + float multiplier = 0.0f; + + if (time_ms <= *init_end_time_ms_) { + // Current update is to be made during initialization phase. + // We update the state as if the `alpha` has been increased according + // alpha(n) = exp(-powf(init_factor_, n)), + // where n is the time (in millisecond) since the first sample received. + // With algebraic derivation as shown in the Appendix, we can find that the + // state can be updated in a similar manner as if alpha is a constant, + // except for a different multiplier. + if (init_time_ms_ == 0) { + // This means `init_factor_` = 0. + multiplier = 0.0f; + } else if (init_time_ms_ == 1) { + // This means `init_factor_` = 1. + multiplier = std::exp(last_state_time_ms_ - time_ms); + } else { + multiplier = std::exp( + -(powf(init_factor_, last_state_time_ms_ - *init_end_time_ms_) - + powf(init_factor_, time_ms - *init_end_time_ms_)) / + init_const_); + } + } else { + if (last_state_time_ms_ < *init_end_time_ms_) { + // The latest state update was made during initialization phase. + // We first extrapolate to the initialization time. + ExtrapolateLastSample(*init_end_time_ms_); + // Then extrapolate the rest by the following. + } + multiplier = powf(alpha_, time_ms - last_state_time_ms_); + } + + state_ = multiplier * state_ + (1.0f - multiplier) * last_sample_; + last_state_time_ms_ = time_ms; +} + +} // namespace webrtc + +// Appendix: derivation of extrapolation during initialization phase. +// (LaTeX syntax) +// Assuming +// \begin{align} +// y(n) &= \alpha_{n-1} y(n-1) + \left(1 - \alpha_{n-1}\right) x(m) \\* +// &= \left(\prod_{i=m}^{n-1} \alpha_i\right) y(m) + +// \left(1 - \prod_{i=m}^{n-1} \alpha_i \right) x(m) +// \end{align} +// Taking $\alpha_{n} = \exp(-\gamma^n)$, $\gamma$ denotes init\_factor\_, the +// multiplier becomes +// \begin{align} +// \prod_{i=m}^{n-1} \alpha_i +// &= \exp\left(-\sum_{i=m}^{n-1} \gamma^i \right) \\* +// &= \begin{cases} +// \exp\left(-\frac{\gamma^m - \gamma^n}{1 - \gamma} \right) +// & \gamma \neq 1 \\* +// m-n & \gamma = 1 +// \end{cases} +// \end{align} +// We know $\gamma = T^{-\frac{1}{T}}$, where $T$ denotes init\_time\_ms\_. Then +// $1 - \gamma$ approaches zero when $T$ increases. This can cause numerical +// difficulties. We multiply $T$ (if $T > 0$) to both numerator and denominator +// in the fraction. See. +// \begin{align} +// \frac{\gamma^m - \gamma^n}{1 - \gamma} +// &= \frac{T^\frac{T-m}{T} - T^\frac{T-n}{T}}{T - T^{1-\frac{1}{T}}} +// \end{align} diff --git a/third_party/libwebrtc/common_audio/smoothing_filter.h b/third_party/libwebrtc/common_audio/smoothing_filter.h new file mode 100644 index 0000000000..3419de7db3 --- /dev/null +++ b/third_party/libwebrtc/common_audio/smoothing_filter.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_AUDIO_SMOOTHING_FILTER_H_ +#define COMMON_AUDIO_SMOOTHING_FILTER_H_ + +#include <stdint.h> + +#include "absl/types/optional.h" + +namespace webrtc { + +class SmoothingFilter { + public: + virtual ~SmoothingFilter() = default; + virtual void AddSample(float sample) = 0; + virtual absl::optional<float> GetAverage() = 0; + virtual bool SetTimeConstantMs(int time_constant_ms) = 0; +}; + +// SmoothingFilterImpl applies an exponential filter +// alpha = exp(-1.0 / time_constant_ms); +// y[t] = alpha * y[t-1] + (1 - alpha) * sample; +// This implies a sample rate of 1000 Hz, i.e., 1 sample / ms. +// But SmoothingFilterImpl allows sparse samples. All missing samples will be +// assumed to equal the last received sample. +class SmoothingFilterImpl final : public SmoothingFilter { + public: + // `init_time_ms` is initialization time. It defines a period starting from + // the arriving time of the first sample. During this period, the exponential + // filter uses a varying time constant so that a smaller time constant will be + // applied to the earlier samples. This is to allow the the filter to adapt to + // earlier samples quickly. After the initialization period, the time constant + // will be set to `init_time_ms` first and can be changed through + // `SetTimeConstantMs`. + explicit SmoothingFilterImpl(int init_time_ms); + + SmoothingFilterImpl() = delete; + SmoothingFilterImpl(const SmoothingFilterImpl&) = delete; + SmoothingFilterImpl& operator=(const SmoothingFilterImpl&) = delete; + + ~SmoothingFilterImpl() override; + + void AddSample(float sample) override; + absl::optional<float> GetAverage() override; + bool SetTimeConstantMs(int time_constant_ms) override; + + // Methods used for unittests. + float alpha() const { return alpha_; } + + private: + void UpdateAlpha(int time_constant_ms); + void ExtrapolateLastSample(int64_t time_ms); + + const int init_time_ms_; + const float init_factor_; + const float init_const_; + + absl::optional<int64_t> init_end_time_ms_; + float last_sample_; + float alpha_; + float state_; + int64_t last_state_time_ms_; +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_SMOOTHING_FILTER_H_ diff --git a/third_party/libwebrtc/common_audio/smoothing_filter_unittest.cc b/third_party/libwebrtc/common_audio/smoothing_filter_unittest.cc new file mode 100644 index 0000000000..47f6c717ec --- /dev/null +++ b/third_party/libwebrtc/common_audio/smoothing_filter_unittest.cc @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/smoothing_filter.h" + +#include <cmath> +#include <memory> + +#include "rtc_base/fake_clock.h" +#include "test/gtest.h" + +namespace webrtc { + +namespace { + +constexpr float kMaxAbsError = 1e-5f; +constexpr int64_t kClockInitialTime = 123456; + +struct SmoothingFilterStates { + explicit SmoothingFilterStates(int init_time_ms) + : smoothing_filter(init_time_ms) { + fake_clock.AdvanceTime(TimeDelta::Millis(kClockInitialTime)); + } + rtc::ScopedFakeClock fake_clock; + SmoothingFilterImpl smoothing_filter; +}; + +// This function does the following: +// 1. Add a sample to filter at current clock, +// 2. Advance the clock by `advance_time_ms`, +// 3. Get the output of both SmoothingFilter and verify that it equals to an +// expected value. +void CheckOutput(SmoothingFilterStates* states, + float sample, + int advance_time_ms, + float expected_ouput) { + states->smoothing_filter.AddSample(sample); + states->fake_clock.AdvanceTime(TimeDelta::Millis(advance_time_ms)); + auto output = states->smoothing_filter.GetAverage(); + EXPECT_TRUE(output); + EXPECT_NEAR(expected_ouput, *output, kMaxAbsError); +} + +} // namespace + +TEST(SmoothingFilterTest, NoOutputWhenNoSampleAdded) { + constexpr int kInitTimeMs = 100; + SmoothingFilterStates states(kInitTimeMs); + EXPECT_FALSE(states.smoothing_filter.GetAverage()); +} + +// Python script to calculate the reference values used in this test. +// import math +// +// class ExpFilter: +// def add_sample(self, new_value): +// self.state = self.state * self.alpha + (1.0 - self.alpha) * new_value +// +// filter = ExpFilter() +// init_time = 795 +// init_factor = (1.0 / init_time) ** (1.0 / init_time) +// +// filter.state = 1.0 +// +// for time_now in range(1, 500): +// filter.alpha = math.exp(-init_factor ** time_now) +// filter.add_sample(1.0) +// print filter.state +// +// for time_now in range(500, 600): +// filter.alpha = math.exp(-init_factor ** time_now) +// filter.add_sample(0.5) +// print filter.state +// +// for time_now in range(600, 700): +// filter.alpha = math.exp(-init_factor ** time_now) +// filter.add_sample(1.0) +// print filter.state +// +// for time_now in range(700, init_time): +// filter.alpha = math.exp(-init_factor ** time_now) +// filter.add_sample(1.0) +// +// filter.alpha = math.exp(-1.0 / init_time) +// for time_now in range(init_time, 800): +// filter.add_sample(1.0) +// print filter.state +// +// for i in range(800, 900): +// filter.add_sample(0.5) +// print filter.state +// +// for i in range(900, 1000): +// filter.add_sample(1.0) +// print filter.state +TEST(SmoothingFilterTest, CheckBehaviorAroundInitTime) { + constexpr int kInitTimeMs = 795; + SmoothingFilterStates states(kInitTimeMs); + CheckOutput(&states, 1.0f, 500, 1.0f); + CheckOutput(&states, 0.5f, 100, 0.680562264029f); + CheckOutput(&states, 1.0f, 100, 0.794207139813f); + // Next step will go across initialization time. + CheckOutput(&states, 1.0f, 100, 0.829803409752f); + CheckOutput(&states, 0.5f, 100, 0.790821764210f); + CheckOutput(&states, 1.0f, 100, 0.815545922911f); +} + +TEST(SmoothingFilterTest, InitTimeEqualsZero) { + constexpr int kInitTimeMs = 0; + SmoothingFilterStates states(kInitTimeMs); + CheckOutput(&states, 1.0f, 1, 1.0f); + CheckOutput(&states, 0.5f, 1, 0.5f); +} + +TEST(SmoothingFilterTest, InitTimeEqualsOne) { + constexpr int kInitTimeMs = 1; + SmoothingFilterStates states(kInitTimeMs); + CheckOutput(&states, 1.0f, 1, 1.0f); + CheckOutput(&states, 0.5f, 1, + 1.0f * std::exp(-1.0f) + (1.0f - std::exp(-1.0f)) * 0.5f); +} + +TEST(SmoothingFilterTest, GetAverageOutputsEmptyBeforeFirstSample) { + constexpr int kInitTimeMs = 100; + SmoothingFilterStates states(kInitTimeMs); + EXPECT_FALSE(states.smoothing_filter.GetAverage()); + constexpr float kFirstSample = 1.2345f; + states.smoothing_filter.AddSample(kFirstSample); + EXPECT_EQ(kFirstSample, states.smoothing_filter.GetAverage()); +} + +TEST(SmoothingFilterTest, CannotChangeTimeConstantDuringInitialization) { + constexpr int kInitTimeMs = 100; + SmoothingFilterStates states(kInitTimeMs); + states.smoothing_filter.AddSample(0.0); + + // During initialization, `SetTimeConstantMs` does not take effect. + states.fake_clock.AdvanceTime(TimeDelta::Millis(kInitTimeMs - 1)); + states.smoothing_filter.AddSample(0.0); + + EXPECT_FALSE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2)); + EXPECT_NE(std::exp(-1.0f / (kInitTimeMs * 2)), + states.smoothing_filter.alpha()); + + states.fake_clock.AdvanceTime(TimeDelta::Millis(1)); + states.smoothing_filter.AddSample(0.0); + // When initialization finishes, the time constant should be come + // `kInitTimeConstantMs`. + EXPECT_FLOAT_EQ(std::exp(-1.0f / kInitTimeMs), + states.smoothing_filter.alpha()); + + // After initialization, `SetTimeConstantMs` takes effect. + EXPECT_TRUE(states.smoothing_filter.SetTimeConstantMs(kInitTimeMs * 2)); + EXPECT_FLOAT_EQ(std::exp(-1.0f / (kInitTimeMs * 2)), + states.smoothing_filter.alpha()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/BUILD.gn b/third_party/libwebrtc/common_audio/third_party/ooura/BUILD.gn new file mode 100644 index 0000000000..a0ddf777db --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/BUILD.gn @@ -0,0 +1,58 @@ +# 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_library("fft_size_128") { + sources = [ + "fft_size_128/ooura_fft.cc", + "fft_size_128/ooura_fft.h", + "fft_size_128/ooura_fft_tables_common.h", + ] + deps = [ + "../../../rtc_base/system:arch", + "../../../system_wrappers", + ] + cflags = [] + + if (target_cpu == "x86" || target_cpu == "x64") { + sources += [ + "fft_size_128/ooura_fft_sse2.cc", + "fft_size_128/ooura_fft_tables_neon_sse2.h", + ] + if (is_posix || is_fuchsia) { + cflags += [ "-msse2" ] + } + } + + if (rtc_build_with_neon) { + sources += [ + "fft_size_128/ooura_fft_neon.cc", + "fft_size_128/ooura_fft_tables_neon_sse2.h", + ] + + deps += [ "../../../common_audio" ] + + if (target_cpu != "arm64") { + # Enable compilation for the NEON instruction set. + suppressed_configs += [ "//build/config/compiler:compiler_arm_fpu" ] + cflags += [ "-mfpu=neon" ] + } + } + + if (target_cpu == "mipsel" && mips_float_abi == "hard") { + sources += [ "fft_size_128/ooura_fft_mips.cc" ] + } +} + +rtc_library("fft_size_256") { + sources = [ + "fft_size_256/fft4g.cc", + "fft_size_256/fft4g.h", + ] +} diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/LICENSE b/third_party/libwebrtc/common_audio/third_party/ooura/LICENSE new file mode 100644 index 0000000000..3bf870aa3c --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/LICENSE @@ -0,0 +1,8 @@ +/* + * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html + * Copyright Takuya OOURA, 1996-2001 + * + * You may use, copy, modify and distribute this code for any purpose (include + * commercial use) and without fee. Please refer to this package when you modify + * this code. + */ diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/README.chromium b/third_party/libwebrtc/common_audio/third_party/ooura/README.chromium new file mode 100644 index 0000000000..9df2ddb5e2 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/README.chromium @@ -0,0 +1,13 @@ +Name: General Purpose FFT (Fast Fourier/Cosine/Sine Transform) Package +Short Name: fft4g +URL: http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html +Version: 0 +Date: 2018-06-19 +License: Custome license +License File: LICENSE +Security Critical: yes + +Description: +This is a package to calculate Discrete Fourier/Cosine/Sine Transforms of +1-dimensional sequences of length 2^N. This package contains C and Fortran +FFT codes. diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.cc b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.cc new file mode 100644 index 0000000000..693312012b --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.cc @@ -0,0 +1,548 @@ +/* + * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html + * Copyright Takuya OOURA, 1996-2001 + * + * You may use, copy, modify and distribute this code for any purpose (include + * commercial use) and without fee. Please refer to this package when you modify + * this code. + * + * Changes by the WebRTC authors: + * - Trivial type modifications. + * - Minimal code subset to do rdft of length 128. + * - Optimizations because of known length. + * - Removed the global variables by moving the code in to a class in order + * to make it thread safe. + * + * All changes are covered by the WebRTC license and IP grant: + * 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 "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" + +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" +#include "rtc_base/system/arch.h" +#include "system_wrappers/include/cpu_features_wrapper.h" + +namespace webrtc { + +namespace { + +#if !(defined(MIPS_FPU_LE) || defined(WEBRTC_HAS_NEON)) +static void cft1st_128_C(float* a) { + const int n = 128; + int j, k1, k2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + // The processing of the first set of elements was simplified in C to avoid + // some operations (multiplication by zero or one, addition of two elements + // multiplied by the same weight, ...). + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wk1r = rdft_w[2]; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wk1r * (x0r - x0i); + a[11] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wk1r * (x0i - x0r); + a[15] = wk1r * (x0i + x0r); + k1 = 0; + for (j = 16; j < n; j += 16) { + k1 += 2; + k2 = 2 * k1; + wk2r = rdft_w[k1 + 0]; + wk2i = rdft_w[k1 + 1]; + wk1r = rdft_w[k2 + 0]; + wk1i = rdft_w[k2 + 1]; + wk3r = rdft_wk3ri_first[k1 + 0]; + wk3i = rdft_wk3ri_first[k1 + 1]; + x0r = a[j + 0] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j + 0] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j + 0] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + wk1r = rdft_w[k2 + 2]; + wk1i = rdft_w[k2 + 3]; + wk3r = rdft_wk3ri_second[k1 + 0]; + wk3i = rdft_wk3ri_second[k1 + 1]; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } +} + +static void cftmdl_128_C(float* a) { + const int l = 8; + const int n = 128; + const int m = 32; + int j0, j1, j2, j3, k, k1, k2, m2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + for (j0 = 0; j0 < l; j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j2 + 0] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1 + 0] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3 + 0] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wk1r = rdft_w[2]; + for (j0 = m; j0 < l + m; j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + a[j2 + 0] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1 + 0] = wk1r * (x0r - x0i); + a[j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3 + 0] = wk1r * (x0i - x0r); + a[j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + k1 += 2; + k2 = 2 * k1; + wk2r = rdft_w[k1 + 0]; + wk2i = rdft_w[k1 + 1]; + wk1r = rdft_w[k2 + 0]; + wk1i = rdft_w[k2 + 1]; + wk3r = rdft_wk3ri_first[k1 + 0]; + wk3i = rdft_wk3ri_first[k1 + 1]; + for (j0 = k; j0 < l + k; j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2 + 0] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1 + 0] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 + 0] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + wk1r = rdft_w[k2 + 2]; + wk1i = rdft_w[k2 + 3]; + wk3r = rdft_wk3ri_second[k1 + 0]; + wk3i = rdft_wk3ri_second[k1 + 1]; + for (j0 = k + m; j0 < l + (k + m); j0 += 2) { + j1 = j0 + 8; + j2 = j0 + 16; + j3 = j0 + 24; + x0r = a[j0 + 0] + a[j1 + 0]; + x0i = a[j0 + 1] + a[j1 + 1]; + x1r = a[j0 + 0] - a[j1 + 0]; + x1i = a[j0 + 1] - a[j1 + 1]; + x2r = a[j2 + 0] + a[j3 + 0]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2 + 0] - a[j3 + 0]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j0 + 0] = x0r + x2r; + a[j0 + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2 + 0] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1 + 0] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3 + 0] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } +} + +static void rftfsub_128_C(float* a) { + const float* c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j2 + 0] -= yr; + a[j2 + 1] -= yi; + a[k2 + 0] += yr; + a[k2 + 1] -= yi; + } +} + +static void rftbsub_128_C(float* a) { + const float* c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + a[1] = -a[1]; + for (j1 = 1, j2 = 2; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j2 + 0] = a[j2 + 0] - yr; + a[j2 + 1] = yi - a[j2 + 1]; + a[k2 + 0] = yr + a[k2 + 0]; + a[k2 + 1] = yi - a[k2 + 1]; + } + a[65] = -a[65]; +} +#endif + +} // namespace + +OouraFft::OouraFft(bool sse2_available) { +#if defined(WEBRTC_ARCH_X86_FAMILY) + use_sse2_ = sse2_available; +#else + use_sse2_ = false; +#endif +} + +OouraFft::OouraFft() { +#if defined(WEBRTC_ARCH_X86_FAMILY) + use_sse2_ = (GetCPUInfo(kSSE2) != 0); +#else + use_sse2_ = false; +#endif +} + +OouraFft::~OouraFft() = default; + +void OouraFft::Fft(float* a) const { + float xi; + bitrv2_128(a); + cftfsub_128(a); + rftfsub_128(a); + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; +} +void OouraFft::InverseFft(float* a) const { + a[1] = 0.5f * (a[0] - a[1]); + a[0] -= a[1]; + rftbsub_128(a); + bitrv2_128(a); + cftbsub_128(a); +} + +void OouraFft::cft1st_128(float* a) const { +#if defined(MIPS_FPU_LE) + cft1st_128_mips(a); +#elif defined(WEBRTC_HAS_NEON) + cft1st_128_neon(a); +#elif defined(WEBRTC_ARCH_X86_FAMILY) + if (use_sse2_) { + cft1st_128_SSE2(a); + } else { + cft1st_128_C(a); + } +#else + cft1st_128_C(a); +#endif +} +void OouraFft::cftmdl_128(float* a) const { +#if defined(MIPS_FPU_LE) + cftmdl_128_mips(a); +#elif defined(WEBRTC_HAS_NEON) + cftmdl_128_neon(a); +#elif defined(WEBRTC_ARCH_X86_FAMILY) + if (use_sse2_) { + cftmdl_128_SSE2(a); + } else { + cftmdl_128_C(a); + } +#else + cftmdl_128_C(a); +#endif +} +void OouraFft::rftfsub_128(float* a) const { +#if defined(MIPS_FPU_LE) + rftfsub_128_mips(a); +#elif defined(WEBRTC_HAS_NEON) + rftfsub_128_neon(a); +#elif defined(WEBRTC_ARCH_X86_FAMILY) + if (use_sse2_) { + rftfsub_128_SSE2(a); + } else { + rftfsub_128_C(a); + } +#else + rftfsub_128_C(a); +#endif +} + +void OouraFft::rftbsub_128(float* a) const { +#if defined(MIPS_FPU_LE) + rftbsub_128_mips(a); +#elif defined(WEBRTC_HAS_NEON) + rftbsub_128_neon(a); +#elif defined(WEBRTC_ARCH_X86_FAMILY) + if (use_sse2_) { + rftbsub_128_SSE2(a); + } else { + rftbsub_128_C(a); + } +#else + rftbsub_128_C(a); +#endif +} + +void OouraFft::cftbsub_128(float* a) const { + int j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + cft1st_128(a); + cftmdl_128(a); + l = 32; + + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } +} + +void OouraFft::cftfsub_128(float* a) const { + int j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + cft1st_128(a); + cftmdl_128(a); + l = 32; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } +} + +void OouraFft::bitrv2_128(float* a) const { + /* + Following things have been attempted but are no faster: + (a) Storing the swap indexes in a LUT (index calculations are done + for 'free' while waiting on memory/L1). + (b) Consolidate the load/store of two consecutive floats by a 64 bit + integer (execution is memory/L1 bound). + (c) Do a mix of floats and 64 bit integer to maximize register + utilization (execution is memory/L1 bound). + (d) Replacing ip[i] by ((k<<31)>>25) + ((k >> 1)<<5). + (e) Hard-coding of the offsets to completely eliminates index + calculations. + */ + + unsigned int j, j1, k, k1; + float xr, xi, yr, yi; + + const int ip[4] = {0, 64, 32, 96}; + for (k = 0; k < 4; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1 + 0]; + xi = a[j1 + 1]; + yr = a[k1 + 0]; + yi = a[k1 + 1]; + a[j1 + 0] = yr; + a[j1 + 1] = yi; + a[k1 + 0] = xr; + a[k1 + 1] = xi; + j1 += 8; + k1 += 16; + xr = a[j1 + 0]; + xi = a[j1 + 1]; + yr = a[k1 + 0]; + yi = a[k1 + 1]; + a[j1 + 0] = yr; + a[j1 + 1] = yi; + a[k1 + 0] = xr; + a[k1 + 1] = xi; + j1 += 8; + k1 -= 8; + xr = a[j1 + 0]; + xi = a[j1 + 1]; + yr = a[k1 + 0]; + yi = a[k1 + 1]; + a[j1 + 0] = yr; + a[j1 + 1] = yi; + a[k1 + 0] = xr; + a[k1 + 1] = xi; + j1 += 8; + k1 += 16; + xr = a[j1 + 0]; + xi = a[j1 + 1]; + yr = a[k1 + 0]; + yi = a[k1 + 1]; + a[j1 + 0] = yr; + a[j1 + 1] = yi; + a[k1 + 0] = xr; + a[k1 + 1] = xi; + } + j1 = 2 * k + 8 + ip[k]; + k1 = j1 + 8; + xr = a[j1 + 0]; + xi = a[j1 + 1]; + yr = a[k1 + 0]; + yi = a[k1 + 1]; + a[j1 + 0] = yr; + a[j1 + 1] = yi; + a[k1 + 0] = xr; + a[k1 + 1] = xi; + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h new file mode 100644 index 0000000000..8273dfe58e --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_ +#define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_ + +#include "rtc_base/system/arch.h" + +namespace webrtc { + +#if defined(WEBRTC_ARCH_X86_FAMILY) +void cft1st_128_SSE2(float* a); +void cftmdl_128_SSE2(float* a); +void rftfsub_128_SSE2(float* a); +void rftbsub_128_SSE2(float* a); +#endif + +#if defined(MIPS_FPU_LE) +void cft1st_128_mips(float* a); +void cftmdl_128_mips(float* a); +void rftfsub_128_mips(float* a); +void rftbsub_128_mips(float* a); +#endif + +#if defined(WEBRTC_HAS_NEON) +void cft1st_128_neon(float* a); +void cftmdl_128_neon(float* a); +void rftfsub_128_neon(float* a); +void rftbsub_128_neon(float* a); +#endif + +class OouraFft { + public: + // Ctor allowing the availability of SSE2 support to be specified. + explicit OouraFft(bool sse2_available); + + // Deprecated: This Ctor will soon be removed. + OouraFft(); + ~OouraFft(); + void Fft(float* a) const; + void InverseFft(float* a) const; + + private: + void cft1st_128(float* a) const; + void cftmdl_128(float* a) const; + void rftfsub_128(float* a) const; + void rftbsub_128(float* a) const; + + void cftfsub_128(float* a) const; + void cftbsub_128(float* a) const; + void bitrv2_128(float* a) const; + bool use_sse2_; +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_H_ diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc new file mode 100644 index 0000000000..4c231e357d --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc @@ -0,0 +1,1245 @@ +/* + * 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 "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" + +namespace webrtc { + +#if defined(MIPS_FPU_LE) +void bitrv2_128_mips(float* a) { + // n is 128 + float xr, xi, yr, yi; + + xr = a[8]; + xi = a[9]; + yr = a[16]; + yi = a[17]; + a[8] = yr; + a[9] = yi; + a[16] = xr; + a[17] = xi; + + xr = a[64]; + xi = a[65]; + yr = a[2]; + yi = a[3]; + a[64] = yr; + a[65] = yi; + a[2] = xr; + a[3] = xi; + + xr = a[72]; + xi = a[73]; + yr = a[18]; + yi = a[19]; + a[72] = yr; + a[73] = yi; + a[18] = xr; + a[19] = xi; + + xr = a[80]; + xi = a[81]; + yr = a[10]; + yi = a[11]; + a[80] = yr; + a[81] = yi; + a[10] = xr; + a[11] = xi; + + xr = a[88]; + xi = a[89]; + yr = a[26]; + yi = a[27]; + a[88] = yr; + a[89] = yi; + a[26] = xr; + a[27] = xi; + + xr = a[74]; + xi = a[75]; + yr = a[82]; + yi = a[83]; + a[74] = yr; + a[75] = yi; + a[82] = xr; + a[83] = xi; + + xr = a[32]; + xi = a[33]; + yr = a[4]; + yi = a[5]; + a[32] = yr; + a[33] = yi; + a[4] = xr; + a[5] = xi; + + xr = a[40]; + xi = a[41]; + yr = a[20]; + yi = a[21]; + a[40] = yr; + a[41] = yi; + a[20] = xr; + a[21] = xi; + + xr = a[48]; + xi = a[49]; + yr = a[12]; + yi = a[13]; + a[48] = yr; + a[49] = yi; + a[12] = xr; + a[13] = xi; + + xr = a[56]; + xi = a[57]; + yr = a[28]; + yi = a[29]; + a[56] = yr; + a[57] = yi; + a[28] = xr; + a[29] = xi; + + xr = a[34]; + xi = a[35]; + yr = a[68]; + yi = a[69]; + a[34] = yr; + a[35] = yi; + a[68] = xr; + a[69] = xi; + + xr = a[42]; + xi = a[43]; + yr = a[84]; + yi = a[85]; + a[42] = yr; + a[43] = yi; + a[84] = xr; + a[85] = xi; + + xr = a[50]; + xi = a[51]; + yr = a[76]; + yi = a[77]; + a[50] = yr; + a[51] = yi; + a[76] = xr; + a[77] = xi; + + xr = a[58]; + xi = a[59]; + yr = a[92]; + yi = a[93]; + a[58] = yr; + a[59] = yi; + a[92] = xr; + a[93] = xi; + + xr = a[44]; + xi = a[45]; + yr = a[52]; + yi = a[53]; + a[44] = yr; + a[45] = yi; + a[52] = xr; + a[53] = xi; + + xr = a[96]; + xi = a[97]; + yr = a[6]; + yi = a[7]; + a[96] = yr; + a[97] = yi; + a[6] = xr; + a[7] = xi; + + xr = a[104]; + xi = a[105]; + yr = a[22]; + yi = a[23]; + a[104] = yr; + a[105] = yi; + a[22] = xr; + a[23] = xi; + + xr = a[112]; + xi = a[113]; + yr = a[14]; + yi = a[15]; + a[112] = yr; + a[113] = yi; + a[14] = xr; + a[15] = xi; + + xr = a[120]; + xi = a[121]; + yr = a[30]; + yi = a[31]; + a[120] = yr; + a[121] = yi; + a[30] = xr; + a[31] = xi; + + xr = a[98]; + xi = a[99]; + yr = a[70]; + yi = a[71]; + a[98] = yr; + a[99] = yi; + a[70] = xr; + a[71] = xi; + + xr = a[106]; + xi = a[107]; + yr = a[86]; + yi = a[87]; + a[106] = yr; + a[107] = yi; + a[86] = xr; + a[87] = xi; + + xr = a[114]; + xi = a[115]; + yr = a[78]; + yi = a[79]; + a[114] = yr; + a[115] = yi; + a[78] = xr; + a[79] = xi; + + xr = a[122]; + xi = a[123]; + yr = a[94]; + yi = a[95]; + a[122] = yr; + a[123] = yi; + a[94] = xr; + a[95] = xi; + + xr = a[100]; + xi = a[101]; + yr = a[38]; + yi = a[39]; + a[100] = yr; + a[101] = yi; + a[38] = xr; + a[39] = xi; + + xr = a[108]; + xi = a[109]; + yr = a[54]; + yi = a[55]; + a[108] = yr; + a[109] = yi; + a[54] = xr; + a[55] = xi; + + xr = a[116]; + xi = a[117]; + yr = a[46]; + yi = a[47]; + a[116] = yr; + a[117] = yi; + a[46] = xr; + a[47] = xi; + + xr = a[124]; + xi = a[125]; + yr = a[62]; + yi = a[63]; + a[124] = yr; + a[125] = yi; + a[62] = xr; + a[63] = xi; + + xr = a[110]; + xi = a[111]; + yr = a[118]; + yi = a[119]; + a[110] = yr; + a[111] = yi; + a[118] = xr; + a[119] = xi; +} + +void cft1st_128_mips(float* a) { + float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14; + int a_ptr, p1_rdft, p2_rdft, count; + const float* first = rdft_wk3ri_first; + const float* second = rdft_wk3ri_second; + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + // first 8 + "lwc1 %[f0], 0(%[a]) \n\t" + "lwc1 %[f1], 4(%[a]) \n\t" + "lwc1 %[f2], 8(%[a]) \n\t" + "lwc1 %[f3], 12(%[a]) \n\t" + "lwc1 %[f4], 16(%[a]) \n\t" + "lwc1 %[f5], 20(%[a]) \n\t" + "lwc1 %[f6], 24(%[a]) \n\t" + "lwc1 %[f7], 28(%[a]) \n\t" + "add.s %[f8], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f1], %[f3] \n\t" + "add.s %[f3], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "add.s %[f7], %[f8], %[f2] \n\t" + "sub.s %[f8], %[f8], %[f2] \n\t" + "sub.s %[f2], %[f1], %[f4] \n\t" + "add.s %[f1], %[f1], %[f4] \n\t" + "add.s %[f4], %[f6], %[f3] \n\t" + "sub.s %[f6], %[f6], %[f3] \n\t" + "sub.s %[f3], %[f0], %[f5] \n\t" + "add.s %[f0], %[f0], %[f5] \n\t" + "swc1 %[f7], 0(%[a]) \n\t" + "swc1 %[f8], 16(%[a]) \n\t" + "swc1 %[f2], 28(%[a]) \n\t" + "swc1 %[f1], 12(%[a]) \n\t" + "swc1 %[f4], 4(%[a]) \n\t" + "swc1 %[f6], 20(%[a]) \n\t" + "swc1 %[f3], 8(%[a]) \n\t" + "swc1 %[f0], 24(%[a]) \n\t" + // second 8 + "lwc1 %[f0], 32(%[a]) \n\t" + "lwc1 %[f1], 36(%[a]) \n\t" + "lwc1 %[f2], 40(%[a]) \n\t" + "lwc1 %[f3], 44(%[a]) \n\t" + "lwc1 %[f4], 48(%[a]) \n\t" + "lwc1 %[f5], 52(%[a]) \n\t" + "lwc1 %[f6], 56(%[a]) \n\t" + "lwc1 %[f7], 60(%[a]) \n\t" + "add.s %[f8], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f1], %[f3] \n\t" + "add.s %[f3], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "add.s %[f7], %[f4], %[f1] \n\t" + "sub.s %[f4], %[f4], %[f1] \n\t" + "add.s %[f1], %[f3], %[f8] \n\t" + "sub.s %[f3], %[f3], %[f8] \n\t" + "sub.s %[f8], %[f0], %[f5] \n\t" + "add.s %[f0], %[f0], %[f5] \n\t" + "add.s %[f5], %[f6], %[f2] \n\t" + "sub.s %[f6], %[f2], %[f6] \n\t" + "lwc1 %[f9], 8(%[rdft_w]) \n\t" + "sub.s %[f2], %[f8], %[f7] \n\t" + "add.s %[f8], %[f8], %[f7] \n\t" + "sub.s %[f7], %[f4], %[f0] \n\t" + "add.s %[f4], %[f4], %[f0] \n\t" + // prepare for loop + "addiu %[a_ptr], %[a], 64 \n\t" + "addiu %[p1_rdft], %[rdft_w], 8 \n\t" + "addiu %[p2_rdft], %[rdft_w], 16 \n\t" + "addiu %[count], $zero, 7 \n\t" + // finish second 8 + "mul.s %[f2], %[f9], %[f2] \n\t" + "mul.s %[f8], %[f9], %[f8] \n\t" + "mul.s %[f7], %[f9], %[f7] \n\t" + "mul.s %[f4], %[f9], %[f4] \n\t" + "swc1 %[f1], 32(%[a]) \n\t" + "swc1 %[f3], 52(%[a]) \n\t" + "swc1 %[f5], 36(%[a]) \n\t" + "swc1 %[f6], 48(%[a]) \n\t" + "swc1 %[f2], 40(%[a]) \n\t" + "swc1 %[f8], 44(%[a]) \n\t" + "swc1 %[f7], 56(%[a]) \n\t" + "swc1 %[f4], 60(%[a]) \n\t" + // loop + "1: \n\t" + "lwc1 %[f0], 0(%[a_ptr]) \n\t" + "lwc1 %[f1], 4(%[a_ptr]) \n\t" + "lwc1 %[f2], 8(%[a_ptr]) \n\t" + "lwc1 %[f3], 12(%[a_ptr]) \n\t" + "lwc1 %[f4], 16(%[a_ptr]) \n\t" + "lwc1 %[f5], 20(%[a_ptr]) \n\t" + "lwc1 %[f6], 24(%[a_ptr]) \n\t" + "lwc1 %[f7], 28(%[a_ptr]) \n\t" + "add.s %[f8], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f1], %[f3] \n\t" + "add.s %[f3], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "lwc1 %[f10], 4(%[p1_rdft]) \n\t" + "lwc1 %[f11], 0(%[p2_rdft]) \n\t" + "lwc1 %[f12], 4(%[p2_rdft]) \n\t" + "lwc1 %[f13], 8(%[first]) \n\t" + "lwc1 %[f14], 12(%[first]) \n\t" + "add.s %[f7], %[f8], %[f2] \n\t" + "sub.s %[f8], %[f8], %[f2] \n\t" + "add.s %[f2], %[f6], %[f3] \n\t" + "sub.s %[f6], %[f6], %[f3] \n\t" + "add.s %[f3], %[f0], %[f5] \n\t" + "sub.s %[f0], %[f0], %[f5] \n\t" + "add.s %[f5], %[f1], %[f4] \n\t" + "sub.s %[f1], %[f1], %[f4] \n\t" + "swc1 %[f7], 0(%[a_ptr]) \n\t" + "swc1 %[f2], 4(%[a_ptr]) \n\t" + "mul.s %[f4], %[f9], %[f8] \n\t" +#if defined(MIPS32_R2_LE) + "mul.s %[f8], %[f10], %[f8] \n\t" + "mul.s %[f7], %[f11], %[f0] \n\t" + "mul.s %[f0], %[f12], %[f0] \n\t" + "mul.s %[f2], %[f13], %[f3] \n\t" + "mul.s %[f3], %[f14], %[f3] \n\t" + "nmsub.s %[f4], %[f4], %[f10], %[f6] \n\t" + "madd.s %[f8], %[f8], %[f9], %[f6] \n\t" + "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t" + "madd.s %[f0], %[f0], %[f11], %[f5] \n\t" + "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t" + "madd.s %[f3], %[f3], %[f13], %[f1] \n\t" +#else + "mul.s %[f7], %[f10], %[f6] \n\t" + "mul.s %[f6], %[f9], %[f6] \n\t" + "mul.s %[f8], %[f10], %[f8] \n\t" + "mul.s %[f2], %[f11], %[f0] \n\t" + "mul.s %[f11], %[f11], %[f5] \n\t" + "mul.s %[f5], %[f12], %[f5] \n\t" + "mul.s %[f0], %[f12], %[f0] \n\t" + "mul.s %[f12], %[f13], %[f3] \n\t" + "mul.s %[f13], %[f13], %[f1] \n\t" + "mul.s %[f1], %[f14], %[f1] \n\t" + "mul.s %[f3], %[f14], %[f3] \n\t" + "sub.s %[f4], %[f4], %[f7] \n\t" + "add.s %[f8], %[f6], %[f8] \n\t" + "sub.s %[f7], %[f2], %[f5] \n\t" + "add.s %[f0], %[f11], %[f0] \n\t" + "sub.s %[f2], %[f12], %[f1] \n\t" + "add.s %[f3], %[f13], %[f3] \n\t" +#endif + "swc1 %[f4], 16(%[a_ptr]) \n\t" + "swc1 %[f8], 20(%[a_ptr]) \n\t" + "swc1 %[f7], 8(%[a_ptr]) \n\t" + "swc1 %[f0], 12(%[a_ptr]) \n\t" + "swc1 %[f2], 24(%[a_ptr]) \n\t" + "swc1 %[f3], 28(%[a_ptr]) \n\t" + "lwc1 %[f0], 32(%[a_ptr]) \n\t" + "lwc1 %[f1], 36(%[a_ptr]) \n\t" + "lwc1 %[f2], 40(%[a_ptr]) \n\t" + "lwc1 %[f3], 44(%[a_ptr]) \n\t" + "lwc1 %[f4], 48(%[a_ptr]) \n\t" + "lwc1 %[f5], 52(%[a_ptr]) \n\t" + "lwc1 %[f6], 56(%[a_ptr]) \n\t" + "lwc1 %[f7], 60(%[a_ptr]) \n\t" + "add.s %[f8], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f1], %[f3] \n\t" + "add.s %[f3], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "lwc1 %[f11], 8(%[p2_rdft]) \n\t" + "lwc1 %[f12], 12(%[p2_rdft]) \n\t" + "lwc1 %[f13], 8(%[second]) \n\t" + "lwc1 %[f14], 12(%[second]) \n\t" + "add.s %[f7], %[f8], %[f2] \n\t" + "sub.s %[f8], %[f2], %[f8] \n\t" + "add.s %[f2], %[f6], %[f3] \n\t" + "sub.s %[f6], %[f3], %[f6] \n\t" + "add.s %[f3], %[f0], %[f5] \n\t" + "sub.s %[f0], %[f0], %[f5] \n\t" + "add.s %[f5], %[f1], %[f4] \n\t" + "sub.s %[f1], %[f1], %[f4] \n\t" + "swc1 %[f7], 32(%[a_ptr]) \n\t" + "swc1 %[f2], 36(%[a_ptr]) \n\t" + "mul.s %[f4], %[f10], %[f8] \n\t" +#if defined(MIPS32_R2_LE) + "mul.s %[f10], %[f10], %[f6] \n\t" + "mul.s %[f7], %[f11], %[f0] \n\t" + "mul.s %[f11], %[f11], %[f5] \n\t" + "mul.s %[f2], %[f13], %[f3] \n\t" + "mul.s %[f13], %[f13], %[f1] \n\t" + "madd.s %[f4], %[f4], %[f9], %[f6] \n\t" + "nmsub.s %[f10], %[f10], %[f9], %[f8] \n\t" + "nmsub.s %[f7], %[f7], %[f12], %[f5] \n\t" + "madd.s %[f11], %[f11], %[f12], %[f0] \n\t" + "nmsub.s %[f2], %[f2], %[f14], %[f1] \n\t" + "madd.s %[f13], %[f13], %[f14], %[f3] \n\t" +#else + "mul.s %[f2], %[f9], %[f6] \n\t" + "mul.s %[f10], %[f10], %[f6] \n\t" + "mul.s %[f9], %[f9], %[f8] \n\t" + "mul.s %[f7], %[f11], %[f0] \n\t" + "mul.s %[f8], %[f12], %[f5] \n\t" + "mul.s %[f11], %[f11], %[f5] \n\t" + "mul.s %[f12], %[f12], %[f0] \n\t" + "mul.s %[f5], %[f13], %[f3] \n\t" + "mul.s %[f0], %[f14], %[f1] \n\t" + "mul.s %[f13], %[f13], %[f1] \n\t" + "mul.s %[f14], %[f14], %[f3] \n\t" + "add.s %[f4], %[f4], %[f2] \n\t" + "sub.s %[f10], %[f10], %[f9] \n\t" + "sub.s %[f7], %[f7], %[f8] \n\t" + "add.s %[f11], %[f11], %[f12] \n\t" + "sub.s %[f2], %[f5], %[f0] \n\t" + "add.s %[f13], %[f13], %[f14] \n\t" +#endif + "swc1 %[f4], 48(%[a_ptr]) \n\t" + "swc1 %[f10], 52(%[a_ptr]) \n\t" + "swc1 %[f7], 40(%[a_ptr]) \n\t" + "swc1 %[f11], 44(%[a_ptr]) \n\t" + "swc1 %[f2], 56(%[a_ptr]) \n\t" + "swc1 %[f13], 60(%[a_ptr]) \n\t" + "addiu %[count], %[count], -1 \n\t" + "lwc1 %[f9], 8(%[p1_rdft]) \n\t" + "addiu %[a_ptr], %[a_ptr], 64 \n\t" + "addiu %[p1_rdft], %[p1_rdft], 8 \n\t" + "addiu %[p2_rdft], %[p2_rdft], 16 \n\t" + "addiu %[first], %[first], 8 \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[second], %[second], 8 \n\t" + ".set pop \n\t" + : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), + [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), + [f8] "=&f"(f8), [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), + [f12] "=&f"(f12), [f13] "=&f"(f13), [f14] "=&f"(f14), + [a_ptr] "=&r"(a_ptr), [p1_rdft] "=&r"(p1_rdft), [first] "+r"(first), + [p2_rdft] "=&r"(p2_rdft), [count] "=&r"(count), [second] "+r"(second) + : [a] "r"(a), [rdft_w] "r"(rdft_w) + : "memory"); +} + +void cftmdl_128_mips(float* a) { + float f0, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14; + int tmp_a, count; + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[tmp_a], %[a], 0 \n\t" + "addiu %[count], $zero, 4 \n\t" + "1: \n\t" + "addiu %[count], %[count], -1 \n\t" + "lwc1 %[f0], 0(%[tmp_a]) \n\t" + "lwc1 %[f2], 32(%[tmp_a]) \n\t" + "lwc1 %[f4], 64(%[tmp_a]) \n\t" + "lwc1 %[f6], 96(%[tmp_a]) \n\t" + "lwc1 %[f1], 4(%[tmp_a]) \n\t" + "lwc1 %[f3], 36(%[tmp_a]) \n\t" + "lwc1 %[f5], 68(%[tmp_a]) \n\t" + "lwc1 %[f7], 100(%[tmp_a]) \n\t" + "add.s %[f8], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f1], %[f3] \n\t" + "add.s %[f3], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "add.s %[f7], %[f8], %[f2] \n\t" + "sub.s %[f8], %[f8], %[f2] \n\t" + "add.s %[f2], %[f1], %[f4] \n\t" + "sub.s %[f1], %[f1], %[f4] \n\t" + "add.s %[f4], %[f6], %[f3] \n\t" + "sub.s %[f6], %[f6], %[f3] \n\t" + "sub.s %[f3], %[f0], %[f5] \n\t" + "add.s %[f0], %[f0], %[f5] \n\t" + "swc1 %[f7], 0(%[tmp_a]) \n\t" + "swc1 %[f8], 64(%[tmp_a]) \n\t" + "swc1 %[f2], 36(%[tmp_a]) \n\t" + "swc1 %[f1], 100(%[tmp_a]) \n\t" + "swc1 %[f4], 4(%[tmp_a]) \n\t" + "swc1 %[f6], 68(%[tmp_a]) \n\t" + "swc1 %[f3], 32(%[tmp_a]) \n\t" + "swc1 %[f0], 96(%[tmp_a]) \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[tmp_a], %[tmp_a], 8 \n\t" + ".set pop \n\t" + : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), + [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), + [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) + : [a] "r"(a) + : "memory"); + f9 = rdft_w[2]; + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[tmp_a], %[a], 128 \n\t" + "addiu %[count], $zero, 4 \n\t" + "1: \n\t" + "addiu %[count], %[count], -1 \n\t" + "lwc1 %[f0], 0(%[tmp_a]) \n\t" + "lwc1 %[f2], 32(%[tmp_a]) \n\t" + "lwc1 %[f5], 68(%[tmp_a]) \n\t" + "lwc1 %[f7], 100(%[tmp_a]) \n\t" + "lwc1 %[f1], 4(%[tmp_a]) \n\t" + "lwc1 %[f3], 36(%[tmp_a]) \n\t" + "lwc1 %[f4], 64(%[tmp_a]) \n\t" + "lwc1 %[f6], 96(%[tmp_a]) \n\t" + "sub.s %[f8], %[f0], %[f2] \n\t" + "add.s %[f0], %[f0], %[f2] \n\t" + "sub.s %[f2], %[f5], %[f7] \n\t" + "add.s %[f5], %[f5], %[f7] \n\t" + "sub.s %[f7], %[f1], %[f3] \n\t" + "add.s %[f1], %[f1], %[f3] \n\t" + "sub.s %[f3], %[f4], %[f6] \n\t" + "add.s %[f4], %[f4], %[f6] \n\t" + "sub.s %[f6], %[f8], %[f2] \n\t" + "add.s %[f8], %[f8], %[f2] \n\t" + "add.s %[f2], %[f5], %[f1] \n\t" + "sub.s %[f5], %[f5], %[f1] \n\t" + "add.s %[f1], %[f3], %[f7] \n\t" + "sub.s %[f3], %[f3], %[f7] \n\t" + "add.s %[f7], %[f0], %[f4] \n\t" + "sub.s %[f0], %[f0], %[f4] \n\t" + "sub.s %[f4], %[f6], %[f1] \n\t" + "add.s %[f6], %[f6], %[f1] \n\t" + "sub.s %[f1], %[f3], %[f8] \n\t" + "add.s %[f3], %[f3], %[f8] \n\t" + "mul.s %[f4], %[f4], %[f9] \n\t" + "mul.s %[f6], %[f6], %[f9] \n\t" + "mul.s %[f1], %[f1], %[f9] \n\t" + "mul.s %[f3], %[f3], %[f9] \n\t" + "swc1 %[f7], 0(%[tmp_a]) \n\t" + "swc1 %[f2], 4(%[tmp_a]) \n\t" + "swc1 %[f5], 64(%[tmp_a]) \n\t" + "swc1 %[f0], 68(%[tmp_a]) \n\t" + "swc1 %[f4], 32(%[tmp_a]) \n\t" + "swc1 %[f6], 36(%[tmp_a]) \n\t" + "swc1 %[f1], 96(%[tmp_a]) \n\t" + "swc1 %[f3], 100(%[tmp_a]) \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[tmp_a], %[tmp_a], 8 \n\t" + ".set pop \n\t" + : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), + [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), + [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) + : [a] "r"(a), [f9] "f"(f9) + : "memory"); + f10 = rdft_w[3]; + f11 = rdft_w[4]; + f12 = rdft_w[5]; + f13 = rdft_wk3ri_first[2]; + f14 = rdft_wk3ri_first[3]; + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[tmp_a], %[a], 256 \n\t" + "addiu %[count], $zero, 4 \n\t" + "1: \n\t" + "addiu %[count], %[count], -1 \n\t" + "lwc1 %[f0], 0(%[tmp_a]) \n\t" + "lwc1 %[f2], 32(%[tmp_a]) \n\t" + "lwc1 %[f4], 64(%[tmp_a]) \n\t" + "lwc1 %[f6], 96(%[tmp_a]) \n\t" + "lwc1 %[f1], 4(%[tmp_a]) \n\t" + "lwc1 %[f3], 36(%[tmp_a]) \n\t" + "lwc1 %[f5], 68(%[tmp_a]) \n\t" + "lwc1 %[f7], 100(%[tmp_a]) \n\t" + "add.s %[f8], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f1], %[f3] \n\t" + "add.s %[f3], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "sub.s %[f7], %[f8], %[f2] \n\t" + "add.s %[f8], %[f8], %[f2] \n\t" + "add.s %[f2], %[f1], %[f4] \n\t" + "sub.s %[f1], %[f1], %[f4] \n\t" + "sub.s %[f4], %[f6], %[f3] \n\t" + "add.s %[f6], %[f6], %[f3] \n\t" + "sub.s %[f3], %[f0], %[f5] \n\t" + "add.s %[f0], %[f0], %[f5] \n\t" + "swc1 %[f8], 0(%[tmp_a]) \n\t" + "swc1 %[f6], 4(%[tmp_a]) \n\t" + "mul.s %[f5], %[f9], %[f7] \n\t" +#if defined(MIPS32_R2_LE) + "mul.s %[f7], %[f10], %[f7] \n\t" + "mul.s %[f8], %[f11], %[f3] \n\t" + "mul.s %[f3], %[f12], %[f3] \n\t" + "mul.s %[f6], %[f13], %[f0] \n\t" + "mul.s %[f0], %[f14], %[f0] \n\t" + "nmsub.s %[f5], %[f5], %[f10], %[f4] \n\t" + "madd.s %[f7], %[f7], %[f9], %[f4] \n\t" + "nmsub.s %[f8], %[f8], %[f12], %[f2] \n\t" + "madd.s %[f3], %[f3], %[f11], %[f2] \n\t" + "nmsub.s %[f6], %[f6], %[f14], %[f1] \n\t" + "madd.s %[f0], %[f0], %[f13], %[f1] \n\t" + "swc1 %[f5], 64(%[tmp_a]) \n\t" + "swc1 %[f7], 68(%[tmp_a]) \n\t" +#else + "mul.s %[f8], %[f10], %[f4] \n\t" + "mul.s %[f4], %[f9], %[f4] \n\t" + "mul.s %[f7], %[f10], %[f7] \n\t" + "mul.s %[f6], %[f11], %[f3] \n\t" + "mul.s %[f3], %[f12], %[f3] \n\t" + "sub.s %[f5], %[f5], %[f8] \n\t" + "mul.s %[f8], %[f12], %[f2] \n\t" + "mul.s %[f2], %[f11], %[f2] \n\t" + "add.s %[f7], %[f4], %[f7] \n\t" + "mul.s %[f4], %[f13], %[f0] \n\t" + "mul.s %[f0], %[f14], %[f0] \n\t" + "sub.s %[f8], %[f6], %[f8] \n\t" + "mul.s %[f6], %[f14], %[f1] \n\t" + "mul.s %[f1], %[f13], %[f1] \n\t" + "add.s %[f3], %[f2], %[f3] \n\t" + "swc1 %[f5], 64(%[tmp_a]) \n\t" + "swc1 %[f7], 68(%[tmp_a]) \n\t" + "sub.s %[f6], %[f4], %[f6] \n\t" + "add.s %[f0], %[f1], %[f0] \n\t" +#endif + "swc1 %[f8], 32(%[tmp_a]) \n\t" + "swc1 %[f3], 36(%[tmp_a]) \n\t" + "swc1 %[f6], 96(%[tmp_a]) \n\t" + "swc1 %[f0], 100(%[tmp_a]) \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[tmp_a], %[tmp_a], 8 \n\t" + ".set pop \n\t" + : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), + [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), + [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) + : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11), + [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14) + : "memory"); + f11 = rdft_w[6]; + f12 = rdft_w[7]; + f13 = rdft_wk3ri_second[2]; + f14 = rdft_wk3ri_second[3]; + __asm __volatile( + ".set push " + "\n\t" + ".set noreorder " + "\n\t" + "addiu %[tmp_a], %[a], 384 " + "\n\t" + "addiu %[count], $zero, 4 " + "\n\t" + "1: " + "\n\t" + "addiu %[count], %[count], -1 " + "\n\t" + "lwc1 %[f0], 0(%[tmp_a]) " + "\n\t" + "lwc1 %[f1], 4(%[tmp_a]) " + "\n\t" + "lwc1 %[f2], 32(%[tmp_a]) " + "\n\t" + "lwc1 %[f3], 36(%[tmp_a]) " + "\n\t" + "lwc1 %[f4], 64(%[tmp_a]) " + "\n\t" + "lwc1 %[f5], 68(%[tmp_a]) " + "\n\t" + "lwc1 %[f6], 96(%[tmp_a]) " + "\n\t" + "lwc1 %[f7], 100(%[tmp_a]) " + "\n\t" + "add.s %[f8], %[f0], %[f2] " + "\n\t" + "sub.s %[f0], %[f0], %[f2] " + "\n\t" + "add.s %[f2], %[f4], %[f6] " + "\n\t" + "sub.s %[f4], %[f4], %[f6] " + "\n\t" + "add.s %[f6], %[f1], %[f3] " + "\n\t" + "sub.s %[f1], %[f1], %[f3] " + "\n\t" + "add.s %[f3], %[f5], %[f7] " + "\n\t" + "sub.s %[f5], %[f5], %[f7] " + "\n\t" + "sub.s %[f7], %[f2], %[f8] " + "\n\t" + "add.s %[f2], %[f2], %[f8] " + "\n\t" + "add.s %[f8], %[f1], %[f4] " + "\n\t" + "sub.s %[f1], %[f1], %[f4] " + "\n\t" + "sub.s %[f4], %[f3], %[f6] " + "\n\t" + "add.s %[f3], %[f3], %[f6] " + "\n\t" + "sub.s %[f6], %[f0], %[f5] " + "\n\t" + "add.s %[f0], %[f0], %[f5] " + "\n\t" + "swc1 %[f2], 0(%[tmp_a]) " + "\n\t" + "swc1 %[f3], 4(%[tmp_a]) " + "\n\t" + "mul.s %[f5], %[f10], %[f7] " + "\n\t" +#if defined(MIPS32_R2_LE) + "mul.s %[f7], %[f9], %[f7] " + "\n\t" + "mul.s %[f2], %[f12], %[f8] " + "\n\t" + "mul.s %[f8], %[f11], %[f8] " + "\n\t" + "mul.s %[f3], %[f14], %[f1] " + "\n\t" + "mul.s %[f1], %[f13], %[f1] " + "\n\t" + "madd.s %[f5], %[f5], %[f9], %[f4] " + "\n\t" + "msub.s %[f7], %[f7], %[f10], %[f4] " + "\n\t" + "msub.s %[f2], %[f2], %[f11], %[f6] " + "\n\t" + "madd.s %[f8], %[f8], %[f12], %[f6] " + "\n\t" + "msub.s %[f3], %[f3], %[f13], %[f0] " + "\n\t" + "madd.s %[f1], %[f1], %[f14], %[f0] " + "\n\t" + "swc1 %[f5], 64(%[tmp_a]) " + "\n\t" + "swc1 %[f7], 68(%[tmp_a]) " + "\n\t" +#else + "mul.s %[f2], %[f9], %[f4] " + "\n\t" + "mul.s %[f4], %[f10], %[f4] " + "\n\t" + "mul.s %[f7], %[f9], %[f7] " + "\n\t" + "mul.s %[f3], %[f11], %[f6] " + "\n\t" + "mul.s %[f6], %[f12], %[f6] " + "\n\t" + "add.s %[f5], %[f5], %[f2] " + "\n\t" + "sub.s %[f7], %[f4], %[f7] " + "\n\t" + "mul.s %[f2], %[f12], %[f8] " + "\n\t" + "mul.s %[f8], %[f11], %[f8] " + "\n\t" + "mul.s %[f4], %[f14], %[f1] " + "\n\t" + "mul.s %[f1], %[f13], %[f1] " + "\n\t" + "sub.s %[f2], %[f3], %[f2] " + "\n\t" + "mul.s %[f3], %[f13], %[f0] " + "\n\t" + "mul.s %[f0], %[f14], %[f0] " + "\n\t" + "add.s %[f8], %[f8], %[f6] " + "\n\t" + "swc1 %[f5], 64(%[tmp_a]) " + "\n\t" + "swc1 %[f7], 68(%[tmp_a]) " + "\n\t" + "sub.s %[f3], %[f3], %[f4] " + "\n\t" + "add.s %[f1], %[f1], %[f0] " + "\n\t" +#endif + "swc1 %[f2], 32(%[tmp_a]) " + "\n\t" + "swc1 %[f8], 36(%[tmp_a]) " + "\n\t" + "swc1 %[f3], 96(%[tmp_a]) " + "\n\t" + "swc1 %[f1], 100(%[tmp_a]) " + "\n\t" + "bgtz %[count], 1b " + "\n\t" + " addiu %[tmp_a], %[tmp_a], 8 " + "\n\t" + ".set pop " + "\n\t" + : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), + [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), + [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) + : [a] "r"(a), [f9] "f"(f9), [f10] "f"(f10), [f11] "f"(f11), + [f12] "f"(f12), [f13] "f"(f13), [f14] "f"(f14) + : "memory"); +} + +void cftfsub_128_mips(float* a) { + float f0, f1, f2, f3, f4, f5, f6, f7, f8; + int tmp_a, count; + + cft1st_128_mips(a); + cftmdl_128_mips(a); + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[tmp_a], %[a], 0 \n\t" + "addiu %[count], $zero, 16 \n\t" + "1: \n\t" + "addiu %[count], %[count], -1 \n\t" + "lwc1 %[f0], 0(%[tmp_a]) \n\t" + "lwc1 %[f2], 128(%[tmp_a]) \n\t" + "lwc1 %[f4], 256(%[tmp_a]) \n\t" + "lwc1 %[f6], 384(%[tmp_a]) \n\t" + "lwc1 %[f1], 4(%[tmp_a]) \n\t" + "lwc1 %[f3], 132(%[tmp_a]) \n\t" + "lwc1 %[f5], 260(%[tmp_a]) \n\t" + "lwc1 %[f7], 388(%[tmp_a]) \n\t" + "add.s %[f8], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f1], %[f3] \n\t" + "add.s %[f3], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "add.s %[f7], %[f8], %[f2] \n\t" + "sub.s %[f8], %[f8], %[f2] \n\t" + "add.s %[f2], %[f1], %[f4] \n\t" + "sub.s %[f1], %[f1], %[f4] \n\t" + "add.s %[f4], %[f6], %[f3] \n\t" + "sub.s %[f6], %[f6], %[f3] \n\t" + "sub.s %[f3], %[f0], %[f5] \n\t" + "add.s %[f0], %[f0], %[f5] \n\t" + "swc1 %[f7], 0(%[tmp_a]) \n\t" + "swc1 %[f8], 256(%[tmp_a]) \n\t" + "swc1 %[f2], 132(%[tmp_a]) \n\t" + "swc1 %[f1], 388(%[tmp_a]) \n\t" + "swc1 %[f4], 4(%[tmp_a]) \n\t" + "swc1 %[f6], 260(%[tmp_a]) \n\t" + "swc1 %[f3], 128(%[tmp_a]) \n\t" + "swc1 %[f0], 384(%[tmp_a]) \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[tmp_a], %[tmp_a], 8 \n\t" + ".set pop \n\t" + : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), + [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), + [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) + : [a] "r"(a) + : "memory"); +} + +void cftbsub_128_mips(float* a) { + float f0, f1, f2, f3, f4, f5, f6, f7, f8; + int tmp_a, count; + + cft1st_128_mips(a); + cftmdl_128_mips(a); + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "addiu %[tmp_a], %[a], 0 \n\t" + "addiu %[count], $zero, 16 \n\t" + "1: \n\t" + "addiu %[count], %[count], -1 \n\t" + "lwc1 %[f0], 0(%[tmp_a]) \n\t" + "lwc1 %[f2], 128(%[tmp_a]) \n\t" + "lwc1 %[f4], 256(%[tmp_a]) \n\t" + "lwc1 %[f6], 384(%[tmp_a]) \n\t" + "lwc1 %[f1], 4(%[tmp_a]) \n\t" + "lwc1 %[f3], 132(%[tmp_a]) \n\t" + "lwc1 %[f5], 260(%[tmp_a]) \n\t" + "lwc1 %[f7], 388(%[tmp_a]) \n\t" + "add.s %[f8], %[f0], %[f2] \n\t" + "sub.s %[f0], %[f0], %[f2] \n\t" + "add.s %[f2], %[f4], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "add.s %[f6], %[f1], %[f3] \n\t" + "sub.s %[f1], %[f3], %[f1] \n\t" + "add.s %[f3], %[f5], %[f7] \n\t" + "sub.s %[f5], %[f5], %[f7] \n\t" + "add.s %[f7], %[f8], %[f2] \n\t" + "sub.s %[f8], %[f8], %[f2] \n\t" + "sub.s %[f2], %[f1], %[f4] \n\t" + "add.s %[f1], %[f1], %[f4] \n\t" + "add.s %[f4], %[f3], %[f6] \n\t" + "sub.s %[f6], %[f3], %[f6] \n\t" + "sub.s %[f3], %[f0], %[f5] \n\t" + "add.s %[f0], %[f0], %[f5] \n\t" + "neg.s %[f4], %[f4] \n\t" + "swc1 %[f7], 0(%[tmp_a]) \n\t" + "swc1 %[f8], 256(%[tmp_a]) \n\t" + "swc1 %[f2], 132(%[tmp_a]) \n\t" + "swc1 %[f1], 388(%[tmp_a]) \n\t" + "swc1 %[f6], 260(%[tmp_a]) \n\t" + "swc1 %[f3], 128(%[tmp_a]) \n\t" + "swc1 %[f0], 384(%[tmp_a]) \n\t" + "swc1 %[f4], 4(%[tmp_a]) \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[tmp_a], %[tmp_a], 8 \n\t" + ".set pop \n\t" + : [f0] "=&f"(f0), [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), + [f4] "=&f"(f4), [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), + [f8] "=&f"(f8), [tmp_a] "=&r"(tmp_a), [count] "=&r"(count) + : [a] "r"(a) + : "memory"); +} + +void rftfsub_128_mips(float* a) { + const float* c = rdft_w + 32; + const float f0 = 0.5f; + float* a1 = &a[2]; + float* a2 = &a[126]; + const float* c1 = &c[1]; + const float* c2 = &c[31]; + float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15; + int count; + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "lwc1 %[f6], 0(%[c2]) \n\t" + "lwc1 %[f1], 0(%[a1]) \n\t" + "lwc1 %[f2], 0(%[a2]) \n\t" + "lwc1 %[f3], 4(%[a1]) \n\t" + "lwc1 %[f4], 4(%[a2]) \n\t" + "lwc1 %[f5], 0(%[c1]) \n\t" + "sub.s %[f6], %[f0], %[f6] \n\t" + "sub.s %[f7], %[f1], %[f2] \n\t" + "add.s %[f8], %[f3], %[f4] \n\t" + "addiu %[count], $zero, 15 \n\t" + "mul.s %[f9], %[f6], %[f7] \n\t" + "mul.s %[f6], %[f6], %[f8] \n\t" +#if !defined(MIPS32_R2_LE) + "mul.s %[f8], %[f5], %[f8] \n\t" + "mul.s %[f5], %[f5], %[f7] \n\t" + "sub.s %[f9], %[f9], %[f8] \n\t" + "add.s %[f6], %[f6], %[f5] \n\t" +#else + "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t" + "madd.s %[f6], %[f6], %[f5], %[f7] \n\t" +#endif + "sub.s %[f1], %[f1], %[f9] \n\t" + "add.s %[f2], %[f2], %[f9] \n\t" + "sub.s %[f3], %[f3], %[f6] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "swc1 %[f1], 0(%[a1]) \n\t" + "swc1 %[f2], 0(%[a2]) \n\t" + "swc1 %[f3], 4(%[a1]) \n\t" + "swc1 %[f4], 4(%[a2]) \n\t" + "addiu %[a1], %[a1], 8 \n\t" + "addiu %[a2], %[a2], -8 \n\t" + "addiu %[c1], %[c1], 4 \n\t" + "addiu %[c2], %[c2], -4 \n\t" + "1: \n\t" + "lwc1 %[f6], 0(%[c2]) \n\t" + "lwc1 %[f1], 0(%[a1]) \n\t" + "lwc1 %[f2], 0(%[a2]) \n\t" + "lwc1 %[f3], 4(%[a1]) \n\t" + "lwc1 %[f4], 4(%[a2]) \n\t" + "lwc1 %[f5], 0(%[c1]) \n\t" + "sub.s %[f6], %[f0], %[f6] \n\t" + "sub.s %[f7], %[f1], %[f2] \n\t" + "add.s %[f8], %[f3], %[f4] \n\t" + "lwc1 %[f10], -4(%[c2]) \n\t" + "lwc1 %[f11], 8(%[a1]) \n\t" + "lwc1 %[f12], -8(%[a2]) \n\t" + "mul.s %[f9], %[f6], %[f7] \n\t" + "mul.s %[f6], %[f6], %[f8] \n\t" +#if !defined(MIPS32_R2_LE) + "mul.s %[f8], %[f5], %[f8] \n\t" + "mul.s %[f5], %[f5], %[f7] \n\t" + "lwc1 %[f13], 12(%[a1]) \n\t" + "lwc1 %[f14], -4(%[a2]) \n\t" + "lwc1 %[f15], 4(%[c1]) \n\t" + "sub.s %[f9], %[f9], %[f8] \n\t" + "add.s %[f6], %[f6], %[f5] \n\t" +#else + "lwc1 %[f13], 12(%[a1]) \n\t" + "lwc1 %[f14], -4(%[a2]) \n\t" + "lwc1 %[f15], 4(%[c1]) \n\t" + "nmsub.s %[f9], %[f9], %[f5], %[f8] \n\t" + "madd.s %[f6], %[f6], %[f5], %[f7] \n\t" +#endif + "sub.s %[f10], %[f0], %[f10] \n\t" + "sub.s %[f5], %[f11], %[f12] \n\t" + "add.s %[f7], %[f13], %[f14] \n\t" + "sub.s %[f1], %[f1], %[f9] \n\t" + "add.s %[f2], %[f2], %[f9] \n\t" + "sub.s %[f3], %[f3], %[f6] \n\t" + "mul.s %[f8], %[f10], %[f5] \n\t" + "mul.s %[f10], %[f10], %[f7] \n\t" +#if !defined(MIPS32_R2_LE) + "mul.s %[f9], %[f15], %[f7] \n\t" + "mul.s %[f15], %[f15], %[f5] \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "swc1 %[f1], 0(%[a1]) \n\t" + "swc1 %[f2], 0(%[a2]) \n\t" + "sub.s %[f8], %[f8], %[f9] \n\t" + "add.s %[f10], %[f10], %[f15] \n\t" +#else + "swc1 %[f1], 0(%[a1]) \n\t" + "swc1 %[f2], 0(%[a2]) \n\t" + "sub.s %[f4], %[f4], %[f6] \n\t" + "nmsub.s %[f8], %[f8], %[f15], %[f7] \n\t" + "madd.s %[f10], %[f10], %[f15], %[f5] \n\t" +#endif + "swc1 %[f3], 4(%[a1]) \n\t" + "swc1 %[f4], 4(%[a2]) \n\t" + "sub.s %[f11], %[f11], %[f8] \n\t" + "add.s %[f12], %[f12], %[f8] \n\t" + "sub.s %[f13], %[f13], %[f10] \n\t" + "sub.s %[f14], %[f14], %[f10] \n\t" + "addiu %[c2], %[c2], -8 \n\t" + "addiu %[c1], %[c1], 8 \n\t" + "swc1 %[f11], 8(%[a1]) \n\t" + "swc1 %[f12], -8(%[a2]) \n\t" + "swc1 %[f13], 12(%[a1]) \n\t" + "swc1 %[f14], -4(%[a2]) \n\t" + "addiu %[a1], %[a1], 16 \n\t" + "addiu %[count], %[count], -1 \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[a2], %[a2], -16 \n\t" + ".set pop \n\t" + : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2), + [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), + [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), + [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12), + [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15), + [count] "=&r"(count) + : [f0] "f"(f0) + : "memory"); +} + +void rftbsub_128_mips(float* a) { + const float* c = rdft_w + 32; + const float f0 = 0.5f; + float* a1 = &a[2]; + float* a2 = &a[126]; + const float* c1 = &c[1]; + const float* c2 = &c[31]; + float f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15; + int count; + + a[1] = -a[1]; + a[65] = -a[65]; + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + "lwc1 %[f6], 0(%[c2]) \n\t" + "lwc1 %[f1], 0(%[a1]) \n\t" + "lwc1 %[f2], 0(%[a2]) \n\t" + "lwc1 %[f3], 4(%[a1]) \n\t" + "lwc1 %[f4], 4(%[a2]) \n\t" + "lwc1 %[f5], 0(%[c1]) \n\t" + "sub.s %[f6], %[f0], %[f6] \n\t" + "sub.s %[f7], %[f1], %[f2] \n\t" + "add.s %[f8], %[f3], %[f4] \n\t" + "addiu %[count], $zero, 15 \n\t" + "mul.s %[f9], %[f6], %[f7] \n\t" + "mul.s %[f6], %[f6], %[f8] \n\t" +#if !defined(MIPS32_R2_LE) + "mul.s %[f8], %[f5], %[f8] \n\t" + "mul.s %[f5], %[f5], %[f7] \n\t" + "add.s %[f9], %[f9], %[f8] \n\t" + "sub.s %[f6], %[f6], %[f5] \n\t" +#else + "madd.s %[f9], %[f9], %[f5], %[f8] \n\t" + "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t" +#endif + "sub.s %[f1], %[f1], %[f9] \n\t" + "add.s %[f2], %[f2], %[f9] \n\t" + "sub.s %[f3], %[f6], %[f3] \n\t" + "sub.s %[f4], %[f6], %[f4] \n\t" + "swc1 %[f1], 0(%[a1]) \n\t" + "swc1 %[f2], 0(%[a2]) \n\t" + "swc1 %[f3], 4(%[a1]) \n\t" + "swc1 %[f4], 4(%[a2]) \n\t" + "addiu %[a1], %[a1], 8 \n\t" + "addiu %[a2], %[a2], -8 \n\t" + "addiu %[c1], %[c1], 4 \n\t" + "addiu %[c2], %[c2], -4 \n\t" + "1: \n\t" + "lwc1 %[f6], 0(%[c2]) \n\t" + "lwc1 %[f1], 0(%[a1]) \n\t" + "lwc1 %[f2], 0(%[a2]) \n\t" + "lwc1 %[f3], 4(%[a1]) \n\t" + "lwc1 %[f4], 4(%[a2]) \n\t" + "lwc1 %[f5], 0(%[c1]) \n\t" + "sub.s %[f6], %[f0], %[f6] \n\t" + "sub.s %[f7], %[f1], %[f2] \n\t" + "add.s %[f8], %[f3], %[f4] \n\t" + "lwc1 %[f10], -4(%[c2]) \n\t" + "lwc1 %[f11], 8(%[a1]) \n\t" + "lwc1 %[f12], -8(%[a2]) \n\t" + "mul.s %[f9], %[f6], %[f7] \n\t" + "mul.s %[f6], %[f6], %[f8] \n\t" +#if !defined(MIPS32_R2_LE) + "mul.s %[f8], %[f5], %[f8] \n\t" + "mul.s %[f5], %[f5], %[f7] \n\t" + "lwc1 %[f13], 12(%[a1]) \n\t" + "lwc1 %[f14], -4(%[a2]) \n\t" + "lwc1 %[f15], 4(%[c1]) \n\t" + "add.s %[f9], %[f9], %[f8] \n\t" + "sub.s %[f6], %[f6], %[f5] \n\t" +#else + "lwc1 %[f13], 12(%[a1]) \n\t" + "lwc1 %[f14], -4(%[a2]) \n\t" + "lwc1 %[f15], 4(%[c1]) \n\t" + "madd.s %[f9], %[f9], %[f5], %[f8] \n\t" + "nmsub.s %[f6], %[f6], %[f5], %[f7] \n\t" +#endif + "sub.s %[f10], %[f0], %[f10] \n\t" + "sub.s %[f5], %[f11], %[f12] \n\t" + "add.s %[f7], %[f13], %[f14] \n\t" + "sub.s %[f1], %[f1], %[f9] \n\t" + "add.s %[f2], %[f2], %[f9] \n\t" + "sub.s %[f3], %[f6], %[f3] \n\t" + "mul.s %[f8], %[f10], %[f5] \n\t" + "mul.s %[f10], %[f10], %[f7] \n\t" +#if !defined(MIPS32_R2_LE) + "mul.s %[f9], %[f15], %[f7] \n\t" + "mul.s %[f15], %[f15], %[f5] \n\t" + "sub.s %[f4], %[f6], %[f4] \n\t" + "swc1 %[f1], 0(%[a1]) \n\t" + "swc1 %[f2], 0(%[a2]) \n\t" + "add.s %[f8], %[f8], %[f9] \n\t" + "sub.s %[f10], %[f10], %[f15] \n\t" +#else + "swc1 %[f1], 0(%[a1]) \n\t" + "swc1 %[f2], 0(%[a2]) \n\t" + "sub.s %[f4], %[f6], %[f4] \n\t" + "madd.s %[f8], %[f8], %[f15], %[f7] \n\t" + "nmsub.s %[f10], %[f10], %[f15], %[f5] \n\t" +#endif + "swc1 %[f3], 4(%[a1]) \n\t" + "swc1 %[f4], 4(%[a2]) \n\t" + "sub.s %[f11], %[f11], %[f8] \n\t" + "add.s %[f12], %[f12], %[f8] \n\t" + "sub.s %[f13], %[f10], %[f13] \n\t" + "sub.s %[f14], %[f10], %[f14] \n\t" + "addiu %[c2], %[c2], -8 \n\t" + "addiu %[c1], %[c1], 8 \n\t" + "swc1 %[f11], 8(%[a1]) \n\t" + "swc1 %[f12], -8(%[a2]) \n\t" + "swc1 %[f13], 12(%[a1]) \n\t" + "swc1 %[f14], -4(%[a2]) \n\t" + "addiu %[a1], %[a1], 16 \n\t" + "addiu %[count], %[count], -1 \n\t" + "bgtz %[count], 1b \n\t" + " addiu %[a2], %[a2], -16 \n\t" + ".set pop \n\t" + : [a1] "+r"(a1), [a2] "+r"(a2), [c1] "+r"(c1), [c2] "+r"(c2), + [f1] "=&f"(f1), [f2] "=&f"(f2), [f3] "=&f"(f3), [f4] "=&f"(f4), + [f5] "=&f"(f5), [f6] "=&f"(f6), [f7] "=&f"(f7), [f8] "=&f"(f8), + [f9] "=&f"(f9), [f10] "=&f"(f10), [f11] "=&f"(f11), [f12] "=&f"(f12), + [f13] "=&f"(f13), [f14] "=&f"(f14), [f15] "=&f"(f15), + [count] "=&r"(count) + : [f0] "f"(f0) + : "memory"); +} +#endif + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc new file mode 100644 index 0000000000..acab9722dc --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc @@ -0,0 +1,351 @@ +/* + * 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. + */ + +/* + * The rdft AEC algorithm, neon version of speed-critical functions. + * + * Based on the sse2 version. + */ + +#include <arm_neon.h> + +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h" + +namespace webrtc { + +#if defined(WEBRTC_HAS_NEON) +void cft1st_128_neon(float* a) { + const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign); + int j, k2; + + for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) { + float32x4_t a00v = vld1q_f32(&a[j + 0]); + float32x4_t a04v = vld1q_f32(&a[j + 4]); + float32x4_t a08v = vld1q_f32(&a[j + 8]); + float32x4_t a12v = vld1q_f32(&a[j + 12]); + float32x4_t a01v = vcombine_f32(vget_low_f32(a00v), vget_low_f32(a08v)); + float32x4_t a23v = vcombine_f32(vget_high_f32(a00v), vget_high_f32(a08v)); + float32x4_t a45v = vcombine_f32(vget_low_f32(a04v), vget_low_f32(a12v)); + float32x4_t a67v = vcombine_f32(vget_high_f32(a04v), vget_high_f32(a12v)); + const float32x4_t wk1rv = vld1q_f32(&rdft_wk1r[k2]); + const float32x4_t wk1iv = vld1q_f32(&rdft_wk1i[k2]); + const float32x4_t wk2rv = vld1q_f32(&rdft_wk2r[k2]); + const float32x4_t wk2iv = vld1q_f32(&rdft_wk2i[k2]); + const float32x4_t wk3rv = vld1q_f32(&rdft_wk3r[k2]); + const float32x4_t wk3iv = vld1q_f32(&rdft_wk3i[k2]); + float32x4_t x0v = vaddq_f32(a01v, a23v); + const float32x4_t x1v = vsubq_f32(a01v, a23v); + const float32x4_t x2v = vaddq_f32(a45v, a67v); + const float32x4_t x3v = vsubq_f32(a45v, a67v); + const float32x4_t x3w = vrev64q_f32(x3v); + float32x4_t x0w; + a01v = vaddq_f32(x0v, x2v); + x0v = vsubq_f32(x0v, x2v); + x0w = vrev64q_f32(x0v); + a45v = vmulq_f32(wk2rv, x0v); + a45v = vmlaq_f32(a45v, wk2iv, x0w); + x0v = vmlaq_f32(x1v, x3w, vec_swap_sign); + x0w = vrev64q_f32(x0v); + a23v = vmulq_f32(wk1rv, x0v); + a23v = vmlaq_f32(a23v, wk1iv, x0w); + x0v = vmlsq_f32(x1v, x3w, vec_swap_sign); + x0w = vrev64q_f32(x0v); + a67v = vmulq_f32(wk3rv, x0v); + a67v = vmlaq_f32(a67v, wk3iv, x0w); + a00v = vcombine_f32(vget_low_f32(a01v), vget_low_f32(a23v)); + a04v = vcombine_f32(vget_low_f32(a45v), vget_low_f32(a67v)); + a08v = vcombine_f32(vget_high_f32(a01v), vget_high_f32(a23v)); + a12v = vcombine_f32(vget_high_f32(a45v), vget_high_f32(a67v)); + vst1q_f32(&a[j + 0], a00v); + vst1q_f32(&a[j + 4], a04v); + vst1q_f32(&a[j + 8], a08v); + vst1q_f32(&a[j + 12], a12v); + } +} + +void cftmdl_128_neon(float* a) { + int j; + const int l = 8; + const float32x4_t vec_swap_sign = vld1q_f32((float32_t*)k_swap_sign); + float32x4_t wk1rv = vld1q_f32(cftmdl_wk1r); + + for (j = 0; j < l; j += 2) { + const float32x2_t a_00 = vld1_f32(&a[j + 0]); + const float32x2_t a_08 = vld1_f32(&a[j + 8]); + const float32x2_t a_32 = vld1_f32(&a[j + 32]); + const float32x2_t a_40 = vld1_f32(&a[j + 40]); + const float32x4_t a_00_32 = vcombine_f32(a_00, a_32); + const float32x4_t a_08_40 = vcombine_f32(a_08, a_40); + const float32x4_t x0r0_0i0_0r1_x0i1 = vaddq_f32(a_00_32, a_08_40); + const float32x4_t x1r0_1i0_1r1_x1i1 = vsubq_f32(a_00_32, a_08_40); + const float32x2_t a_16 = vld1_f32(&a[j + 16]); + const float32x2_t a_24 = vld1_f32(&a[j + 24]); + const float32x2_t a_48 = vld1_f32(&a[j + 48]); + const float32x2_t a_56 = vld1_f32(&a[j + 56]); + const float32x4_t a_16_48 = vcombine_f32(a_16, a_48); + const float32x4_t a_24_56 = vcombine_f32(a_24, a_56); + const float32x4_t x2r0_2i0_2r1_x2i1 = vaddq_f32(a_16_48, a_24_56); + const float32x4_t x3r0_3i0_3r1_x3i1 = vsubq_f32(a_16_48, a_24_56); + const float32x4_t xx0 = vaddq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const float32x4_t xx1 = vsubq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const float32x4_t x3i0_3r0_3i1_x3r1 = vrev64q_f32(x3r0_3i0_3r1_x3i1); + const float32x4_t x1_x3_add = + vmlaq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); + const float32x4_t x1_x3_sub = + vmlsq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); + const float32x2_t yy0_a = vdup_lane_f32(vget_high_f32(x1_x3_add), 0); + const float32x2_t yy0_s = vdup_lane_f32(vget_high_f32(x1_x3_sub), 0); + const float32x4_t yy0_as = vcombine_f32(yy0_a, yy0_s); + const float32x2_t yy1_a = vdup_lane_f32(vget_high_f32(x1_x3_add), 1); + const float32x2_t yy1_s = vdup_lane_f32(vget_high_f32(x1_x3_sub), 1); + const float32x4_t yy1_as = vcombine_f32(yy1_a, yy1_s); + const float32x4_t yy0 = vmlaq_f32(yy0_as, vec_swap_sign, yy1_as); + const float32x4_t yy4 = vmulq_f32(wk1rv, yy0); + const float32x4_t xx1_rev = vrev64q_f32(xx1); + const float32x4_t yy4_rev = vrev64q_f32(yy4); + + vst1_f32(&a[j + 0], vget_low_f32(xx0)); + vst1_f32(&a[j + 32], vget_high_f32(xx0)); + vst1_f32(&a[j + 16], vget_low_f32(xx1)); + vst1_f32(&a[j + 48], vget_high_f32(xx1_rev)); + + a[j + 48] = -a[j + 48]; + + vst1_f32(&a[j + 8], vget_low_f32(x1_x3_add)); + vst1_f32(&a[j + 24], vget_low_f32(x1_x3_sub)); + vst1_f32(&a[j + 40], vget_low_f32(yy4)); + vst1_f32(&a[j + 56], vget_high_f32(yy4_rev)); + } + + { + const int k = 64; + const int k1 = 2; + const int k2 = 2 * k1; + const float32x4_t wk2rv = vld1q_f32(&rdft_wk2r[k2 + 0]); + const float32x4_t wk2iv = vld1q_f32(&rdft_wk2i[k2 + 0]); + const float32x4_t wk1iv = vld1q_f32(&rdft_wk1i[k2 + 0]); + const float32x4_t wk3rv = vld1q_f32(&rdft_wk3r[k2 + 0]); + const float32x4_t wk3iv = vld1q_f32(&rdft_wk3i[k2 + 0]); + wk1rv = vld1q_f32(&rdft_wk1r[k2 + 0]); + for (j = k; j < l + k; j += 2) { + const float32x2_t a_00 = vld1_f32(&a[j + 0]); + const float32x2_t a_08 = vld1_f32(&a[j + 8]); + const float32x2_t a_32 = vld1_f32(&a[j + 32]); + const float32x2_t a_40 = vld1_f32(&a[j + 40]); + const float32x4_t a_00_32 = vcombine_f32(a_00, a_32); + const float32x4_t a_08_40 = vcombine_f32(a_08, a_40); + const float32x4_t x0r0_0i0_0r1_x0i1 = vaddq_f32(a_00_32, a_08_40); + const float32x4_t x1r0_1i0_1r1_x1i1 = vsubq_f32(a_00_32, a_08_40); + const float32x2_t a_16 = vld1_f32(&a[j + 16]); + const float32x2_t a_24 = vld1_f32(&a[j + 24]); + const float32x2_t a_48 = vld1_f32(&a[j + 48]); + const float32x2_t a_56 = vld1_f32(&a[j + 56]); + const float32x4_t a_16_48 = vcombine_f32(a_16, a_48); + const float32x4_t a_24_56 = vcombine_f32(a_24, a_56); + const float32x4_t x2r0_2i0_2r1_x2i1 = vaddq_f32(a_16_48, a_24_56); + const float32x4_t x3r0_3i0_3r1_x3i1 = vsubq_f32(a_16_48, a_24_56); + const float32x4_t xx = vaddq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const float32x4_t xx1 = vsubq_f32(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const float32x4_t x3i0_3r0_3i1_x3r1 = vrev64q_f32(x3r0_3i0_3r1_x3i1); + const float32x4_t x1_x3_add = + vmlaq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); + const float32x4_t x1_x3_sub = + vmlsq_f32(x1r0_1i0_1r1_x1i1, vec_swap_sign, x3i0_3r0_3i1_x3r1); + float32x4_t xx4 = vmulq_f32(wk2rv, xx1); + float32x4_t xx12 = vmulq_f32(wk1rv, x1_x3_add); + float32x4_t xx22 = vmulq_f32(wk3rv, x1_x3_sub); + xx4 = vmlaq_f32(xx4, wk2iv, vrev64q_f32(xx1)); + xx12 = vmlaq_f32(xx12, wk1iv, vrev64q_f32(x1_x3_add)); + xx22 = vmlaq_f32(xx22, wk3iv, vrev64q_f32(x1_x3_sub)); + + vst1_f32(&a[j + 0], vget_low_f32(xx)); + vst1_f32(&a[j + 32], vget_high_f32(xx)); + vst1_f32(&a[j + 16], vget_low_f32(xx4)); + vst1_f32(&a[j + 48], vget_high_f32(xx4)); + vst1_f32(&a[j + 8], vget_low_f32(xx12)); + vst1_f32(&a[j + 40], vget_high_f32(xx12)); + vst1_f32(&a[j + 24], vget_low_f32(xx22)); + vst1_f32(&a[j + 56], vget_high_f32(xx22)); + } + } +} + +__inline static float32x4_t reverse_order_f32x4(float32x4_t in) { + // A B C D -> C D A B + const float32x4_t rev = vcombine_f32(vget_high_f32(in), vget_low_f32(in)); + // C D A B -> D C B A + return vrev64q_f32(rev); +} + +void rftfsub_128_neon(float* a) { + const float* c = rdft_w + 32; + int j1, j2; + const float32x4_t mm_half = vdupq_n_f32(0.5f); + + // Vectorized code (four at once). + // Note: commented number are indexes for the first iteration of the loop. + for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { + // Load 'wk'. + const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4, + const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31, + const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31, + const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28, + const float32x4_t wki_ = c_j1; // 1, 2, 3, 4, + // Load and shuffle 'a'. + // 2, 4, 6, 8, 3, 5, 7, 9 + float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]); + // 120, 122, 124, 126, 121, 123, 125, 127, + const float32x4x2_t k2_0_4 = vld2q_f32(&a[122 - j2]); + // 126, 124, 122, 120 + const float32x4_t a_k2_p0 = reverse_order_f32x4(k2_0_4.val[0]); + // 127, 125, 123, 121 + const float32x4_t a_k2_p1 = reverse_order_f32x4(k2_0_4.val[1]); + // Calculate 'x'. + const float32x4_t xr_ = vsubq_f32(a_j2_p.val[0], a_k2_p0); + // 2-126, 4-124, 6-122, 8-120, + const float32x4_t xi_ = vaddq_f32(a_j2_p.val[1], a_k2_p1); + // 3-127, 5-125, 7-123, 9-121, + // Calculate product into 'y'. + // yr = wkr * xr - wki * xi; + // yi = wkr * xi + wki * xr; + const float32x4_t a_ = vmulq_f32(wkr_, xr_); + const float32x4_t b_ = vmulq_f32(wki_, xi_); + const float32x4_t c_ = vmulq_f32(wkr_, xi_); + const float32x4_t d_ = vmulq_f32(wki_, xr_); + const float32x4_t yr_ = vsubq_f32(a_, b_); // 2-126, 4-124, 6-122, 8-120, + const float32x4_t yi_ = vaddq_f32(c_, d_); // 3-127, 5-125, 7-123, 9-121, + // Update 'a'. + // a[j2 + 0] -= yr; + // a[j2 + 1] -= yi; + // a[k2 + 0] += yr; + // a[k2 + 1] -= yi; + // 126, 124, 122, 120, + const float32x4_t a_k2_p0n = vaddq_f32(a_k2_p0, yr_); + // 127, 125, 123, 121, + const float32x4_t a_k2_p1n = vsubq_f32(a_k2_p1, yi_); + // Shuffle in right order and store. + const float32x4_t a_k2_p0nr = vrev64q_f32(a_k2_p0n); + const float32x4_t a_k2_p1nr = vrev64q_f32(a_k2_p1n); + // 124, 125, 126, 127, 120, 121, 122, 123 + const float32x4x2_t a_k2_n = vzipq_f32(a_k2_p0nr, a_k2_p1nr); + // 2, 4, 6, 8, + a_j2_p.val[0] = vsubq_f32(a_j2_p.val[0], yr_); + // 3, 5, 7, 9, + a_j2_p.val[1] = vsubq_f32(a_j2_p.val[1], yi_); + // 2, 3, 4, 5, 6, 7, 8, 9, + vst2q_f32(&a[0 + j2], a_j2_p); + + vst1q_f32(&a[122 - j2], a_k2_n.val[1]); + vst1q_f32(&a[126 - j2], a_k2_n.val[0]); + } + + // Scalar code for the remaining items. + for (; j2 < 64; j1 += 1, j2 += 2) { + const int k2 = 128 - j2; + const int k1 = 32 - j1; + const float wkr = 0.5f - c[k1]; + const float wki = c[j1]; + const float xr = a[j2 + 0] - a[k2 + 0]; + const float xi = a[j2 + 1] + a[k2 + 1]; + const float yr = wkr * xr - wki * xi; + const float yi = wkr * xi + wki * xr; + a[j2 + 0] -= yr; + a[j2 + 1] -= yi; + a[k2 + 0] += yr; + a[k2 + 1] -= yi; + } +} + +void rftbsub_128_neon(float* a) { + const float* c = rdft_w + 32; + int j1, j2; + const float32x4_t mm_half = vdupq_n_f32(0.5f); + + a[1] = -a[1]; + // Vectorized code (four at once). + // Note: commented number are indexes for the first iteration of the loop. + for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { + // Load 'wk'. + const float32x4_t c_j1 = vld1q_f32(&c[j1]); // 1, 2, 3, 4, + const float32x4_t c_k1 = vld1q_f32(&c[29 - j1]); // 28, 29, 30, 31, + const float32x4_t wkrt = vsubq_f32(mm_half, c_k1); // 28, 29, 30, 31, + const float32x4_t wkr_ = reverse_order_f32x4(wkrt); // 31, 30, 29, 28, + const float32x4_t wki_ = c_j1; // 1, 2, 3, 4, + // Load and shuffle 'a'. + // 2, 4, 6, 8, 3, 5, 7, 9 + float32x4x2_t a_j2_p = vld2q_f32(&a[0 + j2]); + // 120, 122, 124, 126, 121, 123, 125, 127, + const float32x4x2_t k2_0_4 = vld2q_f32(&a[122 - j2]); + // 126, 124, 122, 120 + const float32x4_t a_k2_p0 = reverse_order_f32x4(k2_0_4.val[0]); + // 127, 125, 123, 121 + const float32x4_t a_k2_p1 = reverse_order_f32x4(k2_0_4.val[1]); + // Calculate 'x'. + const float32x4_t xr_ = vsubq_f32(a_j2_p.val[0], a_k2_p0); + // 2-126, 4-124, 6-122, 8-120, + const float32x4_t xi_ = vaddq_f32(a_j2_p.val[1], a_k2_p1); + // 3-127, 5-125, 7-123, 9-121, + // Calculate product into 'y'. + // yr = wkr * xr - wki * xi; + // yi = wkr * xi + wki * xr; + const float32x4_t a_ = vmulq_f32(wkr_, xr_); + const float32x4_t b_ = vmulq_f32(wki_, xi_); + const float32x4_t c_ = vmulq_f32(wkr_, xi_); + const float32x4_t d_ = vmulq_f32(wki_, xr_); + const float32x4_t yr_ = vaddq_f32(a_, b_); // 2-126, 4-124, 6-122, 8-120, + const float32x4_t yi_ = vsubq_f32(c_, d_); // 3-127, 5-125, 7-123, 9-121, + // Update 'a'. + // a[j2 + 0] -= yr; + // a[j2 + 1] -= yi; + // a[k2 + 0] += yr; + // a[k2 + 1] -= yi; + // 126, 124, 122, 120, + const float32x4_t a_k2_p0n = vaddq_f32(a_k2_p0, yr_); + // 127, 125, 123, 121, + const float32x4_t a_k2_p1n = vsubq_f32(yi_, a_k2_p1); + // Shuffle in right order and store. + // 2, 3, 4, 5, 6, 7, 8, 9, + const float32x4_t a_k2_p0nr = vrev64q_f32(a_k2_p0n); + const float32x4_t a_k2_p1nr = vrev64q_f32(a_k2_p1n); + // 124, 125, 126, 127, 120, 121, 122, 123 + const float32x4x2_t a_k2_n = vzipq_f32(a_k2_p0nr, a_k2_p1nr); + // 2, 4, 6, 8, + a_j2_p.val[0] = vsubq_f32(a_j2_p.val[0], yr_); + // 3, 5, 7, 9, + a_j2_p.val[1] = vsubq_f32(yi_, a_j2_p.val[1]); + // 2, 3, 4, 5, 6, 7, 8, 9, + vst2q_f32(&a[0 + j2], a_j2_p); + + vst1q_f32(&a[122 - j2], a_k2_n.val[1]); + vst1q_f32(&a[126 - j2], a_k2_n.val[0]); + } + + // Scalar code for the remaining items. + for (; j2 < 64; j1 += 1, j2 += 2) { + const int k2 = 128 - j2; + const int k1 = 32 - j1; + const float wkr = 0.5f - c[k1]; + const float wki = c[j1]; + const float xr = a[j2 + 0] - a[k2 + 0]; + const float xi = a[j2 + 1] + a[k2 + 1]; + const float yr = wkr * xr + wki * xi; + const float yi = wkr * xi - wki * xr; + a[j2 + 0] = a[j2 + 0] - yr; + a[j2 + 1] = yi - a[j2 + 1]; + a[k2 + 0] = yr + a[k2 + 0]; + a[k2 + 1] = yi - a[k2 + 1]; + } + a[65] = -a[65]; +} +#endif + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc new file mode 100644 index 0000000000..7f0802ddfa --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc @@ -0,0 +1,439 @@ +/* + * 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. + */ + +#include <emmintrin.h> +#include <xmmintrin.h> + +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h" +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h" +#include "rtc_base/system/arch.h" + +namespace webrtc { + +#if defined(WEBRTC_ARCH_X86_FAMILY) + +namespace { +// These intrinsics were unavailable before VS 2008. +// TODO(andrew): move to a common file. +#if defined(_MSC_VER) && _MSC_VER < 1500 +static __inline __m128 _mm_castsi128_ps(__m128i a) { + return *(__m128*)&a; +} +static __inline __m128i _mm_castps_si128(__m128 a) { + return *(__m128i*)&a; +} +#endif + +} // namespace + +void cft1st_128_SSE2(float* a) { + const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign); + int j, k2; + + for (k2 = 0, j = 0; j < 128; j += 16, k2 += 4) { + __m128 a00v = _mm_loadu_ps(&a[j + 0]); + __m128 a04v = _mm_loadu_ps(&a[j + 4]); + __m128 a08v = _mm_loadu_ps(&a[j + 8]); + __m128 a12v = _mm_loadu_ps(&a[j + 12]); + __m128 a01v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(1, 0, 1, 0)); + __m128 a23v = _mm_shuffle_ps(a00v, a08v, _MM_SHUFFLE(3, 2, 3, 2)); + __m128 a45v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(1, 0, 1, 0)); + __m128 a67v = _mm_shuffle_ps(a04v, a12v, _MM_SHUFFLE(3, 2, 3, 2)); + + const __m128 wk1rv = _mm_load_ps(&rdft_wk1r[k2]); + const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2]); + const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2]); + const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2]); + const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2]); + const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2]); + __m128 x0v = _mm_add_ps(a01v, a23v); + const __m128 x1v = _mm_sub_ps(a01v, a23v); + const __m128 x2v = _mm_add_ps(a45v, a67v); + const __m128 x3v = _mm_sub_ps(a45v, a67v); + __m128 x0w; + a01v = _mm_add_ps(x0v, x2v); + x0v = _mm_sub_ps(x0v, x2v); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1)); + { + const __m128 a45_0v = _mm_mul_ps(wk2rv, x0v); + const __m128 a45_1v = _mm_mul_ps(wk2iv, x0w); + a45v = _mm_add_ps(a45_0v, a45_1v); + } + { + __m128 a23_0v, a23_1v; + const __m128 x3w = _mm_shuffle_ps(x3v, x3v, _MM_SHUFFLE(2, 3, 0, 1)); + const __m128 x3s = _mm_mul_ps(mm_swap_sign, x3w); + x0v = _mm_add_ps(x1v, x3s); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1)); + a23_0v = _mm_mul_ps(wk1rv, x0v); + a23_1v = _mm_mul_ps(wk1iv, x0w); + a23v = _mm_add_ps(a23_0v, a23_1v); + + x0v = _mm_sub_ps(x1v, x3s); + x0w = _mm_shuffle_ps(x0v, x0v, _MM_SHUFFLE(2, 3, 0, 1)); + } + { + const __m128 a67_0v = _mm_mul_ps(wk3rv, x0v); + const __m128 a67_1v = _mm_mul_ps(wk3iv, x0w); + a67v = _mm_add_ps(a67_0v, a67_1v); + } + + a00v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(1, 0, 1, 0)); + a04v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(1, 0, 1, 0)); + a08v = _mm_shuffle_ps(a01v, a23v, _MM_SHUFFLE(3, 2, 3, 2)); + a12v = _mm_shuffle_ps(a45v, a67v, _MM_SHUFFLE(3, 2, 3, 2)); + _mm_storeu_ps(&a[j + 0], a00v); + _mm_storeu_ps(&a[j + 4], a04v); + _mm_storeu_ps(&a[j + 8], a08v); + _mm_storeu_ps(&a[j + 12], a12v); + } +} + +void cftmdl_128_SSE2(float* a) { + const int l = 8; + const __m128 mm_swap_sign = _mm_load_ps(k_swap_sign); + int j0; + + __m128 wk1rv = _mm_load_ps(cftmdl_wk1r); + for (j0 = 0; j0 < l; j0 += 2) { + const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); + const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); + const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); + const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); + const __m128 a_00_32 = + _mm_shuffle_ps(_mm_castsi128_ps(a_00), _mm_castsi128_ps(a_32), + _MM_SHUFFLE(1, 0, 1, 0)); + const __m128 a_08_40 = + _mm_shuffle_ps(_mm_castsi128_ps(a_08), _mm_castsi128_ps(a_40), + _MM_SHUFFLE(1, 0, 1, 0)); + __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); + const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); + + const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); + const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); + const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); + const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); + const __m128 a_16_48 = + _mm_shuffle_ps(_mm_castsi128_ps(a_16), _mm_castsi128_ps(a_48), + _MM_SHUFFLE(1, 0, 1, 0)); + const __m128 a_24_56 = + _mm_shuffle_ps(_mm_castsi128_ps(a_24), _mm_castsi128_ps(a_56), + _MM_SHUFFLE(1, 0, 1, 0)); + const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); + const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); + + const __m128 xx0 = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + + const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32( + _mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1))); + const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); + const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + + const __m128 yy0 = + _mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(2, 2, 2, 2)); + const __m128 yy1 = + _mm_shuffle_ps(x1_x3_add, x1_x3_sub, _MM_SHUFFLE(3, 3, 3, 3)); + const __m128 yy2 = _mm_mul_ps(mm_swap_sign, yy1); + const __m128 yy3 = _mm_add_ps(yy0, yy2); + const __m128 yy4 = _mm_mul_ps(wk1rv, yy3); + + _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx0)); + _mm_storel_epi64( + (__m128i*)&a[j0 + 32], + _mm_shuffle_epi32(_mm_castps_si128(xx0), _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx1)); + _mm_storel_epi64( + (__m128i*)&a[j0 + 48], + _mm_shuffle_epi32(_mm_castps_si128(xx1), _MM_SHUFFLE(2, 3, 2, 3))); + a[j0 + 48] = -a[j0 + 48]; + + _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(x1_x3_add)); + _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(x1_x3_sub)); + + _mm_storel_epi64((__m128i*)&a[j0 + 40], _mm_castps_si128(yy4)); + _mm_storel_epi64( + (__m128i*)&a[j0 + 56], + _mm_shuffle_epi32(_mm_castps_si128(yy4), _MM_SHUFFLE(2, 3, 2, 3))); + } + + { + int k = 64; + int k1 = 2; + int k2 = 2 * k1; + const __m128 wk2rv = _mm_load_ps(&rdft_wk2r[k2 + 0]); + const __m128 wk2iv = _mm_load_ps(&rdft_wk2i[k2 + 0]); + const __m128 wk1iv = _mm_load_ps(&rdft_wk1i[k2 + 0]); + const __m128 wk3rv = _mm_load_ps(&rdft_wk3r[k2 + 0]); + const __m128 wk3iv = _mm_load_ps(&rdft_wk3i[k2 + 0]); + wk1rv = _mm_load_ps(&rdft_wk1r[k2 + 0]); + for (j0 = k; j0 < l + k; j0 += 2) { + const __m128i a_00 = _mm_loadl_epi64((__m128i*)&a[j0 + 0]); + const __m128i a_08 = _mm_loadl_epi64((__m128i*)&a[j0 + 8]); + const __m128i a_32 = _mm_loadl_epi64((__m128i*)&a[j0 + 32]); + const __m128i a_40 = _mm_loadl_epi64((__m128i*)&a[j0 + 40]); + const __m128 a_00_32 = + _mm_shuffle_ps(_mm_castsi128_ps(a_00), _mm_castsi128_ps(a_32), + _MM_SHUFFLE(1, 0, 1, 0)); + const __m128 a_08_40 = + _mm_shuffle_ps(_mm_castsi128_ps(a_08), _mm_castsi128_ps(a_40), + _MM_SHUFFLE(1, 0, 1, 0)); + __m128 x0r0_0i0_0r1_x0i1 = _mm_add_ps(a_00_32, a_08_40); + const __m128 x1r0_1i0_1r1_x1i1 = _mm_sub_ps(a_00_32, a_08_40); + + const __m128i a_16 = _mm_loadl_epi64((__m128i*)&a[j0 + 16]); + const __m128i a_24 = _mm_loadl_epi64((__m128i*)&a[j0 + 24]); + const __m128i a_48 = _mm_loadl_epi64((__m128i*)&a[j0 + 48]); + const __m128i a_56 = _mm_loadl_epi64((__m128i*)&a[j0 + 56]); + const __m128 a_16_48 = + _mm_shuffle_ps(_mm_castsi128_ps(a_16), _mm_castsi128_ps(a_48), + _MM_SHUFFLE(1, 0, 1, 0)); + const __m128 a_24_56 = + _mm_shuffle_ps(_mm_castsi128_ps(a_24), _mm_castsi128_ps(a_56), + _MM_SHUFFLE(1, 0, 1, 0)); + const __m128 x2r0_2i0_2r1_x2i1 = _mm_add_ps(a_16_48, a_24_56); + const __m128 x3r0_3i0_3r1_x3i1 = _mm_sub_ps(a_16_48, a_24_56); + + const __m128 xx = _mm_add_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx1 = _mm_sub_ps(x0r0_0i0_0r1_x0i1, x2r0_2i0_2r1_x2i1); + const __m128 xx2 = _mm_mul_ps(xx1, wk2rv); + const __m128 xx3 = _mm_mul_ps( + wk2iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(xx1), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx4 = _mm_add_ps(xx2, xx3); + + const __m128 x3i0_3r0_3i1_x3r1 = _mm_castsi128_ps(_mm_shuffle_epi32( + _mm_castps_si128(x3r0_3i0_3r1_x3i1), _MM_SHUFFLE(2, 3, 0, 1))); + const __m128 x3_swapped = _mm_mul_ps(mm_swap_sign, x3i0_3r0_3i1_x3r1); + const __m128 x1_x3_add = _mm_add_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + const __m128 x1_x3_sub = _mm_sub_ps(x1r0_1i0_1r1_x1i1, x3_swapped); + + const __m128 xx10 = _mm_mul_ps(x1_x3_add, wk1rv); + const __m128 xx11 = _mm_mul_ps( + wk1iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_add), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx12 = _mm_add_ps(xx10, xx11); + + const __m128 xx20 = _mm_mul_ps(x1_x3_sub, wk3rv); + const __m128 xx21 = _mm_mul_ps( + wk3iv, _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(x1_x3_sub), + _MM_SHUFFLE(2, 3, 0, 1)))); + const __m128 xx22 = _mm_add_ps(xx20, xx21); + + _mm_storel_epi64((__m128i*)&a[j0 + 0], _mm_castps_si128(xx)); + _mm_storel_epi64( + (__m128i*)&a[j0 + 32], + _mm_shuffle_epi32(_mm_castps_si128(xx), _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 16], _mm_castps_si128(xx4)); + _mm_storel_epi64( + (__m128i*)&a[j0 + 48], + _mm_shuffle_epi32(_mm_castps_si128(xx4), _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 8], _mm_castps_si128(xx12)); + _mm_storel_epi64( + (__m128i*)&a[j0 + 40], + _mm_shuffle_epi32(_mm_castps_si128(xx12), _MM_SHUFFLE(3, 2, 3, 2))); + + _mm_storel_epi64((__m128i*)&a[j0 + 24], _mm_castps_si128(xx22)); + _mm_storel_epi64( + (__m128i*)&a[j0 + 56], + _mm_shuffle_epi32(_mm_castps_si128(xx22), _MM_SHUFFLE(3, 2, 3, 2))); + } + } +} + +void rftfsub_128_SSE2(float* a) { + const float* c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + static const ALIGN16_BEG float ALIGN16_END k_half[4] = {0.5f, 0.5f, 0.5f, + 0.5f}; + const __m128 mm_half = _mm_load_ps(k_half); + + // Vectorized code (four at once). + // Note: commented number are indexes for the first iteration of the loop. + for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { + // Load 'wk'. + const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4, + const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31, + const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31, + const __m128 wkr_ = + _mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28, + const __m128 wki_ = c_j1; // 1, 2, 3, 4, + // Load and shuffle 'a'. + const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5, + const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9, + const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123, + const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127, + const __m128 a_j2_p0 = _mm_shuffle_ps( + a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8, + const __m128 a_j2_p1 = _mm_shuffle_ps( + a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9, + const __m128 a_k2_p0 = _mm_shuffle_ps( + a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120, + const __m128 a_k2_p1 = _mm_shuffle_ps( + a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121, + // Calculate 'x'. + const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0); + // 2-126, 4-124, 6-122, 8-120, + const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1); + // 3-127, 5-125, 7-123, 9-121, + // Calculate product into 'y'. + // yr = wkr * xr - wki * xi; + // yi = wkr * xi + wki * xr; + const __m128 a_ = _mm_mul_ps(wkr_, xr_); + const __m128 b_ = _mm_mul_ps(wki_, xi_); + const __m128 c_ = _mm_mul_ps(wkr_, xi_); + const __m128 d_ = _mm_mul_ps(wki_, xr_); + const __m128 yr_ = _mm_sub_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120, + const __m128 yi_ = _mm_add_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121, + // Update 'a'. + // a[j2 + 0] -= yr; + // a[j2 + 1] -= yi; + // a[k2 + 0] += yr; + // a[k2 + 1] -= yi; + const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8, + const __m128 a_j2_p1n = _mm_sub_ps(a_j2_p1, yi_); // 3, 5, 7, 9, + const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120, + const __m128 a_k2_p1n = _mm_sub_ps(a_k2_p1, yi_); // 127, 125, 123, 121, + // Shuffle in right order and store. + const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n); + // 2, 3, 4, 5, + const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n); + // 6, 7, 8, 9, + const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n); + // 122, 123, 120, 121, + const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n); + // 126, 127, 124, 125, + const __m128 a_k2_0n = _mm_shuffle_ps( + a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123, + const __m128 a_k2_4n = _mm_shuffle_ps( + a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127, + _mm_storeu_ps(&a[0 + j2], a_j2_0n); + _mm_storeu_ps(&a[4 + j2], a_j2_4n); + _mm_storeu_ps(&a[122 - j2], a_k2_0n); + _mm_storeu_ps(&a[126 - j2], a_k2_4n); + } + // Scalar code for the remaining items. + for (; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j2 + 0] -= yr; + a[j2 + 1] -= yi; + a[k2 + 0] += yr; + a[k2 + 1] -= yi; + } +} + +void rftbsub_128_SSE2(float* a) { + const float* c = rdft_w + 32; + int j1, j2, k1, k2; + float wkr, wki, xr, xi, yr, yi; + + static const ALIGN16_BEG float ALIGN16_END k_half[4] = {0.5f, 0.5f, 0.5f, + 0.5f}; + const __m128 mm_half = _mm_load_ps(k_half); + + a[1] = -a[1]; + // Vectorized code (four at once). + // Note: commented number are indexes for the first iteration of the loop. + for (j1 = 1, j2 = 2; j2 + 7 < 64; j1 += 4, j2 += 8) { + // Load 'wk'. + const __m128 c_j1 = _mm_loadu_ps(&c[j1]); // 1, 2, 3, 4, + const __m128 c_k1 = _mm_loadu_ps(&c[29 - j1]); // 28, 29, 30, 31, + const __m128 wkrt = _mm_sub_ps(mm_half, c_k1); // 28, 29, 30, 31, + const __m128 wkr_ = + _mm_shuffle_ps(wkrt, wkrt, _MM_SHUFFLE(0, 1, 2, 3)); // 31, 30, 29, 28, + const __m128 wki_ = c_j1; // 1, 2, 3, 4, + // Load and shuffle 'a'. + const __m128 a_j2_0 = _mm_loadu_ps(&a[0 + j2]); // 2, 3, 4, 5, + const __m128 a_j2_4 = _mm_loadu_ps(&a[4 + j2]); // 6, 7, 8, 9, + const __m128 a_k2_0 = _mm_loadu_ps(&a[122 - j2]); // 120, 121, 122, 123, + const __m128 a_k2_4 = _mm_loadu_ps(&a[126 - j2]); // 124, 125, 126, 127, + const __m128 a_j2_p0 = _mm_shuffle_ps( + a_j2_0, a_j2_4, _MM_SHUFFLE(2, 0, 2, 0)); // 2, 4, 6, 8, + const __m128 a_j2_p1 = _mm_shuffle_ps( + a_j2_0, a_j2_4, _MM_SHUFFLE(3, 1, 3, 1)); // 3, 5, 7, 9, + const __m128 a_k2_p0 = _mm_shuffle_ps( + a_k2_4, a_k2_0, _MM_SHUFFLE(0, 2, 0, 2)); // 126, 124, 122, 120, + const __m128 a_k2_p1 = _mm_shuffle_ps( + a_k2_4, a_k2_0, _MM_SHUFFLE(1, 3, 1, 3)); // 127, 125, 123, 121, + // Calculate 'x'. + const __m128 xr_ = _mm_sub_ps(a_j2_p0, a_k2_p0); + // 2-126, 4-124, 6-122, 8-120, + const __m128 xi_ = _mm_add_ps(a_j2_p1, a_k2_p1); + // 3-127, 5-125, 7-123, 9-121, + // Calculate product into 'y'. + // yr = wkr * xr + wki * xi; + // yi = wkr * xi - wki * xr; + const __m128 a_ = _mm_mul_ps(wkr_, xr_); + const __m128 b_ = _mm_mul_ps(wki_, xi_); + const __m128 c_ = _mm_mul_ps(wkr_, xi_); + const __m128 d_ = _mm_mul_ps(wki_, xr_); + const __m128 yr_ = _mm_add_ps(a_, b_); // 2-126, 4-124, 6-122, 8-120, + const __m128 yi_ = _mm_sub_ps(c_, d_); // 3-127, 5-125, 7-123, 9-121, + // Update 'a'. + // a[j2 + 0] = a[j2 + 0] - yr; + // a[j2 + 1] = yi - a[j2 + 1]; + // a[k2 + 0] = yr + a[k2 + 0]; + // a[k2 + 1] = yi - a[k2 + 1]; + const __m128 a_j2_p0n = _mm_sub_ps(a_j2_p0, yr_); // 2, 4, 6, 8, + const __m128 a_j2_p1n = _mm_sub_ps(yi_, a_j2_p1); // 3, 5, 7, 9, + const __m128 a_k2_p0n = _mm_add_ps(a_k2_p0, yr_); // 126, 124, 122, 120, + const __m128 a_k2_p1n = _mm_sub_ps(yi_, a_k2_p1); // 127, 125, 123, 121, + // Shuffle in right order and store. + const __m128 a_j2_0n = _mm_unpacklo_ps(a_j2_p0n, a_j2_p1n); + // 2, 3, 4, 5, + const __m128 a_j2_4n = _mm_unpackhi_ps(a_j2_p0n, a_j2_p1n); + // 6, 7, 8, 9, + const __m128 a_k2_0nt = _mm_unpackhi_ps(a_k2_p0n, a_k2_p1n); + // 122, 123, 120, 121, + const __m128 a_k2_4nt = _mm_unpacklo_ps(a_k2_p0n, a_k2_p1n); + // 126, 127, 124, 125, + const __m128 a_k2_0n = _mm_shuffle_ps( + a_k2_0nt, a_k2_0nt, _MM_SHUFFLE(1, 0, 3, 2)); // 120, 121, 122, 123, + const __m128 a_k2_4n = _mm_shuffle_ps( + a_k2_4nt, a_k2_4nt, _MM_SHUFFLE(1, 0, 3, 2)); // 124, 125, 126, 127, + _mm_storeu_ps(&a[0 + j2], a_j2_0n); + _mm_storeu_ps(&a[4 + j2], a_j2_4n); + _mm_storeu_ps(&a[122 - j2], a_k2_0n); + _mm_storeu_ps(&a[126 - j2], a_k2_4n); + } + // Scalar code for the remaining items. + for (; j2 < 64; j1 += 1, j2 += 2) { + k2 = 128 - j2; + k1 = 32 - j1; + wkr = 0.5f - c[k1]; + wki = c[j1]; + xr = a[j2 + 0] - a[k2 + 0]; + xi = a[j2 + 1] + a[k2 + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j2 + 0] = a[j2 + 0] - yr; + a[j2 + 1] = yi - a[j2 + 1]; + a[k2 + 0] = yr + a[k2 + 0]; + a[k2 + 1] = yi - a[k2 + 1]; + } + a[65] = -a[65]; +} +#endif + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h new file mode 100644 index 0000000000..6db1dd9ae4 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_common.h @@ -0,0 +1,54 @@ +/* + * 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_UTILITY_OOURA_FFT_TABLES_COMMON_H_ +#define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_ + +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" + +namespace webrtc { + +// This tables used to be computed at run-time. For example, refer to: +// https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/utility/apm_rdft.c?r=6564 +// to see the initialization code. +// Constants shared by all paths (C, SSE2, NEON). +const float rdft_w[64] = { + 1.0000000000f, 0.0000000000f, 0.7071067691f, 0.7071067691f, 0.9238795638f, + 0.3826834559f, 0.3826834559f, 0.9238795638f, 0.9807852507f, 0.1950903237f, + 0.5555702448f, 0.8314695954f, 0.8314695954f, 0.5555702448f, 0.1950903237f, + 0.9807852507f, 0.9951847196f, 0.0980171412f, 0.6343933344f, 0.7730104327f, + 0.8819212914f, 0.4713967443f, 0.2902846634f, 0.9569403529f, 0.9569403529f, + 0.2902846634f, 0.4713967443f, 0.8819212914f, 0.7730104327f, 0.6343933344f, + 0.0980171412f, 0.9951847196f, 0.7071067691f, 0.4993977249f, 0.4975923598f, + 0.4945882559f, 0.4903926253f, 0.4850156307f, 0.4784701765f, 0.4707720280f, + 0.4619397819f, 0.4519946277f, 0.4409606457f, 0.4288643003f, 0.4157347977f, + 0.4016037583f, 0.3865052164f, 0.3704755902f, 0.3535533845f, 0.3357794881f, + 0.3171966672f, 0.2978496552f, 0.2777851224f, 0.2570513785f, 0.2356983721f, + 0.2137775421f, 0.1913417280f, 0.1684449315f, 0.1451423317f, 0.1214900985f, + 0.0975451618f, 0.0733652338f, 0.0490085706f, 0.0245338380f, +}; + +// Constants used by the C and MIPS paths. +const float rdft_wk3ri_first[16] = { + 1.000000000f, 0.000000000f, 0.382683456f, 0.923879564f, + 0.831469536f, 0.555570245f, -0.195090353f, 0.980785251f, + 0.956940353f, 0.290284693f, 0.098017156f, 0.995184720f, + 0.634393334f, 0.773010492f, -0.471396863f, 0.881921172f, +}; +const float rdft_wk3ri_second[16] = { + -0.707106769f, 0.707106769f, -0.923879564f, -0.382683456f, + -0.980785251f, 0.195090353f, -0.555570245f, -0.831469536f, + -0.881921172f, 0.471396863f, -0.773010492f, -0.634393334f, + -0.995184720f, -0.098017156f, -0.290284693f, -0.956940353f, +}; + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_COMMON_H_ diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h new file mode 100644 index 0000000000..a63d187018 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_tables_neon_sse2.h @@ -0,0 +1,98 @@ +/* + * 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_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_ +#define MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_ + +#include "common_audio/third_party/ooura/fft_size_128/ooura_fft.h" +#include "rtc_base/system/arch.h" + +#ifdef _MSC_VER /* visual c++ */ +#define ALIGN16_BEG __declspec(align(16)) +#define ALIGN16_END +#else /* gcc or icc */ +#define ALIGN16_BEG +#define ALIGN16_END __attribute__((aligned(16))) +#endif + +namespace webrtc { + +// These tables used to be computed at run-time. For example, refer to: +// https://code.google.com/p/webrtc/source/browse/trunk/webrtc/modules/audio_processing/utility/apm_rdft.c?r=6564 +// to see the initialization code. +#if defined(WEBRTC_ARCH_X86_FAMILY) || defined(WEBRTC_HAS_NEON) +// Constants used by SSE2 and NEON but initialized in the C path. +const ALIGN16_BEG float ALIGN16_END k_swap_sign[4] = {-1.f, 1.f, -1.f, 1.f}; + +ALIGN16_BEG const float ALIGN16_END rdft_wk1r[32] = { + 1.000000000f, 1.000000000f, 0.707106769f, 0.707106769f, 0.923879564f, + 0.923879564f, 0.382683456f, 0.382683456f, 0.980785251f, 0.980785251f, + 0.555570245f, 0.555570245f, 0.831469595f, 0.831469595f, 0.195090324f, + 0.195090324f, 0.995184720f, 0.995184720f, 0.634393334f, 0.634393334f, + 0.881921291f, 0.881921291f, 0.290284663f, 0.290284663f, 0.956940353f, + 0.956940353f, 0.471396744f, 0.471396744f, 0.773010433f, 0.773010433f, + 0.098017141f, 0.098017141f, +}; +ALIGN16_BEG const float ALIGN16_END rdft_wk2r[32] = { + 1.000000000f, 1.000000000f, -0.000000000f, -0.000000000f, 0.707106769f, + 0.707106769f, -0.707106769f, -0.707106769f, 0.923879564f, 0.923879564f, + -0.382683456f, -0.382683456f, 0.382683456f, 0.382683456f, -0.923879564f, + -0.923879564f, 0.980785251f, 0.980785251f, -0.195090324f, -0.195090324f, + 0.555570245f, 0.555570245f, -0.831469595f, -0.831469595f, 0.831469595f, + 0.831469595f, -0.555570245f, -0.555570245f, 0.195090324f, 0.195090324f, + -0.980785251f, -0.980785251f, +}; +ALIGN16_BEG const float ALIGN16_END rdft_wk3r[32] = { + 1.000000000f, 1.000000000f, -0.707106769f, -0.707106769f, 0.382683456f, + 0.382683456f, -0.923879564f, -0.923879564f, 0.831469536f, 0.831469536f, + -0.980785251f, -0.980785251f, -0.195090353f, -0.195090353f, -0.555570245f, + -0.555570245f, 0.956940353f, 0.956940353f, -0.881921172f, -0.881921172f, + 0.098017156f, 0.098017156f, -0.773010492f, -0.773010492f, 0.634393334f, + 0.634393334f, -0.995184720f, -0.995184720f, -0.471396863f, -0.471396863f, + -0.290284693f, -0.290284693f, +}; +ALIGN16_BEG const float ALIGN16_END rdft_wk1i[32] = { + -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f, -0.382683456f, + 0.382683456f, -0.923879564f, 0.923879564f, -0.195090324f, 0.195090324f, + -0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f, -0.980785251f, + 0.980785251f, -0.098017141f, 0.098017141f, -0.773010433f, 0.773010433f, + -0.471396744f, 0.471396744f, -0.956940353f, 0.956940353f, -0.290284663f, + 0.290284663f, -0.881921291f, 0.881921291f, -0.634393334f, 0.634393334f, + -0.995184720f, 0.995184720f, +}; +ALIGN16_BEG const float ALIGN16_END rdft_wk2i[32] = { + -0.000000000f, 0.000000000f, -1.000000000f, 1.000000000f, -0.707106769f, + 0.707106769f, -0.707106769f, 0.707106769f, -0.382683456f, 0.382683456f, + -0.923879564f, 0.923879564f, -0.923879564f, 0.923879564f, -0.382683456f, + 0.382683456f, -0.195090324f, 0.195090324f, -0.980785251f, 0.980785251f, + -0.831469595f, 0.831469595f, -0.555570245f, 0.555570245f, -0.555570245f, + 0.555570245f, -0.831469595f, 0.831469595f, -0.980785251f, 0.980785251f, + -0.195090324f, 0.195090324f, +}; +ALIGN16_BEG const float ALIGN16_END rdft_wk3i[32] = { + -0.000000000f, 0.000000000f, -0.707106769f, 0.707106769f, -0.923879564f, + 0.923879564f, 0.382683456f, -0.382683456f, -0.555570245f, 0.555570245f, + -0.195090353f, 0.195090353f, -0.980785251f, 0.980785251f, 0.831469536f, + -0.831469536f, -0.290284693f, 0.290284693f, -0.471396863f, 0.471396863f, + -0.995184720f, 0.995184720f, 0.634393334f, -0.634393334f, -0.773010492f, + 0.773010492f, 0.098017156f, -0.098017156f, -0.881921172f, 0.881921172f, + 0.956940353f, -0.956940353f, +}; +ALIGN16_BEG const float ALIGN16_END cftmdl_wk1r[4] = { + 0.707106769f, + 0.707106769f, + 0.707106769f, + -0.707106769f, +}; +#endif + +} // namespace webrtc + +#endif // MODULES_AUDIO_PROCESSING_UTILITY_OOURA_FFT_TABLES_NEON_SSE2_H_ diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128_gn/moz.build b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128_gn/moz.build new file mode 100644 index 0000000000..2f5623b610 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128_gn/moz.build @@ -0,0 +1,276 @@ +# 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/common_audio/third_party/ooura/fft_size_128/ooura_fft.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 + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc" + ] + +if CONFIG["CPU_ARCH"] == "arm": + + CXXFLAGS += [ + "-mfpu=neon" + ] + + DEFINES["WEBRTC_ARCH_ARM"] = True + DEFINES["WEBRTC_ARCH_ARM_V7"] = True + DEFINES["WEBRTC_HAS_NEON"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_neon.cc" + ] + +if CONFIG["CPU_ARCH"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_mips.cc" + ] + +if CONFIG["CPU_ARCH"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc" + ] + +if CONFIG["CPU_ARCH"] == "x86_64": + + DEFINES["WEBRTC_ENABLE_AVX2"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_128/ooura_fft_sse2.cc" + ] + +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", + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Android": + + CXXFLAGS += [ + "-msse2" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Darwin": + + CXXFLAGS += [ + "-msse2" + ] + +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", + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + CXXFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "OpenBSD": + + CXXFLAGS += [ + "-msse2" + ] + +Library("fft_size_128_gn") diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc new file mode 100644 index 0000000000..d2f7c1c41e --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256/fft4g.cc @@ -0,0 +1,866 @@ +/* + * http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html + * Copyright Takuya OOURA, 1996-2001 + * + * You may use, copy, modify and distribute this code for any purpose (include + * commercial use) and without fee. Please refer to this package when you modify + * this code. + * + * Changes: + * Trivial type modifications by the WebRTC authors. + */ + +/* +Fast Fourier/Cosine/Sine Transform + dimension :one + data length :power of 2 + decimation :frequency + radix :4, 2 + data :inplace + table :use +functions + cdft: Complex Discrete Fourier Transform + rdft: Real Discrete Fourier Transform + ddct: Discrete Cosine Transform + ddst: Discrete Sine Transform + dfct: Cosine Transform of RDFT (Real Symmetric DFT) + dfst: Sine Transform of RDFT (Real Anti-symmetric DFT) +function prototypes + void cdft(int, int, float *, int *, float *); + void rdft(size_t, int, float *, size_t *, float *); + void ddct(int, int, float *, int *, float *); + void ddst(int, int, float *, int *, float *); + void dfct(int, float *, float *, int *, float *); + void dfst(int, float *, float *, int *, float *); + + +-------- Complex DFT (Discrete Fourier Transform) -------- + [definition] + <case1> + X[k] = sum_j=0^n-1 x[j]*exp(2*pi*i*j*k/n), 0<=k<n + <case2> + X[k] = sum_j=0^n-1 x[j]*exp(-2*pi*i*j*k/n), 0<=k<n + (notes: sum_j=0^n-1 is a summation from j=0 to n-1) + [usage] + <case1> + ip[0] = 0; // first time only + cdft(2*n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + cdft(2*n, -1, a, ip, w); + [parameters] + 2*n :data length (int) + n >= 1, n = power of 2 + a[0...2*n-1] :input/output data (float *) + input data + a[2*j] = Re(x[j]), + a[2*j+1] = Im(x[j]), 0<=j<n + output data + a[2*k] = Re(X[k]), + a[2*k+1] = Im(X[k]), 0<=k<n + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n) + strictly, + length of ip >= + 2+(1<<(int)(log(n+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + cdft(2*n, -1, a, ip, w); + is + cdft(2*n, 1, a, ip, w); + for (j = 0; j <= 2 * n - 1; j++) { + a[j] *= 1.0 / n; + } + . + + +-------- Real DFT / Inverse of Real DFT -------- + [definition] + <case1> RDFT + R[k] = sum_j=0^n-1 a[j]*cos(2*pi*j*k/n), 0<=k<=n/2 + I[k] = sum_j=0^n-1 a[j]*sin(2*pi*j*k/n), 0<k<n/2 + <case2> IRDFT (excluding scale) + a[k] = (R[0] + R[n/2]*cos(pi*k))/2 + + sum_j=1^n/2-1 R[j]*cos(2*pi*j*k/n) + + sum_j=1^n/2-1 I[j]*sin(2*pi*j*k/n), 0<=k<n + [usage] + <case1> + ip[0] = 0; // first time only + rdft(n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + rdft(n, -1, a, ip, w); + [parameters] + n :data length (size_t) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + <case1> + output data + a[2*k] = R[k], 0<=k<n/2 + a[2*k+1] = I[k], 0<k<n/2 + a[1] = R[n/2] + <case2> + input data + a[2*j] = R[j], 0<=j<n/2 + a[2*j+1] = I[j], 0<j<n/2 + a[1] = R[n/2] + ip[0...*] :work area for bit reversal (size_t *) + length of ip >= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n/2-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + rdft(n, 1, a, ip, w); + is + rdft(n, -1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DCT (Discrete Cosine Transform) / Inverse of DCT -------- + [definition] + <case1> IDCT (excluding scale) + C[k] = sum_j=0^n-1 a[j]*cos(pi*j*(k+1/2)/n), 0<=k<n + <case2> DCT + C[k] = sum_j=0^n-1 a[j]*cos(pi*(j+1/2)*k/n), 0<=k<n + [usage] + <case1> + ip[0] = 0; // first time only + ddct(n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + ddct(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + output data + a[k] = C[k], 0<=k<n + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddct(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddct(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- DST (Discrete Sine Transform) / Inverse of DST -------- + [definition] + <case1> IDST (excluding scale) + S[k] = sum_j=1^n A[j]*sin(pi*j*(k+1/2)/n), 0<=k<n + <case2> DST + S[k] = sum_j=0^n-1 a[j]*sin(pi*(j+1/2)*k/n), 0<k<=n + [usage] + <case1> + ip[0] = 0; // first time only + ddst(n, 1, a, ip, w); + <case2> + ip[0] = 0; // first time only + ddst(n, -1, a, ip, w); + [parameters] + n :data length (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + <case1> + input data + a[j] = A[j], 0<j<n + a[0] = A[n] + output data + a[k] = S[k], 0<=k<n + <case2> + output data + a[k] = S[k], 0<k<n + a[0] = S[n] + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/2) + strictly, + length of ip >= + 2+(1<<(int)(log(n/2+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/4-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + ddst(n, -1, a, ip, w); + is + a[0] *= 0.5; + ddst(n, 1, a, ip, w); + for (j = 0; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Cosine Transform of RDFT (Real Symmetric DFT) -------- + [definition] + C[k] = sum_j=0^n a[j]*cos(pi*j*k/n), 0<=k<=n + [usage] + ip[0] = 0; // first time only + dfct(n, a, t, ip, w); + [parameters] + n :data length - 1 (int) + n >= 2, n = power of 2 + a[0...n] :input/output data (float *) + output data + a[k] = C[k], 0<=k<=n + t[0...n/2] :work area (float *) + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + is + a[0] *= 0.5; + a[n] *= 0.5; + dfct(n, a, t, ip, w); + for (j = 0; j <= n; j++) { + a[j] *= 2.0 / n; + } + . + + +-------- Sine Transform of RDFT (Real Anti-symmetric DFT) -------- + [definition] + S[k] = sum_j=1^n-1 a[j]*sin(pi*j*k/n), 0<k<n + [usage] + ip[0] = 0; // first time only + dfst(n, a, t, ip, w); + [parameters] + n :data length + 1 (int) + n >= 2, n = power of 2 + a[0...n-1] :input/output data (float *) + output data + a[k] = S[k], 0<k<n + (a[0] is used for work area) + t[0...n/2-1] :work area (float *) + ip[0...*] :work area for bit reversal (int *) + length of ip >= 2+sqrt(n/4) + strictly, + length of ip >= + 2+(1<<(int)(log(n/4+0.5)/log(2))/2). + ip[0],ip[1] are pointers of the cos/sin table. + w[0...n*5/8-1] :cos/sin table (float *) + w[],ip[] are initialized if ip[0] == 0. + [remark] + Inverse of + dfst(n, a, t, ip, w); + is + dfst(n, a, t, ip, w); + for (j = 1; j <= n - 1; j++) { + a[j] *= 2.0 / n; + } + . + + +Appendix : + The cos/sin table is recalculated when the larger table required. + w[] and ip[] are compatible with all routines. +*/ + +#include <math.h> +#include <stddef.h> + +#include "common_audio/third_party/ooura/fft_size_256/fft4g.h" + +namespace webrtc { + +namespace { + +void makewt(size_t nw, size_t* ip, float* w); +void makect(size_t nc, size_t* ip, float* c); +void bitrv2(size_t n, size_t* ip, float* a); +void cftfsub(size_t n, float* a, float* w); +void cftbsub(size_t n, float* a, float* w); +void cft1st(size_t n, float* a, float* w); +void cftmdl(size_t n, size_t l, float* a, float* w); +void rftfsub(size_t n, float* a, size_t nc, float* c); +void rftbsub(size_t n, float* a, size_t nc, float* c); + +/* -------- initializing routines -------- */ + +void makewt(size_t nw, size_t* ip, float* w) { + size_t j, nwh; + float delta, x, y; + + ip[0] = nw; + ip[1] = 1; + if (nw > 2) { + nwh = nw >> 1; + delta = atanf(1.0f) / nwh; + w[0] = 1; + w[1] = 0; + w[nwh] = (float)cos(delta * nwh); + w[nwh + 1] = w[nwh]; + if (nwh > 2) { + for (j = 2; j < nwh; j += 2) { + x = (float)cos(delta * j); + y = (float)sin(delta * j); + w[j] = x; + w[j + 1] = y; + w[nw - j] = y; + w[nw - j + 1] = x; + } + bitrv2(nw, ip + 2, w); + } + } +} + +void makect(size_t nc, size_t* ip, float* c) { + size_t j, nch; + float delta; + + ip[1] = nc; + if (nc > 1) { + nch = nc >> 1; + delta = atanf(1.0f) / nch; + c[0] = (float)cos(delta * nch); + c[nch] = 0.5f * c[0]; + for (j = 1; j < nch; j++) { + c[j] = 0.5f * (float)cos(delta * j); + c[nc - j] = 0.5f * (float)sin(delta * j); + } + } +} + +/* -------- child routines -------- */ + +void bitrv2(size_t n, size_t* ip, float* a) { + size_t j, j1, k, k1, l, m, m2; + float xr, xi, yr, yi; + + ip[0] = 0; + l = n; + m = 1; + while ((m << 3) < l) { + l >>= 1; + for (j = 0; j < m; j++) { + ip[m + j] = ip[j] + l; + } + m <<= 1; + } + m2 = 2 * m; + if ((m << 3) == l) { + for (k = 0; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 -= m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += 2 * m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + j1 = 2 * k + m2 + ip[k]; + k1 = j1 + m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } else { + for (k = 1; k < m; k++) { + for (j = 0; j < k; j++) { + j1 = 2 * j + ip[k]; + k1 = 2 * k + ip[j]; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + j1 += m2; + k1 += m2; + xr = a[j1]; + xi = a[j1 + 1]; + yr = a[k1]; + yi = a[k1 + 1]; + a[j1] = yr; + a[j1 + 1] = yi; + a[k1] = xr; + a[k1 + 1] = xi; + } + } + } +} + +void cftfsub(size_t n, float* a, float* w) { + size_t j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = a[j + 1] - a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] += a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + +void cftbsub(size_t n, float* a, float* w) { + size_t j, j1, j2, j3, l; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + l = 2; + if (n > 8) { + cft1st(n, a, w); + l = 8; + while ((l << 2) < n) { + cftmdl(n, l, a, w); + l <<= 2; + } + } + if ((l << 2) == n) { + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = -a[j + 1] - a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = -a[j + 1] + a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i - x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i + x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i - x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i + x3r; + } + } else { + for (j = 0; j < l; j += 2) { + j1 = j + l; + x0r = a[j] - a[j1]; + x0i = -a[j + 1] + a[j1 + 1]; + a[j] += a[j1]; + a[j + 1] = -a[j + 1] - a[j1 + 1]; + a[j1] = x0r; + a[j1 + 1] = x0i; + } + } +} + +void cft1st(size_t n, float* a, float* w) { + size_t j, k1, k2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + x0r = a[0] + a[2]; + x0i = a[1] + a[3]; + x1r = a[0] - a[2]; + x1i = a[1] - a[3]; + x2r = a[4] + a[6]; + x2i = a[5] + a[7]; + x3r = a[4] - a[6]; + x3i = a[5] - a[7]; + a[0] = x0r + x2r; + a[1] = x0i + x2i; + a[4] = x0r - x2r; + a[5] = x0i - x2i; + a[2] = x1r - x3i; + a[3] = x1i + x3r; + a[6] = x1r + x3i; + a[7] = x1i - x3r; + wk1r = w[2]; + x0r = a[8] + a[10]; + x0i = a[9] + a[11]; + x1r = a[8] - a[10]; + x1i = a[9] - a[11]; + x2r = a[12] + a[14]; + x2i = a[13] + a[15]; + x3r = a[12] - a[14]; + x3i = a[13] - a[15]; + a[8] = x0r + x2r; + a[9] = x0i + x2i; + a[12] = x2i - x0i; + a[13] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[10] = wk1r * (x0r - x0i); + a[11] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[14] = wk1r * (x0i - x0r); + a[15] = wk1r * (x0i + x0r); + k1 = 0; + for (j = 16; j < n; j += 16) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + x0r = a[j] + a[j + 2]; + x0i = a[j + 1] + a[j + 3]; + x1r = a[j] - a[j + 2]; + x1i = a[j + 1] - a[j + 3]; + x2r = a[j + 4] + a[j + 6]; + x2i = a[j + 5] + a[j + 7]; + x3r = a[j + 4] - a[j + 6]; + x3i = a[j + 5] - a[j + 7]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 4] = wk2r * x0r - wk2i * x0i; + a[j + 5] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 2] = wk1r * x0r - wk1i * x0i; + a[j + 3] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 6] = wk3r * x0r - wk3i * x0i; + a[j + 7] = wk3r * x0i + wk3i * x0r; + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + x0r = a[j + 8] + a[j + 10]; + x0i = a[j + 9] + a[j + 11]; + x1r = a[j + 8] - a[j + 10]; + x1i = a[j + 9] - a[j + 11]; + x2r = a[j + 12] + a[j + 14]; + x2i = a[j + 13] + a[j + 15]; + x3r = a[j + 12] - a[j + 14]; + x3i = a[j + 13] - a[j + 15]; + a[j + 8] = x0r + x2r; + a[j + 9] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j + 12] = -wk2i * x0r - wk2r * x0i; + a[j + 13] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j + 10] = wk1r * x0r - wk1i * x0i; + a[j + 11] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j + 14] = wk3r * x0r - wk3i * x0i; + a[j + 15] = wk3r * x0i + wk3i * x0r; + } +} + +void cftmdl(size_t n, size_t l, float* a, float* w) { + size_t j, j1, j2, j3, k, k1, k2, m, m2; + float wk1r, wk1i, wk2r, wk2i, wk3r, wk3i; + float x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i; + + m = l << 2; + for (j = 0; j < l; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x0r - x2r; + a[j2 + 1] = x0i - x2i; + a[j1] = x1r - x3i; + a[j1 + 1] = x1i + x3r; + a[j3] = x1r + x3i; + a[j3 + 1] = x1i - x3r; + } + wk1r = w[2]; + for (j = m; j < l + m; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + a[j2] = x2i - x0i; + a[j2 + 1] = x0r - x2r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * (x0r - x0i); + a[j1 + 1] = wk1r * (x0r + x0i); + x0r = x3i + x1r; + x0i = x3r - x1i; + a[j3] = wk1r * (x0i - x0r); + a[j3 + 1] = wk1r * (x0i + x0r); + } + k1 = 0; + m2 = 2 * m; + for (k = m2; k < n; k += m2) { + k1 += 2; + k2 = 2 * k1; + wk2r = w[k1]; + wk2i = w[k1 + 1]; + wk1r = w[k2]; + wk1i = w[k2 + 1]; + wk3r = wk1r - 2 * wk2i * wk1i; + wk3i = 2 * wk2i * wk1r - wk1i; + for (j = k; j < l + k; j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = wk2r * x0r - wk2i * x0i; + a[j2 + 1] = wk2r * x0i + wk2i * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + wk1r = w[k2 + 2]; + wk1i = w[k2 + 3]; + wk3r = wk1r - 2 * wk2r * wk1i; + wk3i = 2 * wk2r * wk1r - wk1i; + for (j = k + m; j < l + (k + m); j += 2) { + j1 = j + l; + j2 = j1 + l; + j3 = j2 + l; + x0r = a[j] + a[j1]; + x0i = a[j + 1] + a[j1 + 1]; + x1r = a[j] - a[j1]; + x1i = a[j + 1] - a[j1 + 1]; + x2r = a[j2] + a[j3]; + x2i = a[j2 + 1] + a[j3 + 1]; + x3r = a[j2] - a[j3]; + x3i = a[j2 + 1] - a[j3 + 1]; + a[j] = x0r + x2r; + a[j + 1] = x0i + x2i; + x0r -= x2r; + x0i -= x2i; + a[j2] = -wk2i * x0r - wk2r * x0i; + a[j2 + 1] = -wk2i * x0i + wk2r * x0r; + x0r = x1r - x3i; + x0i = x1i + x3r; + a[j1] = wk1r * x0r - wk1i * x0i; + a[j1 + 1] = wk1r * x0i + wk1i * x0r; + x0r = x1r + x3i; + x0i = x1i - x3r; + a[j3] = wk3r * x0r - wk3i * x0i; + a[j3 + 1] = wk3r * x0i + wk3i * x0r; + } + } +} + +void rftfsub(size_t n, float* a, size_t nc, float* c) { + size_t j, k, kk, ks, m; + float wkr, wki, xr, xi, yr, yi; + + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5f - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr - wki * xi; + yi = wkr * xi + wki * xr; + a[j] -= yr; + a[j + 1] -= yi; + a[k] += yr; + a[k + 1] -= yi; + } +} + +void rftbsub(size_t n, float* a, size_t nc, float* c) { + size_t j, k, kk, ks, m; + float wkr, wki, xr, xi, yr, yi; + + a[1] = -a[1]; + m = n >> 1; + ks = 2 * nc / m; + kk = 0; + for (j = 2; j < m; j += 2) { + k = n - j; + kk += ks; + wkr = 0.5f - c[nc - kk]; + wki = c[kk]; + xr = a[j] - a[k]; + xi = a[j + 1] + a[k + 1]; + yr = wkr * xr + wki * xi; + yi = wkr * xi - wki * xr; + a[j] -= yr; + a[j + 1] = yi - a[j + 1]; + a[k] += yr; + a[k + 1] = yi - a[k + 1]; + } + a[m + 1] = -a[m + 1]; +} + +} // namespace + +void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w) { + size_t nw, nc; + float xi; + + nw = ip[0]; + if (n > (nw << 2)) { + nw = n >> 2; + makewt(nw, ip, w); + } + nc = ip[1]; + if (n > (nc << 2)) { + nc = n >> 2; + makect(nc, ip, w + nw); + } + if (isgn >= 0) { + if (n > 4) { + bitrv2(n, ip + 2, a); + cftfsub(n, a, w); + rftfsub(n, a, nc, w + nw); + } else if (n == 4) { + cftfsub(n, a, w); + } + xi = a[0] - a[1]; + a[0] += a[1]; + a[1] = xi; + } else { + a[1] = 0.5f * (a[0] - a[1]); + a[0] -= a[1]; + if (n > 4) { + rftbsub(n, a, nc, w + nw); + bitrv2(n, ip + 2, a); + cftbsub(n, a, w); + } else if (n == 4) { + cftfsub(n, a, w); + } + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h new file mode 100644 index 0000000000..d41d2c65aa --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256/fft4g.h @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2018 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 COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_ +#define COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_ + +namespace webrtc { + +// Refer to fft4g.c for documentation. +void WebRtc_rdft(size_t n, int isgn, float* a, size_t* ip, float* w); + +} // namespace webrtc + +#endif // COMMON_AUDIO_THIRD_PARTY_OOURA_FFT_SIZE_256_FFT4G_H_ diff --git a/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256_gn/moz.build b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256_gn/moz.build new file mode 100644 index 0000000000..8639a7ae2e --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/ooura/fft_size_256_gn/moz.build @@ -0,0 +1,217 @@ +# 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/common_audio/third_party/ooura/fft_size_256/fft4g.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 + +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("fft_size_256_gn") diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn new file mode 100644 index 0000000000..e66ed2796e --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/BUILD.gn @@ -0,0 +1,24 @@ +# Copyright (c) 2018 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_library("spl_sqrt_floor") { + visibility = [ "../..:common_audio_c" ] + sources = [ "spl_sqrt_floor.h" ] + deps = [] + if (target_cpu == "arm") { + sources += [ "spl_sqrt_floor_arm.S" ] + + deps += [ "../../../rtc_base/system:asm_defines" ] + } else if (target_cpu == "mipsel") { + sources += [ "spl_sqrt_floor_mips.c" ] + } else { + sources += [ "spl_sqrt_floor.c" ] + } +} diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/LICENSE b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/LICENSE new file mode 100644 index 0000000000..fdf17a2041 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/LICENSE @@ -0,0 +1,27 @@ +/* + * Written by Wilco Dijkstra, 1996. The following email exchange establishes the + * license. + * + * From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com> + * Date: Fri, Jun 24, 2011 at 3:20 AM + * Subject: Re: sqrt routine + * To: Kevin Ma <kma@google.com> + * Hi Kevin, + * Thanks for asking. Those routines are public domain (originally posted to + * comp.sys.arm a long time ago), so you can use them freely for any purpose. + * Cheers, + * Wilco + * + * ----- Original Message ----- + * From: "Kevin Ma" <kma@google.com> + * To: <Wilco.Dijkstra@ntlworld.com> + * Sent: Thursday, June 23, 2011 11:44 PM + * Subject: Fwd: sqrt routine + * Hi Wilco, + * I saw your sqrt routine from several web sites, including + * http://www.finesse.demon.co.uk/steven/sqrt.html. + * Just wonder if there's any copyright information with your Successive + * approximation routines, or if I can freely use it for any purpose. + * Thanks. + * Kevin + */ diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/README.chromium b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/README.chromium new file mode 100644 index 0000000000..b226490e85 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/README.chromium @@ -0,0 +1,12 @@ +Name: sql sqrt floor +Short Name: sql_sqrt_floor +URL: http://www.pertinentdetail.org/sqrt +Version: 0 +Date: 2018-03-22 +License: Custom license +License File: LICENSE +Security Critical: yes + +Description: +Sqrt routine, originally was posted to the USENET group comp.sys.arm on +20 Jun 1996. diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c new file mode 100644 index 0000000000..b478a41b96 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c @@ -0,0 +1,77 @@ +/* + * Written by Wilco Dijkstra, 1996. The following email exchange establishes the + * license. + * + * From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com> + * Date: Fri, Jun 24, 2011 at 3:20 AM + * Subject: Re: sqrt routine + * To: Kevin Ma <kma@google.com> + * Hi Kevin, + * Thanks for asking. Those routines are public domain (originally posted to + * comp.sys.arm a long time ago), so you can use them freely for any purpose. + * Cheers, + * Wilco + * + * ----- Original Message ----- + * From: "Kevin Ma" <kma@google.com> + * To: <Wilco.Dijkstra@ntlworld.com> + * Sent: Thursday, June 23, 2011 11:44 PM + * Subject: Fwd: sqrt routine + * Hi Wilco, + * I saw your sqrt routine from several web sites, including + * http://www.finesse.demon.co.uk/steven/sqrt.html. + * Just wonder if there's any copyright information with your Successive + * approximation routines, or if I can freely use it for any purpose. + * Thanks. + * Kevin + */ + +// Minor modifications in code style for WebRTC, 2012. + +#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" + +/* + * Algorithm: + * Successive approximation of the equation (root + delta) ^ 2 = N + * until delta < 1. If delta < 1 we have the integer part of SQRT (N). + * Use delta = 2^i for i = 15 .. 0. + * + * Output precision is 16 bits. Note for large input values (close to + * 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word) + * contains the MSB information (a non-sign value). Do with caution + * if you need to cast the output to int16_t type. + * + * If the input value is negative, it returns 0. + */ + +#define WEBRTC_SPL_SQRT_ITER(N) \ + try1 = root + (1 << (N)); \ + if (value >= try1 << (N)) \ + { \ + value -= try1 << (N); \ + root |= 2 << (N); \ + } + +int32_t WebRtcSpl_SqrtFloor(int32_t value) +{ + int32_t root = 0, try1; + + WEBRTC_SPL_SQRT_ITER (15); + WEBRTC_SPL_SQRT_ITER (14); + WEBRTC_SPL_SQRT_ITER (13); + WEBRTC_SPL_SQRT_ITER (12); + WEBRTC_SPL_SQRT_ITER (11); + WEBRTC_SPL_SQRT_ITER (10); + WEBRTC_SPL_SQRT_ITER ( 9); + WEBRTC_SPL_SQRT_ITER ( 8); + WEBRTC_SPL_SQRT_ITER ( 7); + WEBRTC_SPL_SQRT_ITER ( 6); + WEBRTC_SPL_SQRT_ITER ( 5); + WEBRTC_SPL_SQRT_ITER ( 4); + WEBRTC_SPL_SQRT_ITER ( 3); + WEBRTC_SPL_SQRT_ITER ( 2); + WEBRTC_SPL_SQRT_ITER ( 1); + WEBRTC_SPL_SQRT_ITER ( 0); + + return root >> 1; +} diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h new file mode 100644 index 0000000000..718a18ff7d --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2018 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 <stdint.h> + +// +// WebRtcSpl_SqrtFloor(...) +// +// Returns the square root of the input value `value`. The precision of this +// function is rounding down integer precision, i.e., sqrt(8) gives 2 as answer. +// If `value` is a negative number then 0 is returned. +// +// Algorithm: +// +// An iterative 4 cylce/bit routine +// +// Input: +// - value : Value to calculate sqrt of +// +// Return value : Result of the sqrt calculation +// +int32_t WebRtcSpl_SqrtFloor(int32_t value); diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S new file mode 100644 index 0000000000..228e68e6ca --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S @@ -0,0 +1,110 @@ +@ +@ Written by Wilco Dijkstra, 1996. The following email exchange establishes the +@ license. +@ +@ From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com> +@ Date: Fri, Jun 24, 2011 at 3:20 AM +@ Subject: Re: sqrt routine +@ To: Kevin Ma <kma@google.com> +@ Hi Kevin, +@ Thanks for asking. Those routines are public domain (originally posted to +@ comp.sys.arm a long time ago), so you can use them freely for any purpose. +@ Cheers, +@ Wilco +@ +@ ----- Original Message ----- +@ From: "Kevin Ma" <kma@google.com> +@ To: <Wilco.Dijkstra@ntlworld.com> +@ Sent: Thursday, June 23, 2011 11:44 PM +@ Subject: Fwd: sqrt routine +@ Hi Wilco, +@ I saw your sqrt routine from several web sites, including +@ http://www.finesse.demon.co.uk/steven/sqrt.html. +@ Just wonder if there's any copyright information with your Successive +@ approximation routines, or if I can freely use it for any purpose. +@ Thanks. +@ Kevin + +@ Minor modifications in code style for WebRTC, 2012. +@ Output is bit-exact with the reference C code in spl_sqrt_floor.c. + +@ Input : r0 32 bit unsigned integer +@ Output: r0 = INT (SQRT (r0)), precision is 16 bits +@ Registers touched: r1, r2 + +#include "rtc_base/system/asm_defines.h" + +GLOBAL_FUNCTION WebRtcSpl_SqrtFloor +.align 2 +DEFINE_FUNCTION WebRtcSpl_SqrtFloor + mov r1, #3 << 30 + mov r2, #1 << 30 + + @ unroll for i = 0 .. 15 + + cmp r0, r2, ror #2 * 0 + subhs r0, r0, r2, ror #2 * 0 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 1 + subhs r0, r0, r2, ror #2 * 1 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 2 + subhs r0, r0, r2, ror #2 * 2 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 3 + subhs r0, r0, r2, ror #2 * 3 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 4 + subhs r0, r0, r2, ror #2 * 4 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 5 + subhs r0, r0, r2, ror #2 * 5 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 6 + subhs r0, r0, r2, ror #2 * 6 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 7 + subhs r0, r0, r2, ror #2 * 7 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 8 + subhs r0, r0, r2, ror #2 * 8 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 9 + subhs r0, r0, r2, ror #2 * 9 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 10 + subhs r0, r0, r2, ror #2 * 10 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 11 + subhs r0, r0, r2, ror #2 * 11 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 12 + subhs r0, r0, r2, ror #2 * 12 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 13 + subhs r0, r0, r2, ror #2 * 13 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 14 + subhs r0, r0, r2, ror #2 * 14 + adc r2, r1, r2, lsl #1 + + cmp r0, r2, ror #2 * 15 + subhs r0, r0, r2, ror #2 * 15 + adc r2, r1, r2, lsl #1 + + bic r0, r2, #3 << 30 @ for rounding add: cmp r0, r2 adc r2, #1 + bx lr diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_gn/moz.build b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_gn/moz.build new file mode 100644 index 0000000000..4bae7df227 --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_gn/moz.build @@ -0,0 +1,273 @@ +# 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 + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +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 + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +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 + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +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 + + SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_arm.S" + ] + +if CONFIG["CPU_ARCH"] == "mips32": + + DEFINES["MIPS32_LE"] = True + DEFINES["MIPS_FPU_LE"] = True + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c" + ] + +if CONFIG["CPU_ARCH"] == "mips64": + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +if CONFIG["CPU_ARCH"] == "ppc64": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +if CONFIG["CPU_ARCH"] == "riscv64": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +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"] == "aarch64" and CONFIG["OS_TARGET"] == "Android": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +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": + + CFLAGS += [ + "-msse2" + ] + + OS_LIBS += [ + "android_support" + ] + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Android": + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +if CONFIG["CPU_ARCH"] == "aarch64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +if CONFIG["CPU_ARCH"] == "arm" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + +if CONFIG["CPU_ARCH"] == "x86" and CONFIG["OS_TARGET"] == "Linux": + + CFLAGS += [ + "-msse2" + ] + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +if CONFIG["CPU_ARCH"] == "x86_64" and CONFIG["OS_TARGET"] == "Linux": + + DEFINES["_GNU_SOURCE"] = True + + UNIFIED_SOURCES += [ + "/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.c" + ] + +Library("spl_sqrt_floor_gn") diff --git a/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c new file mode 100644 index 0000000000..04033c14de --- /dev/null +++ b/third_party/libwebrtc/common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor_mips.c @@ -0,0 +1,207 @@ +/* + * Written by Wilco Dijkstra, 1996. The following email exchange establishes the + * license. + * + * From: Wilco Dijkstra <Wilco.Dijkstra@ntlworld.com> + * Date: Fri, Jun 24, 2011 at 3:20 AM + * Subject: Re: sqrt routine + * To: Kevin Ma <kma@google.com> + * Hi Kevin, + * Thanks for asking. Those routines are public domain (originally posted to + * comp.sys.arm a long time ago), so you can use them freely for any purpose. + * Cheers, + * Wilco + * + * ----- Original Message ----- + * From: "Kevin Ma" <kma@google.com> + * To: <Wilco.Dijkstra@ntlworld.com> + * Sent: Thursday, June 23, 2011 11:44 PM + * Subject: Fwd: sqrt routine + * Hi Wilco, + * I saw your sqrt routine from several web sites, including + * http://www.finesse.demon.co.uk/steven/sqrt.html. + * Just wonder if there's any copyright information with your Successive + * approximation routines, or if I can freely use it for any purpose. + * Thanks. + * Kevin + */ + +// Minor modifications in code style for WebRTC, 2012. +// Code optimizations for MIPS, 2013. + +#include "common_audio/third_party/spl_sqrt_floor/spl_sqrt_floor.h" + +/* + * Algorithm: + * Successive approximation of the equation (root + delta) ^ 2 = N + * until delta < 1. If delta < 1 we have the integer part of SQRT (N). + * Use delta = 2^i for i = 15 .. 0. + * + * Output precision is 16 bits. Note for large input values (close to + * 0x7FFFFFFF), bit 15 (the highest bit of the low 16-bit half word) + * contains the MSB information (a non-sign value). Do with caution + * if you need to cast the output to int16_t type. + * + * If the input value is negative, it returns 0. + */ + + +int32_t WebRtcSpl_SqrtFloor(int32_t value) +{ + int32_t root = 0, tmp1, tmp2, tmp3, tmp4; + + __asm __volatile( + ".set push \n\t" + ".set noreorder \n\t" + + "lui %[tmp1], 0x4000 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "sub %[tmp3], %[value], %[tmp1] \n\t" + "lui %[tmp1], 0x1 \n\t" + "or %[tmp4], %[root], %[tmp1] \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x4000 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 14 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x8000 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x2000 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 13 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x4000 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x1000 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 12 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x2000 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x800 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 11 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x1000 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x400 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 10 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x800 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x200 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 9 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x400 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x100 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 8 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x200 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x80 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 7 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x100 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x40 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 6 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x80 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x20 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 5 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x40 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x10 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 4 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x20 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x8 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 3 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x10 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x4 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 2 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x8 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x2 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "sll %[tmp1], 1 \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "subu %[tmp3], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x4 \n\t" + "movz %[value], %[tmp3], %[tmp2] \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + "addiu %[tmp1], $0, 0x1 \n\t" + "addu %[tmp1], %[tmp1], %[root] \n\t" + "slt %[tmp2], %[value], %[tmp1] \n\t" + "ori %[tmp4], %[root], 0x2 \n\t" + "movz %[root], %[tmp4], %[tmp2] \n\t" + + ".set pop \n\t" + + : [root] "+r" (root), [value] "+r" (value), + [tmp1] "=&r" (tmp1), [tmp2] "=&r" (tmp2), + [tmp3] "=&r" (tmp3), [tmp4] "=&r" (tmp4) + : + ); + + return root >> 1; +} + diff --git a/third_party/libwebrtc/common_audio/vad/include/vad.h b/third_party/libwebrtc/common_audio/vad/include/vad.h new file mode 100644 index 0000000000..b15275b166 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/include/vad.h @@ -0,0 +1,50 @@ +/* + * 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 COMMON_AUDIO_VAD_INCLUDE_VAD_H_ +#define COMMON_AUDIO_VAD_INCLUDE_VAD_H_ + +#include <memory> + +#include "common_audio/vad/include/webrtc_vad.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +class Vad { + public: + enum Aggressiveness { + kVadNormal = 0, + kVadLowBitrate = 1, + kVadAggressive = 2, + kVadVeryAggressive = 3 + }; + + enum Activity { kPassive = 0, kActive = 1, kError = -1 }; + + virtual ~Vad() = default; + + // Calculates a VAD decision for the given audio frame. Valid sample rates + // are 8000, 16000, and 32000 Hz; the number of samples must be such that the + // frame is 10, 20, or 30 ms long. + virtual Activity VoiceActivity(const int16_t* audio, + size_t num_samples, + int sample_rate_hz) = 0; + + // Resets VAD state. + virtual void Reset() = 0; +}; + +// Returns a Vad instance that's implemented on top of WebRtcVad. +std::unique_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness); + +} // namespace webrtc + +#endif // COMMON_AUDIO_VAD_INCLUDE_VAD_H_ diff --git a/third_party/libwebrtc/common_audio/vad/include/webrtc_vad.h b/third_party/libwebrtc/common_audio/vad/include/webrtc_vad.h new file mode 100644 index 0000000000..31e628f058 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/include/webrtc_vad.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * This header file includes the VAD API calls. Specific function calls are + * given below. + */ + +#ifndef COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT +#define COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ + +#include <stddef.h> +#include <stdint.h> + +typedef struct WebRtcVadInst VadInst; + +#ifdef __cplusplus +extern "C" { +#endif + +// Creates an instance to the VAD structure. +VadInst* WebRtcVad_Create(void); + +// Frees the dynamic memory of a specified VAD instance. +// +// - handle [i] : Pointer to VAD instance that should be freed. +void WebRtcVad_Free(VadInst* handle); + +// Initializes a VAD instance. +// +// - handle [i/o] : Instance that should be initialized. +// +// returns : 0 - (OK), +// -1 - (null pointer or Default mode could not be set). +int WebRtcVad_Init(VadInst* handle); + +// Sets the VAD operating mode. A more aggressive (higher mode) VAD is more +// restrictive in reporting speech. Put in other words the probability of being +// speech when the VAD returns 1 is increased with increasing mode. As a +// consequence also the missed detection rate goes up. +// +// - handle [i/o] : VAD instance. +// - mode [i] : Aggressiveness mode (0, 1, 2, or 3). +// +// returns : 0 - (OK), +// -1 - (null pointer, mode could not be set or the VAD instance +// has not been initialized). +int WebRtcVad_set_mode(VadInst* handle, int mode); + +// Calculates a VAD decision for the `audio_frame`. For valid sampling rates +// frame lengths, see the description of WebRtcVad_ValidRatesAndFrameLengths(). +// +// - handle [i/o] : VAD Instance. Needs to be initialized by +// WebRtcVad_Init() before call. +// - fs [i] : Sampling frequency (Hz): 8000, 16000, or 32000 +// - audio_frame [i] : Audio frame buffer. +// - frame_length [i] : Length of audio frame buffer in number of samples. +// +// returns : 1 - (Active Voice), +// 0 - (Non-active Voice), +// -1 - (Error) +int WebRtcVad_Process(VadInst* handle, + int fs, + const int16_t* audio_frame, + size_t frame_length); + +// Checks for valid combinations of `rate` and `frame_length`. We support 10, +// 20 and 30 ms frames and the rates 8000, 16000 and 32000 Hz. +// +// - rate [i] : Sampling frequency (Hz). +// - frame_length [i] : Speech frame buffer length in number of samples. +// +// returns : 0 - (valid combination), -1 - (invalid combination) +int WebRtcVad_ValidRateAndFrameLength(int rate, size_t frame_length); + +#ifdef __cplusplus +} +#endif + +#endif // COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT diff --git a/third_party/libwebrtc/common_audio/vad/mock/mock_vad.h b/third_party/libwebrtc/common_audio/vad/mock/mock_vad.h new file mode 100644 index 0000000000..5a554ce1f9 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/mock/mock_vad.h @@ -0,0 +1,33 @@ +/* + * 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 COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_ +#define COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_ + +#include "common_audio/vad/include/vad.h" +#include "test/gmock.h" + +namespace webrtc { + +class MockVad : public Vad { + public: + ~MockVad() override { Die(); } + MOCK_METHOD(void, Die, ()); + + MOCK_METHOD(enum Activity, + VoiceActivity, + (const int16_t* audio, size_t num_samples, int sample_rate_hz), + (override)); + MOCK_METHOD(void, Reset, (), (override)); +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_ diff --git a/third_party/libwebrtc/common_audio/vad/vad.cc b/third_party/libwebrtc/common_audio/vad/vad.cc new file mode 100644 index 0000000000..1647246590 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad.cc @@ -0,0 +1,66 @@ +/* + * 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 "common_audio/vad/include/vad.h" + +#include <memory> + +#include "common_audio/vad/include/webrtc_vad.h" +#include "rtc_base/checks.h" + +namespace webrtc { + +namespace { + +class VadImpl final : public Vad { + public: + explicit VadImpl(Aggressiveness aggressiveness) + : handle_(nullptr), aggressiveness_(aggressiveness) { + Reset(); + } + + ~VadImpl() override { WebRtcVad_Free(handle_); } + + Activity VoiceActivity(const int16_t* audio, + size_t num_samples, + int sample_rate_hz) override { + int ret = WebRtcVad_Process(handle_, sample_rate_hz, audio, num_samples); + switch (ret) { + case 0: + return kPassive; + case 1: + return kActive; + default: + RTC_DCHECK_NOTREACHED() << "WebRtcVad_Process returned an error."; + return kError; + } + } + + void Reset() override { + if (handle_) + WebRtcVad_Free(handle_); + handle_ = WebRtcVad_Create(); + RTC_CHECK(handle_); + RTC_CHECK_EQ(WebRtcVad_Init(handle_), 0); + RTC_CHECK_EQ(WebRtcVad_set_mode(handle_, aggressiveness_), 0); + } + + private: + VadInst* handle_; + Aggressiveness aggressiveness_; +}; + +} // namespace + +std::unique_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness) { + return std::unique_ptr<Vad>(new VadImpl(aggressiveness)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/vad/vad_core.c b/third_party/libwebrtc/common_audio/vad/vad_core.c new file mode 100644 index 0000000000..0872449a7c --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_core.c @@ -0,0 +1,685 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/vad/vad_core.h" + +#include "rtc_base/sanitizer.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "common_audio/vad/vad_filterbank.h" +#include "common_audio/vad/vad_gmm.h" +#include "common_audio/vad/vad_sp.h" + +// Spectrum Weighting +static const int16_t kSpectrumWeight[kNumChannels] = { 6, 8, 10, 12, 14, 16 }; +static const int16_t kNoiseUpdateConst = 655; // Q15 +static const int16_t kSpeechUpdateConst = 6554; // Q15 +static const int16_t kBackEta = 154; // Q8 +// Minimum difference between the two models, Q5 +static const int16_t kMinimumDifference[kNumChannels] = { + 544, 544, 576, 576, 576, 576 }; +// Upper limit of mean value for speech model, Q7 +static const int16_t kMaximumSpeech[kNumChannels] = { + 11392, 11392, 11520, 11520, 11520, 11520 }; +// Minimum value for mean value +static const int16_t kMinimumMean[kNumGaussians] = { 640, 768 }; +// Upper limit of mean value for noise model, Q7 +static const int16_t kMaximumNoise[kNumChannels] = { + 9216, 9088, 8960, 8832, 8704, 8576 }; +// Start values for the Gaussian models, Q7 +// Weights for the two Gaussians for the six channels (noise) +static const int16_t kNoiseDataWeights[kTableSize] = { + 34, 62, 72, 66, 53, 25, 94, 66, 56, 62, 75, 103 }; +// Weights for the two Gaussians for the six channels (speech) +static const int16_t kSpeechDataWeights[kTableSize] = { + 48, 82, 45, 87, 50, 47, 80, 46, 83, 41, 78, 81 }; +// Means for the two Gaussians for the six channels (noise) +static const int16_t kNoiseDataMeans[kTableSize] = { + 6738, 4892, 7065, 6715, 6771, 3369, 7646, 3863, 7820, 7266, 5020, 4362 }; +// Means for the two Gaussians for the six channels (speech) +static const int16_t kSpeechDataMeans[kTableSize] = { + 8306, 10085, 10078, 11823, 11843, 6309, 9473, 9571, 10879, 7581, 8180, 7483 +}; +// Stds for the two Gaussians for the six channels (noise) +static const int16_t kNoiseDataStds[kTableSize] = { + 378, 1064, 493, 582, 688, 593, 474, 697, 475, 688, 421, 455 }; +// Stds for the two Gaussians for the six channels (speech) +static const int16_t kSpeechDataStds[kTableSize] = { + 555, 505, 567, 524, 585, 1231, 509, 828, 492, 1540, 1079, 850 }; + +// Constants used in GmmProbability(). +// +// Maximum number of counted speech (VAD = 1) frames in a row. +static const int16_t kMaxSpeechFrames = 6; +// Minimum standard deviation for both speech and noise. +static const int16_t kMinStd = 384; + +// Constants in WebRtcVad_InitCore(). +// Default aggressiveness mode. +static const short kDefaultMode = 0; +static const int kInitCheck = 42; + +// Constants used in WebRtcVad_set_mode_core(). +// +// Thresholds for different frame lengths (10 ms, 20 ms and 30 ms). +// +// Mode 0, Quality. +static const int16_t kOverHangMax1Q[3] = { 8, 4, 3 }; +static const int16_t kOverHangMax2Q[3] = { 14, 7, 5 }; +static const int16_t kLocalThresholdQ[3] = { 24, 21, 24 }; +static const int16_t kGlobalThresholdQ[3] = { 57, 48, 57 }; +// Mode 1, Low bitrate. +static const int16_t kOverHangMax1LBR[3] = { 8, 4, 3 }; +static const int16_t kOverHangMax2LBR[3] = { 14, 7, 5 }; +static const int16_t kLocalThresholdLBR[3] = { 37, 32, 37 }; +static const int16_t kGlobalThresholdLBR[3] = { 100, 80, 100 }; +// Mode 2, Aggressive. +static const int16_t kOverHangMax1AGG[3] = { 6, 3, 2 }; +static const int16_t kOverHangMax2AGG[3] = { 9, 5, 3 }; +static const int16_t kLocalThresholdAGG[3] = { 82, 78, 82 }; +static const int16_t kGlobalThresholdAGG[3] = { 285, 260, 285 }; +// Mode 3, Very aggressive. +static const int16_t kOverHangMax1VAG[3] = { 6, 3, 2 }; +static const int16_t kOverHangMax2VAG[3] = { 9, 5, 3 }; +static const int16_t kLocalThresholdVAG[3] = { 94, 94, 94 }; +static const int16_t kGlobalThresholdVAG[3] = { 1100, 1050, 1100 }; + +// Calculates the weighted average w.r.t. number of Gaussians. The `data` are +// updated with an `offset` before averaging. +// +// - data [i/o] : Data to average. +// - offset [i] : An offset added to `data`. +// - weights [i] : Weights used for averaging. +// +// returns : The weighted average. +static int32_t WeightedAverage(int16_t* data, int16_t offset, + const int16_t* weights) { + int k; + int32_t weighted_average = 0; + + for (k = 0; k < kNumGaussians; k++) { + data[k * kNumChannels] += offset; + weighted_average += data[k * kNumChannels] * weights[k * kNumChannels]; + } + return weighted_average; +} + +// An s16 x s32 -> s32 multiplication that's allowed to overflow. (It's still +// undefined behavior, so not a good idea; this just makes UBSan ignore the +// violation, so that our old code can continue to do what it's always been +// doing.) +static inline int32_t RTC_NO_SANITIZE("signed-integer-overflow") + OverflowingMulS16ByS32ToS32(int16_t a, int32_t b) { + return a * b; +} + +// Calculates the probabilities for both speech and background noise using +// Gaussian Mixture Models (GMM). A hypothesis-test is performed to decide which +// type of signal is most probable. +// +// - self [i/o] : Pointer to VAD instance +// - features [i] : Feature vector of length `kNumChannels` +// = log10(energy in frequency band) +// - total_power [i] : Total power in audio frame. +// - frame_length [i] : Number of input samples +// +// - returns : the VAD decision (0 - noise, 1 - speech). +static int16_t GmmProbability(VadInstT* self, int16_t* features, + int16_t total_power, size_t frame_length) { + int channel, k; + int16_t feature_minimum; + int16_t h0, h1; + int16_t log_likelihood_ratio; + int16_t vadflag = 0; + int16_t shifts_h0, shifts_h1; + int16_t tmp_s16, tmp1_s16, tmp2_s16; + int16_t diff; + int gaussian; + int16_t nmk, nmk2, nmk3, smk, smk2, nsk, ssk; + int16_t delt, ndelt; + int16_t maxspe, maxmu; + int16_t deltaN[kTableSize], deltaS[kTableSize]; + int16_t ngprvec[kTableSize] = { 0 }; // Conditional probability = 0. + int16_t sgprvec[kTableSize] = { 0 }; // Conditional probability = 0. + int32_t h0_test, h1_test; + int32_t tmp1_s32, tmp2_s32; + int32_t sum_log_likelihood_ratios = 0; + int32_t noise_global_mean, speech_global_mean; + int32_t noise_probability[kNumGaussians], speech_probability[kNumGaussians]; + int16_t overhead1, overhead2, individualTest, totalTest; + + // Set various thresholds based on frame lengths (80, 160 or 240 samples). + if (frame_length == 80) { + overhead1 = self->over_hang_max_1[0]; + overhead2 = self->over_hang_max_2[0]; + individualTest = self->individual[0]; + totalTest = self->total[0]; + } else if (frame_length == 160) { + overhead1 = self->over_hang_max_1[1]; + overhead2 = self->over_hang_max_2[1]; + individualTest = self->individual[1]; + totalTest = self->total[1]; + } else { + overhead1 = self->over_hang_max_1[2]; + overhead2 = self->over_hang_max_2[2]; + individualTest = self->individual[2]; + totalTest = self->total[2]; + } + + if (total_power > kMinEnergy) { + // The signal power of current frame is large enough for processing. The + // processing consists of two parts: + // 1) Calculating the likelihood of speech and thereby a VAD decision. + // 2) Updating the underlying model, w.r.t., the decision made. + + // The detection scheme is an LRT with hypothesis + // H0: Noise + // H1: Speech + // + // We combine a global LRT with local tests, for each frequency sub-band, + // here defined as `channel`. + for (channel = 0; channel < kNumChannels; channel++) { + // For each channel we model the probability with a GMM consisting of + // `kNumGaussians`, with different means and standard deviations depending + // on H0 or H1. + h0_test = 0; + h1_test = 0; + for (k = 0; k < kNumGaussians; k++) { + gaussian = channel + k * kNumChannels; + // Probability under H0, that is, probability of frame being noise. + // Value given in Q27 = Q7 * Q20. + tmp1_s32 = WebRtcVad_GaussianProbability(features[channel], + self->noise_means[gaussian], + self->noise_stds[gaussian], + &deltaN[gaussian]); + noise_probability[k] = kNoiseDataWeights[gaussian] * tmp1_s32; + h0_test += noise_probability[k]; // Q27 + + // Probability under H1, that is, probability of frame being speech. + // Value given in Q27 = Q7 * Q20. + tmp1_s32 = WebRtcVad_GaussianProbability(features[channel], + self->speech_means[gaussian], + self->speech_stds[gaussian], + &deltaS[gaussian]); + speech_probability[k] = kSpeechDataWeights[gaussian] * tmp1_s32; + h1_test += speech_probability[k]; // Q27 + } + + // Calculate the log likelihood ratio: log2(Pr{X|H1} / Pr{X|H1}). + // Approximation: + // log2(Pr{X|H1} / Pr{X|H1}) = log2(Pr{X|H1}*2^Q) - log2(Pr{X|H1}*2^Q) + // = log2(h1_test) - log2(h0_test) + // = log2(2^(31-shifts_h1)*(1+b1)) + // - log2(2^(31-shifts_h0)*(1+b0)) + // = shifts_h0 - shifts_h1 + // + log2(1+b1) - log2(1+b0) + // ~= shifts_h0 - shifts_h1 + // + // Note that b0 and b1 are values less than 1, hence, 0 <= log2(1+b0) < 1. + // Further, b0 and b1 are independent and on the average the two terms + // cancel. + shifts_h0 = WebRtcSpl_NormW32(h0_test); + shifts_h1 = WebRtcSpl_NormW32(h1_test); + if (h0_test == 0) { + shifts_h0 = 31; + } + if (h1_test == 0) { + shifts_h1 = 31; + } + log_likelihood_ratio = shifts_h0 - shifts_h1; + + // Update `sum_log_likelihood_ratios` with spectrum weighting. This is + // used for the global VAD decision. + sum_log_likelihood_ratios += + (int32_t) (log_likelihood_ratio * kSpectrumWeight[channel]); + + // Local VAD decision. + if ((log_likelihood_ratio * 4) > individualTest) { + vadflag = 1; + } + + // TODO(bjornv): The conditional probabilities below are applied on the + // hard coded number of Gaussians set to two. Find a way to generalize. + // Calculate local noise probabilities used later when updating the GMM. + h0 = (int16_t) (h0_test >> 12); // Q15 + if (h0 > 0) { + // High probability of noise. Assign conditional probabilities for each + // Gaussian in the GMM. + tmp1_s32 = (noise_probability[0] & 0xFFFFF000) << 2; // Q29 + ngprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h0); // Q14 + ngprvec[channel + kNumChannels] = 16384 - ngprvec[channel]; + } else { + // Low noise probability. Assign conditional probability 1 to the first + // Gaussian and 0 to the rest (which is already set at initialization). + ngprvec[channel] = 16384; + } + + // Calculate local speech probabilities used later when updating the GMM. + h1 = (int16_t) (h1_test >> 12); // Q15 + if (h1 > 0) { + // High probability of speech. Assign conditional probabilities for each + // Gaussian in the GMM. Otherwise use the initialized values, i.e., 0. + tmp1_s32 = (speech_probability[0] & 0xFFFFF000) << 2; // Q29 + sgprvec[channel] = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, h1); // Q14 + sgprvec[channel + kNumChannels] = 16384 - sgprvec[channel]; + } + } + + // Make a global VAD decision. + vadflag |= (sum_log_likelihood_ratios >= totalTest); + + // Update the model parameters. + maxspe = 12800; + for (channel = 0; channel < kNumChannels; channel++) { + + // Get minimum value in past which is used for long term correction in Q4. + feature_minimum = WebRtcVad_FindMinimum(self, features[channel], channel); + + // Compute the "global" mean, that is the sum of the two means weighted. + noise_global_mean = WeightedAverage(&self->noise_means[channel], 0, + &kNoiseDataWeights[channel]); + tmp1_s16 = (int16_t) (noise_global_mean >> 6); // Q8 + + for (k = 0; k < kNumGaussians; k++) { + gaussian = channel + k * kNumChannels; + + nmk = self->noise_means[gaussian]; + smk = self->speech_means[gaussian]; + nsk = self->noise_stds[gaussian]; + ssk = self->speech_stds[gaussian]; + + // Update noise mean vector if the frame consists of noise only. + nmk2 = nmk; + if (!vadflag) { + // deltaN = (x-mu)/sigma^2 + // ngprvec[k] = `noise_probability[k]` / + // (`noise_probability[0]` + `noise_probability[1]`) + + // (Q14 * Q11 >> 11) = Q14. + delt = (int16_t)((ngprvec[gaussian] * deltaN[gaussian]) >> 11); + // Q7 + (Q14 * Q15 >> 22) = Q7. + nmk2 = nmk + (int16_t)((delt * kNoiseUpdateConst) >> 22); + } + + // Long term correction of the noise mean. + // Q8 - Q8 = Q8. + ndelt = (feature_minimum << 4) - tmp1_s16; + // Q7 + (Q8 * Q8) >> 9 = Q7. + nmk3 = nmk2 + (int16_t)((ndelt * kBackEta) >> 9); + + // Control that the noise mean does not drift to much. + tmp_s16 = (int16_t) ((k + 5) << 7); + if (nmk3 < tmp_s16) { + nmk3 = tmp_s16; + } + tmp_s16 = (int16_t) ((72 + k - channel) << 7); + if (nmk3 > tmp_s16) { + nmk3 = tmp_s16; + } + self->noise_means[gaussian] = nmk3; + + if (vadflag) { + // Update speech mean vector: + // `deltaS` = (x-mu)/sigma^2 + // sgprvec[k] = `speech_probability[k]` / + // (`speech_probability[0]` + `speech_probability[1]`) + + // (Q14 * Q11) >> 11 = Q14. + delt = (int16_t)((sgprvec[gaussian] * deltaS[gaussian]) >> 11); + // Q14 * Q15 >> 21 = Q8. + tmp_s16 = (int16_t)((delt * kSpeechUpdateConst) >> 21); + // Q7 + (Q8 >> 1) = Q7. With rounding. + smk2 = smk + ((tmp_s16 + 1) >> 1); + + // Control that the speech mean does not drift to much. + maxmu = maxspe + 640; + if (smk2 < kMinimumMean[k]) { + smk2 = kMinimumMean[k]; + } + if (smk2 > maxmu) { + smk2 = maxmu; + } + self->speech_means[gaussian] = smk2; // Q7. + + // (Q7 >> 3) = Q4. With rounding. + tmp_s16 = ((smk + 4) >> 3); + + tmp_s16 = features[channel] - tmp_s16; // Q4 + // (Q11 * Q4 >> 3) = Q12. + tmp1_s32 = (deltaS[gaussian] * tmp_s16) >> 3; + tmp2_s32 = tmp1_s32 - 4096; + tmp_s16 = sgprvec[gaussian] >> 2; + // (Q14 >> 2) * Q12 = Q24. + tmp1_s32 = tmp_s16 * tmp2_s32; + + tmp2_s32 = tmp1_s32 >> 4; // Q20 + + // 0.1 * Q20 / Q7 = Q13. + if (tmp2_s32 > 0) { + tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp2_s32, ssk * 10); + } else { + tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp2_s32, ssk * 10); + tmp_s16 = -tmp_s16; + } + // Divide by 4 giving an update factor of 0.025 (= 0.1 / 4). + // Note that division by 4 equals shift by 2, hence, + // (Q13 >> 8) = (Q13 >> 6) / 4 = Q7. + tmp_s16 += 128; // Rounding. + ssk += (tmp_s16 >> 8); + if (ssk < kMinStd) { + ssk = kMinStd; + } + self->speech_stds[gaussian] = ssk; + } else { + // Update GMM variance vectors. + // deltaN * (features[channel] - nmk) - 1 + // Q4 - (Q7 >> 3) = Q4. + tmp_s16 = features[channel] - (nmk >> 3); + // (Q11 * Q4 >> 3) = Q12. + tmp1_s32 = (deltaN[gaussian] * tmp_s16) >> 3; + tmp1_s32 -= 4096; + + // (Q14 >> 2) * Q12 = Q24. + tmp_s16 = (ngprvec[gaussian] + 2) >> 2; + tmp2_s32 = OverflowingMulS16ByS32ToS32(tmp_s16, tmp1_s32); + // Q20 * approx 0.001 (2^-10=0.0009766), hence, + // (Q24 >> 14) = (Q24 >> 4) / 2^10 = Q20. + tmp1_s32 = tmp2_s32 >> 14; + + // Q20 / Q7 = Q13. + if (tmp1_s32 > 0) { + tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(tmp1_s32, nsk); + } else { + tmp_s16 = (int16_t) WebRtcSpl_DivW32W16(-tmp1_s32, nsk); + tmp_s16 = -tmp_s16; + } + tmp_s16 += 32; // Rounding + nsk += tmp_s16 >> 6; // Q13 >> 6 = Q7. + if (nsk < kMinStd) { + nsk = kMinStd; + } + self->noise_stds[gaussian] = nsk; + } + } + + // Separate models if they are too close. + // `noise_global_mean` in Q14 (= Q7 * Q7). + noise_global_mean = WeightedAverage(&self->noise_means[channel], 0, + &kNoiseDataWeights[channel]); + + // `speech_global_mean` in Q14 (= Q7 * Q7). + speech_global_mean = WeightedAverage(&self->speech_means[channel], 0, + &kSpeechDataWeights[channel]); + + // `diff` = "global" speech mean - "global" noise mean. + // (Q14 >> 9) - (Q14 >> 9) = Q5. + diff = (int16_t) (speech_global_mean >> 9) - + (int16_t) (noise_global_mean >> 9); + if (diff < kMinimumDifference[channel]) { + tmp_s16 = kMinimumDifference[channel] - diff; + + // `tmp1_s16` = ~0.8 * (kMinimumDifference - diff) in Q7. + // `tmp2_s16` = ~0.2 * (kMinimumDifference - diff) in Q7. + tmp1_s16 = (int16_t)((13 * tmp_s16) >> 2); + tmp2_s16 = (int16_t)((3 * tmp_s16) >> 2); + + // Move Gaussian means for speech model by `tmp1_s16` and update + // `speech_global_mean`. Note that `self->speech_means[channel]` is + // changed after the call. + speech_global_mean = WeightedAverage(&self->speech_means[channel], + tmp1_s16, + &kSpeechDataWeights[channel]); + + // Move Gaussian means for noise model by -`tmp2_s16` and update + // `noise_global_mean`. Note that `self->noise_means[channel]` is + // changed after the call. + noise_global_mean = WeightedAverage(&self->noise_means[channel], + -tmp2_s16, + &kNoiseDataWeights[channel]); + } + + // Control that the speech & noise means do not drift to much. + maxspe = kMaximumSpeech[channel]; + tmp2_s16 = (int16_t) (speech_global_mean >> 7); + if (tmp2_s16 > maxspe) { + // Upper limit of speech model. + tmp2_s16 -= maxspe; + + for (k = 0; k < kNumGaussians; k++) { + self->speech_means[channel + k * kNumChannels] -= tmp2_s16; + } + } + + tmp2_s16 = (int16_t) (noise_global_mean >> 7); + if (tmp2_s16 > kMaximumNoise[channel]) { + tmp2_s16 -= kMaximumNoise[channel]; + + for (k = 0; k < kNumGaussians; k++) { + self->noise_means[channel + k * kNumChannels] -= tmp2_s16; + } + } + } + self->frame_counter++; + } + + // Smooth with respect to transition hysteresis. + if (!vadflag) { + if (self->over_hang > 0) { + vadflag = 2 + self->over_hang; + self->over_hang--; + } + self->num_of_speech = 0; + } else { + self->num_of_speech++; + if (self->num_of_speech > kMaxSpeechFrames) { + self->num_of_speech = kMaxSpeechFrames; + self->over_hang = overhead2; + } else { + self->over_hang = overhead1; + } + } + return vadflag; +} + +// Initialize the VAD. Set aggressiveness mode to default value. +int WebRtcVad_InitCore(VadInstT* self) { + int i; + + if (self == NULL) { + return -1; + } + + // Initialization of general struct variables. + self->vad = 1; // Speech active (=1). + self->frame_counter = 0; + self->over_hang = 0; + self->num_of_speech = 0; + + // Initialization of downsampling filter state. + memset(self->downsampling_filter_states, 0, + sizeof(self->downsampling_filter_states)); + + // Initialization of 48 to 8 kHz downsampling. + WebRtcSpl_ResetResample48khzTo8khz(&self->state_48_to_8); + + // Read initial PDF parameters. + for (i = 0; i < kTableSize; i++) { + self->noise_means[i] = kNoiseDataMeans[i]; + self->speech_means[i] = kSpeechDataMeans[i]; + self->noise_stds[i] = kNoiseDataStds[i]; + self->speech_stds[i] = kSpeechDataStds[i]; + } + + // Initialize Index and Minimum value vectors. + for (i = 0; i < 16 * kNumChannels; i++) { + self->low_value_vector[i] = 10000; + self->index_vector[i] = 0; + } + + // Initialize splitting filter states. + memset(self->upper_state, 0, sizeof(self->upper_state)); + memset(self->lower_state, 0, sizeof(self->lower_state)); + + // Initialize high pass filter states. + memset(self->hp_filter_state, 0, sizeof(self->hp_filter_state)); + + // Initialize mean value memory, for WebRtcVad_FindMinimum(). + for (i = 0; i < kNumChannels; i++) { + self->mean_value[i] = 1600; + } + + // Set aggressiveness mode to default (=`kDefaultMode`). + if (WebRtcVad_set_mode_core(self, kDefaultMode) != 0) { + return -1; + } + + self->init_flag = kInitCheck; + + return 0; +} + +// Set aggressiveness mode +int WebRtcVad_set_mode_core(VadInstT* self, int mode) { + int return_value = 0; + + switch (mode) { + case 0: + // Quality mode. + memcpy(self->over_hang_max_1, kOverHangMax1Q, + sizeof(self->over_hang_max_1)); + memcpy(self->over_hang_max_2, kOverHangMax2Q, + sizeof(self->over_hang_max_2)); + memcpy(self->individual, kLocalThresholdQ, + sizeof(self->individual)); + memcpy(self->total, kGlobalThresholdQ, + sizeof(self->total)); + break; + case 1: + // Low bitrate mode. + memcpy(self->over_hang_max_1, kOverHangMax1LBR, + sizeof(self->over_hang_max_1)); + memcpy(self->over_hang_max_2, kOverHangMax2LBR, + sizeof(self->over_hang_max_2)); + memcpy(self->individual, kLocalThresholdLBR, + sizeof(self->individual)); + memcpy(self->total, kGlobalThresholdLBR, + sizeof(self->total)); + break; + case 2: + // Aggressive mode. + memcpy(self->over_hang_max_1, kOverHangMax1AGG, + sizeof(self->over_hang_max_1)); + memcpy(self->over_hang_max_2, kOverHangMax2AGG, + sizeof(self->over_hang_max_2)); + memcpy(self->individual, kLocalThresholdAGG, + sizeof(self->individual)); + memcpy(self->total, kGlobalThresholdAGG, + sizeof(self->total)); + break; + case 3: + // Very aggressive mode. + memcpy(self->over_hang_max_1, kOverHangMax1VAG, + sizeof(self->over_hang_max_1)); + memcpy(self->over_hang_max_2, kOverHangMax2VAG, + sizeof(self->over_hang_max_2)); + memcpy(self->individual, kLocalThresholdVAG, + sizeof(self->individual)); + memcpy(self->total, kGlobalThresholdVAG, + sizeof(self->total)); + break; + default: + return_value = -1; + break; + } + + return return_value; +} + +// Calculate VAD decision by first extracting feature values and then calculate +// probability for both speech and background noise. + +int WebRtcVad_CalcVad48khz(VadInstT* inst, const int16_t* speech_frame, + size_t frame_length) { + int vad; + size_t i; + int16_t speech_nb[240]; // 30 ms in 8 kHz. + // `tmp_mem` is a temporary memory used by resample function, length is + // frame length in 10 ms (480 samples) + 256 extra. + int32_t tmp_mem[480 + 256] = { 0 }; + const size_t kFrameLen10ms48khz = 480; + const size_t kFrameLen10ms8khz = 80; + size_t num_10ms_frames = frame_length / kFrameLen10ms48khz; + + for (i = 0; i < num_10ms_frames; i++) { + WebRtcSpl_Resample48khzTo8khz(speech_frame, + &speech_nb[i * kFrameLen10ms8khz], + &inst->state_48_to_8, + tmp_mem); + } + + // Do VAD on an 8 kHz signal + vad = WebRtcVad_CalcVad8khz(inst, speech_nb, frame_length / 6); + + return vad; +} + +int WebRtcVad_CalcVad32khz(VadInstT* inst, const int16_t* speech_frame, + size_t frame_length) +{ + size_t len; + int vad; + int16_t speechWB[480]; // Downsampled speech frame: 960 samples (30ms in SWB) + int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB) + + + // Downsample signal 32->16->8 before doing VAD + WebRtcVad_Downsampling(speech_frame, speechWB, &(inst->downsampling_filter_states[2]), + frame_length); + len = frame_length / 2; + + WebRtcVad_Downsampling(speechWB, speechNB, inst->downsampling_filter_states, len); + len /= 2; + + // Do VAD on an 8 kHz signal + vad = WebRtcVad_CalcVad8khz(inst, speechNB, len); + + return vad; +} + +int WebRtcVad_CalcVad16khz(VadInstT* inst, const int16_t* speech_frame, + size_t frame_length) +{ + size_t len; + int vad; + int16_t speechNB[240]; // Downsampled speech frame: 480 samples (30ms in WB) + + // Wideband: Downsample signal before doing VAD + WebRtcVad_Downsampling(speech_frame, speechNB, inst->downsampling_filter_states, + frame_length); + + len = frame_length / 2; + vad = WebRtcVad_CalcVad8khz(inst, speechNB, len); + + return vad; +} + +int WebRtcVad_CalcVad8khz(VadInstT* inst, const int16_t* speech_frame, + size_t frame_length) +{ + int16_t feature_vector[kNumChannels], total_power; + + // Get power in the bands + total_power = WebRtcVad_CalculateFeatures(inst, speech_frame, frame_length, + feature_vector); + + // Make a VAD + inst->vad = GmmProbability(inst, feature_vector, total_power, frame_length); + + return inst->vad; +} diff --git a/third_party/libwebrtc/common_audio/vad/vad_core.h b/third_party/libwebrtc/common_audio/vad/vad_core.h new file mode 100644 index 0000000000..fbaf970065 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_core.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * This header file includes the descriptions of the core VAD calls. + */ + +#ifndef COMMON_AUDIO_VAD_VAD_CORE_H_ +#define COMMON_AUDIO_VAD_VAD_CORE_H_ + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// TODO(https://bugs.webrtc.org/14476): When converted to C++, remove the macro. +#if defined(__cplusplus) +#define CONSTEXPR_INT(x) constexpr int x +#else +#define CONSTEXPR_INT(x) enum { x } +#endif + +CONSTEXPR_INT(kNumChannels = 6); // Number of frequency bands (named channels). +CONSTEXPR_INT( + kNumGaussians = 2); // Number of Gaussians per channel in the GMM. +CONSTEXPR_INT(kTableSize = kNumChannels * kNumGaussians); +CONSTEXPR_INT( + kMinEnergy = 10); // Minimum energy required to trigger audio signal. + +typedef struct VadInstT_ { + int vad; + int32_t downsampling_filter_states[4]; + WebRtcSpl_State48khzTo8khz state_48_to_8; + int16_t noise_means[kTableSize]; + int16_t speech_means[kTableSize]; + int16_t noise_stds[kTableSize]; + int16_t speech_stds[kTableSize]; + // TODO(bjornv): Change to `frame_count`. + int32_t frame_counter; + int16_t over_hang; // Over Hang + int16_t num_of_speech; + // TODO(bjornv): Change to `age_vector`. + int16_t index_vector[16 * kNumChannels]; + int16_t low_value_vector[16 * kNumChannels]; + // TODO(bjornv): Change to `median`. + int16_t mean_value[kNumChannels]; + int16_t upper_state[5]; + int16_t lower_state[5]; + int16_t hp_filter_state[4]; + int16_t over_hang_max_1[3]; + int16_t over_hang_max_2[3]; + int16_t individual[3]; + int16_t total[3]; + + int init_flag; +} VadInstT; + +// Initializes the core VAD component. The default aggressiveness mode is +// controlled by `kDefaultMode` in vad_core.c. +// +// - self [i/o] : Instance that should be initialized +// +// returns : 0 (OK), -1 (null pointer in or if the default mode can't be +// set) +int WebRtcVad_InitCore(VadInstT* self); + +/**************************************************************************** + * WebRtcVad_set_mode_core(...) + * + * This function changes the VAD settings + * + * Input: + * - inst : VAD instance + * - mode : Aggressiveness degree + * 0 (High quality) - 3 (Highly aggressive) + * + * Output: + * - inst : Changed instance + * + * Return value : 0 - Ok + * -1 - Error + */ + +int WebRtcVad_set_mode_core(VadInstT* self, int mode); + +/**************************************************************************** + * WebRtcVad_CalcVad48khz(...) + * WebRtcVad_CalcVad32khz(...) + * WebRtcVad_CalcVad16khz(...) + * WebRtcVad_CalcVad8khz(...) + * + * Calculate probability for active speech and make VAD decision. + * + * Input: + * - inst : Instance that should be initialized + * - speech_frame : Input speech frame + * - frame_length : Number of input samples + * + * Output: + * - inst : Updated filter states etc. + * + * Return value : VAD decision + * 0 - No active speech + * 1-6 - Active speech + */ +int WebRtcVad_CalcVad48khz(VadInstT* inst, + const int16_t* speech_frame, + size_t frame_length); +int WebRtcVad_CalcVad32khz(VadInstT* inst, + const int16_t* speech_frame, + size_t frame_length); +int WebRtcVad_CalcVad16khz(VadInstT* inst, + const int16_t* speech_frame, + size_t frame_length); +int WebRtcVad_CalcVad8khz(VadInstT* inst, + const int16_t* speech_frame, + size_t frame_length); + +#endif // COMMON_AUDIO_VAD_VAD_CORE_H_ diff --git a/third_party/libwebrtc/common_audio/vad/vad_core_unittest.cc b/third_party/libwebrtc/common_audio/vad/vad_core_unittest.cc new file mode 100644 index 0000000000..3131a86ae3 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_core_unittest.cc @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdlib.h> + +#include "common_audio/vad/vad_unittest.h" +#include "test/gtest.h" + +extern "C" { +#include "common_audio/vad/vad_core.h" +} + +namespace webrtc { +namespace test { + +TEST_F(VadTest, InitCore) { + // Test WebRtcVad_InitCore(). + VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT))); + + // null pointer test. + EXPECT_EQ(-1, WebRtcVad_InitCore(nullptr)); + + // Verify return = 0 for non-null pointer. + EXPECT_EQ(0, WebRtcVad_InitCore(self)); + // Verify init_flag is set. + EXPECT_EQ(42, self->init_flag); + + free(self); +} + +TEST_F(VadTest, set_mode_core) { + VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT))); + + // TODO(bjornv): Add null pointer check if we take care of it in + // vad_core.c + + ASSERT_EQ(0, WebRtcVad_InitCore(self)); + // Test WebRtcVad_set_mode_core(). + // Invalid modes should return -1. + EXPECT_EQ(-1, WebRtcVad_set_mode_core(self, -1)); + EXPECT_EQ(-1, WebRtcVad_set_mode_core(self, 1000)); + // Valid modes should return 0. + for (size_t j = 0; j < kModesSize; ++j) { + EXPECT_EQ(0, WebRtcVad_set_mode_core(self, kModes[j])); + } + + free(self); +} + +TEST_F(VadTest, CalcVad) { + VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT))); + int16_t speech[kMaxFrameLength]; + + // TODO(bjornv): Add null pointer check if we take care of it in + // vad_core.c + + // Test WebRtcVad_CalcVadXXkhz() + // Verify that all zeros in gives VAD = 0 out. + memset(speech, 0, sizeof(speech)); + ASSERT_EQ(0, WebRtcVad_InitCore(self)); + for (size_t j = 0; j < kFrameLengthsSize; ++j) { + if (ValidRatesAndFrameLengths(8000, kFrameLengths[j])) { + EXPECT_EQ(0, WebRtcVad_CalcVad8khz(self, speech, kFrameLengths[j])); + } + if (ValidRatesAndFrameLengths(16000, kFrameLengths[j])) { + EXPECT_EQ(0, WebRtcVad_CalcVad16khz(self, speech, kFrameLengths[j])); + } + if (ValidRatesAndFrameLengths(32000, kFrameLengths[j])) { + EXPECT_EQ(0, WebRtcVad_CalcVad32khz(self, speech, kFrameLengths[j])); + } + if (ValidRatesAndFrameLengths(48000, kFrameLengths[j])) { + EXPECT_EQ(0, WebRtcVad_CalcVad48khz(self, speech, kFrameLengths[j])); + } + } + + // Construct a speech signal that will trigger the VAD in all modes. It is + // known that (i * i) will wrap around, but that doesn't matter in this case. + for (size_t i = 0; i < kMaxFrameLength; ++i) { + speech[i] = static_cast<int16_t>(i * i); + } + for (size_t j = 0; j < kFrameLengthsSize; ++j) { + if (ValidRatesAndFrameLengths(8000, kFrameLengths[j])) { + EXPECT_EQ(1, WebRtcVad_CalcVad8khz(self, speech, kFrameLengths[j])); + } + if (ValidRatesAndFrameLengths(16000, kFrameLengths[j])) { + EXPECT_EQ(1, WebRtcVad_CalcVad16khz(self, speech, kFrameLengths[j])); + } + if (ValidRatesAndFrameLengths(32000, kFrameLengths[j])) { + EXPECT_EQ(1, WebRtcVad_CalcVad32khz(self, speech, kFrameLengths[j])); + } + if (ValidRatesAndFrameLengths(48000, kFrameLengths[j])) { + EXPECT_EQ(1, WebRtcVad_CalcVad48khz(self, speech, kFrameLengths[j])); + } + } + + free(self); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/vad/vad_filterbank.c b/third_party/libwebrtc/common_audio/vad/vad_filterbank.c new file mode 100644 index 0000000000..aff63f79cd --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_filterbank.c @@ -0,0 +1,329 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/vad/vad_filterbank.h" + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" + +// Constants used in LogOfEnergy(). +static const int16_t kLogConst = 24660; // 160*log10(2) in Q9. +static const int16_t kLogEnergyIntPart = 14336; // 14 in Q10 + +// Coefficients used by HighPassFilter, Q14. +static const int16_t kHpZeroCoefs[3] = { 6631, -13262, 6631 }; +static const int16_t kHpPoleCoefs[3] = { 16384, -7756, 5620 }; + +// Allpass filter coefficients, upper and lower, in Q15. +// Upper: 0.64, Lower: 0.17 +static const int16_t kAllPassCoefsQ15[2] = { 20972, 5571 }; + +// Adjustment for division with two in SplitFilter. +static const int16_t kOffsetVector[6] = { 368, 368, 272, 176, 176, 176 }; + +// High pass filtering, with a cut-off frequency at 80 Hz, if the `data_in` is +// sampled at 500 Hz. +// +// - data_in [i] : Input audio data sampled at 500 Hz. +// - data_length [i] : Length of input and output data. +// - filter_state [i/o] : State of the filter. +// - data_out [o] : Output audio data in the frequency interval +// 80 - 250 Hz. +static void HighPassFilter(const int16_t* data_in, size_t data_length, + int16_t* filter_state, int16_t* data_out) { + size_t i; + const int16_t* in_ptr = data_in; + int16_t* out_ptr = data_out; + int32_t tmp32 = 0; + + + // The sum of the absolute values of the impulse response: + // The zero/pole-filter has a max amplification of a single sample of: 1.4546 + // Impulse response: 0.4047 -0.6179 -0.0266 0.1993 0.1035 -0.0194 + // The all-zero section has a max amplification of a single sample of: 1.6189 + // Impulse response: 0.4047 -0.8094 0.4047 0 0 0 + // The all-pole section has a max amplification of a single sample of: 1.9931 + // Impulse response: 1.0000 0.4734 -0.1189 -0.2187 -0.0627 0.04532 + + for (i = 0; i < data_length; i++) { + // All-zero section (filter coefficients in Q14). + tmp32 = kHpZeroCoefs[0] * *in_ptr; + tmp32 += kHpZeroCoefs[1] * filter_state[0]; + tmp32 += kHpZeroCoefs[2] * filter_state[1]; + filter_state[1] = filter_state[0]; + filter_state[0] = *in_ptr++; + + // All-pole section (filter coefficients in Q14). + tmp32 -= kHpPoleCoefs[1] * filter_state[2]; + tmp32 -= kHpPoleCoefs[2] * filter_state[3]; + filter_state[3] = filter_state[2]; + filter_state[2] = (int16_t) (tmp32 >> 14); + *out_ptr++ = filter_state[2]; + } +} + +// All pass filtering of `data_in`, used before splitting the signal into two +// frequency bands (low pass vs high pass). +// Note that `data_in` and `data_out` can NOT correspond to the same address. +// +// - data_in [i] : Input audio signal given in Q0. +// - data_length [i] : Length of input and output data. +// - filter_coefficient [i] : Given in Q15. +// - filter_state [i/o] : State of the filter given in Q(-1). +// - data_out [o] : Output audio signal given in Q(-1). +static void AllPassFilter(const int16_t* data_in, size_t data_length, + int16_t filter_coefficient, int16_t* filter_state, + int16_t* data_out) { + // The filter can only cause overflow (in the w16 output variable) + // if more than 4 consecutive input numbers are of maximum value and + // has the the same sign as the impulse responses first taps. + // First 6 taps of the impulse response: + // 0.6399 0.5905 -0.3779 0.2418 -0.1547 0.0990 + + size_t i; + int16_t tmp16 = 0; + int32_t tmp32 = 0; + int32_t state32 = ((int32_t) (*filter_state) * (1 << 16)); // Q15 + + for (i = 0; i < data_length; i++) { + tmp32 = state32 + filter_coefficient * *data_in; + tmp16 = (int16_t) (tmp32 >> 16); // Q(-1) + *data_out++ = tmp16; + state32 = (*data_in * (1 << 14)) - filter_coefficient * tmp16; // Q14 + state32 *= 2; // Q15. + data_in += 2; + } + + *filter_state = (int16_t) (state32 >> 16); // Q(-1) +} + +// Splits `data_in` into `hp_data_out` and `lp_data_out` corresponding to +// an upper (high pass) part and a lower (low pass) part respectively. +// +// - data_in [i] : Input audio data to be split into two frequency bands. +// - data_length [i] : Length of `data_in`. +// - upper_state [i/o] : State of the upper filter, given in Q(-1). +// - lower_state [i/o] : State of the lower filter, given in Q(-1). +// - hp_data_out [o] : Output audio data of the upper half of the spectrum. +// The length is `data_length` / 2. +// - lp_data_out [o] : Output audio data of the lower half of the spectrum. +// The length is `data_length` / 2. +static void SplitFilter(const int16_t* data_in, size_t data_length, + int16_t* upper_state, int16_t* lower_state, + int16_t* hp_data_out, int16_t* lp_data_out) { + size_t i; + size_t half_length = data_length >> 1; // Downsampling by 2. + int16_t tmp_out; + + // All-pass filtering upper branch. + AllPassFilter(&data_in[0], half_length, kAllPassCoefsQ15[0], upper_state, + hp_data_out); + + // All-pass filtering lower branch. + AllPassFilter(&data_in[1], half_length, kAllPassCoefsQ15[1], lower_state, + lp_data_out); + + // Make LP and HP signals. + for (i = 0; i < half_length; i++) { + tmp_out = *hp_data_out; + *hp_data_out++ -= *lp_data_out; + *lp_data_out++ += tmp_out; + } +} + +// Calculates the energy of `data_in` in dB, and also updates an overall +// `total_energy` if necessary. +// +// - data_in [i] : Input audio data for energy calculation. +// - data_length [i] : Length of input data. +// - offset [i] : Offset value added to `log_energy`. +// - total_energy [i/o] : An external energy updated with the energy of +// `data_in`. +// NOTE: `total_energy` is only updated if +// `total_energy` <= `kMinEnergy`. +// - log_energy [o] : 10 * log10("energy of `data_in`") given in Q4. +static void LogOfEnergy(const int16_t* data_in, size_t data_length, + int16_t offset, int16_t* total_energy, + int16_t* log_energy) { + // `tot_rshifts` accumulates the number of right shifts performed on `energy`. + int tot_rshifts = 0; + // The `energy` will be normalized to 15 bits. We use unsigned integer because + // we eventually will mask out the fractional part. + uint32_t energy = 0; + + RTC_DCHECK(data_in); + RTC_DCHECK_GT(data_length, 0); + + energy = (uint32_t) WebRtcSpl_Energy((int16_t*) data_in, data_length, + &tot_rshifts); + + if (energy != 0) { + // By construction, normalizing to 15 bits is equivalent with 17 leading + // zeros of an unsigned 32 bit value. + int normalizing_rshifts = 17 - WebRtcSpl_NormU32(energy); + // In a 15 bit representation the leading bit is 2^14. log2(2^14) in Q10 is + // (14 << 10), which is what we initialize `log2_energy` with. For a more + // detailed derivations, see below. + int16_t log2_energy = kLogEnergyIntPart; + + tot_rshifts += normalizing_rshifts; + // Normalize `energy` to 15 bits. + // `tot_rshifts` is now the total number of right shifts performed on + // `energy` after normalization. This means that `energy` is in + // Q(-tot_rshifts). + if (normalizing_rshifts < 0) { + energy <<= -normalizing_rshifts; + } else { + energy >>= normalizing_rshifts; + } + + // Calculate the energy of `data_in` in dB, in Q4. + // + // 10 * log10("true energy") in Q4 = 2^4 * 10 * log10("true energy") = + // 160 * log10(`energy` * 2^`tot_rshifts`) = + // 160 * log10(2) * log2(`energy` * 2^`tot_rshifts`) = + // 160 * log10(2) * (log2(`energy`) + log2(2^`tot_rshifts`)) = + // (160 * log10(2)) * (log2(`energy`) + `tot_rshifts`) = + // `kLogConst` * (`log2_energy` + `tot_rshifts`) + // + // We know by construction that `energy` is normalized to 15 bits. Hence, + // `energy` = 2^14 + frac_Q15, where frac_Q15 is a fractional part in Q15. + // Further, we'd like `log2_energy` in Q10 + // log2(`energy`) in Q10 = 2^10 * log2(2^14 + frac_Q15) = + // 2^10 * log2(2^14 * (1 + frac_Q15 * 2^-14)) = + // 2^10 * (14 + log2(1 + frac_Q15 * 2^-14)) ~= + // (14 << 10) + 2^10 * (frac_Q15 * 2^-14) = + // (14 << 10) + (frac_Q15 * 2^-4) = (14 << 10) + (frac_Q15 >> 4) + // + // Note that frac_Q15 = (`energy` & 0x00003FFF) + + // Calculate and add the fractional part to `log2_energy`. + log2_energy += (int16_t) ((energy & 0x00003FFF) >> 4); + + // `kLogConst` is in Q9, `log2_energy` in Q10 and `tot_rshifts` in Q0. + // Note that we in our derivation above have accounted for an output in Q4. + *log_energy = (int16_t)(((kLogConst * log2_energy) >> 19) + + ((tot_rshifts * kLogConst) >> 9)); + + if (*log_energy < 0) { + *log_energy = 0; + } + } else { + *log_energy = offset; + return; + } + + *log_energy += offset; + + // Update the approximate `total_energy` with the energy of `data_in`, if + // `total_energy` has not exceeded `kMinEnergy`. `total_energy` is used as an + // energy indicator in WebRtcVad_GmmProbability() in vad_core.c. + if (*total_energy <= kMinEnergy) { + if (tot_rshifts >= 0) { + // We know by construction that the `energy` > `kMinEnergy` in Q0, so add + // an arbitrary value such that `total_energy` exceeds `kMinEnergy`. + *total_energy += kMinEnergy + 1; + } else { + // By construction `energy` is represented by 15 bits, hence any number of + // right shifted `energy` will fit in an int16_t. In addition, adding the + // value to `total_energy` is wrap around safe as long as + // `kMinEnergy` < 8192. + *total_energy += (int16_t) (energy >> -tot_rshifts); // Q0. + } + } +} + +int16_t WebRtcVad_CalculateFeatures(VadInstT* self, const int16_t* data_in, + size_t data_length, int16_t* features) { + int16_t total_energy = 0; + // We expect `data_length` to be 80, 160 or 240 samples, which corresponds to + // 10, 20 or 30 ms in 8 kHz. Therefore, the intermediate downsampled data will + // have at most 120 samples after the first split and at most 60 samples after + // the second split. + int16_t hp_120[120], lp_120[120]; + int16_t hp_60[60], lp_60[60]; + const size_t half_data_length = data_length >> 1; + size_t length = half_data_length; // `data_length` / 2, corresponds to + // bandwidth = 2000 Hz after downsampling. + + // Initialize variables for the first SplitFilter(). + int frequency_band = 0; + const int16_t* in_ptr = data_in; // [0 - 4000] Hz. + int16_t* hp_out_ptr = hp_120; // [2000 - 4000] Hz. + int16_t* lp_out_ptr = lp_120; // [0 - 2000] Hz. + + RTC_DCHECK_LE(data_length, 240); + RTC_DCHECK_LT(4, kNumChannels - 1); // Checking maximum `frequency_band`. + + // Split at 2000 Hz and downsample. + SplitFilter(in_ptr, data_length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // For the upper band (2000 Hz - 4000 Hz) split at 3000 Hz and downsample. + frequency_band = 1; + in_ptr = hp_120; // [2000 - 4000] Hz. + hp_out_ptr = hp_60; // [3000 - 4000] Hz. + lp_out_ptr = lp_60; // [2000 - 3000] Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 3000 Hz - 4000 Hz. + length >>= 1; // `data_length` / 4 <=> bandwidth = 1000 Hz. + + LogOfEnergy(hp_60, length, kOffsetVector[5], &total_energy, &features[5]); + + // Energy in 2000 Hz - 3000 Hz. + LogOfEnergy(lp_60, length, kOffsetVector[4], &total_energy, &features[4]); + + // For the lower band (0 Hz - 2000 Hz) split at 1000 Hz and downsample. + frequency_band = 2; + in_ptr = lp_120; // [0 - 2000] Hz. + hp_out_ptr = hp_60; // [1000 - 2000] Hz. + lp_out_ptr = lp_60; // [0 - 1000] Hz. + length = half_data_length; // `data_length` / 2 <=> bandwidth = 2000 Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 1000 Hz - 2000 Hz. + length >>= 1; // `data_length` / 4 <=> bandwidth = 1000 Hz. + LogOfEnergy(hp_60, length, kOffsetVector[3], &total_energy, &features[3]); + + // For the lower band (0 Hz - 1000 Hz) split at 500 Hz and downsample. + frequency_band = 3; + in_ptr = lp_60; // [0 - 1000] Hz. + hp_out_ptr = hp_120; // [500 - 1000] Hz. + lp_out_ptr = lp_120; // [0 - 500] Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 500 Hz - 1000 Hz. + length >>= 1; // `data_length` / 8 <=> bandwidth = 500 Hz. + LogOfEnergy(hp_120, length, kOffsetVector[2], &total_energy, &features[2]); + + // For the lower band (0 Hz - 500 Hz) split at 250 Hz and downsample. + frequency_band = 4; + in_ptr = lp_120; // [0 - 500] Hz. + hp_out_ptr = hp_60; // [250 - 500] Hz. + lp_out_ptr = lp_60; // [0 - 250] Hz. + SplitFilter(in_ptr, length, &self->upper_state[frequency_band], + &self->lower_state[frequency_band], hp_out_ptr, lp_out_ptr); + + // Energy in 250 Hz - 500 Hz. + length >>= 1; // `data_length` / 16 <=> bandwidth = 250 Hz. + LogOfEnergy(hp_60, length, kOffsetVector[1], &total_energy, &features[1]); + + // Remove 0 Hz - 80 Hz, by high pass filtering the lower band. + HighPassFilter(lp_60, length, self->hp_filter_state, hp_120); + + // Energy in 80 Hz - 250 Hz. + LogOfEnergy(hp_120, length, kOffsetVector[0], &total_energy, &features[0]); + + return total_energy; +} diff --git a/third_party/libwebrtc/common_audio/vad/vad_filterbank.h b/third_party/libwebrtc/common_audio/vad/vad_filterbank.h new file mode 100644 index 0000000000..205eac832c --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_filterbank.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * This file includes feature calculating functionality used in vad_core.c. + */ + +#ifndef COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ +#define COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ + +#include "common_audio/vad/vad_core.h" + +// Takes `data_length` samples of `data_in` and calculates the logarithm of the +// energy of each of the `kNumChannels` = 6 frequency bands used by the VAD: +// 80 Hz - 250 Hz +// 250 Hz - 500 Hz +// 500 Hz - 1000 Hz +// 1000 Hz - 2000 Hz +// 2000 Hz - 3000 Hz +// 3000 Hz - 4000 Hz +// +// The values are given in Q4 and written to `features`. Further, an approximate +// overall energy is returned. The return value is used in +// WebRtcVad_GmmProbability() as a signal indicator, hence it is arbitrary above +// the threshold `kMinEnergy`. +// +// - self [i/o] : State information of the VAD. +// - data_in [i] : Input audio data, for feature extraction. +// - data_length [i] : Audio data size, in number of samples. +// - features [o] : 10 * log10(energy in each frequency band), Q4. +// - returns : Total energy of the signal (NOTE! This value is not +// exact. It is only used in a comparison.) +int16_t WebRtcVad_CalculateFeatures(VadInstT* self, + const int16_t* data_in, + size_t data_length, + int16_t* features); + +#endif // COMMON_AUDIO_VAD_VAD_FILTERBANK_H_ diff --git a/third_party/libwebrtc/common_audio/vad/vad_filterbank_unittest.cc b/third_party/libwebrtc/common_audio/vad/vad_filterbank_unittest.cc new file mode 100644 index 0000000000..51d8d0fefd --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_filterbank_unittest.cc @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdlib.h> + +#include "common_audio/vad/vad_unittest.h" +#include "test/gtest.h" + +extern "C" { +#include "common_audio/vad/vad_core.h" +#include "common_audio/vad/vad_filterbank.h" +} + +namespace webrtc { +namespace test { + +const int kNumValidFrameLengths = 3; + +TEST_F(VadTest, vad_filterbank) { + VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT))); + static const int16_t kReference[kNumValidFrameLengths] = {48, 11, 11}; + static const int16_t kFeatures[kNumValidFrameLengths * kNumChannels] = { + 1213, 759, 587, 462, 434, 272, 1479, 1385, 1291, + 1200, 1103, 1099, 1732, 1692, 1681, 1629, 1436, 1436}; + static const int16_t kOffsetVector[kNumChannels] = {368, 368, 272, + 176, 176, 176}; + int16_t features[kNumChannels]; + + // Construct a speech signal that will trigger the VAD in all modes. It is + // known that (i * i) will wrap around, but that doesn't matter in this case. + int16_t speech[kMaxFrameLength]; + for (size_t i = 0; i < kMaxFrameLength; ++i) { + speech[i] = static_cast<int16_t>(i * i); + } + + int frame_length_index = 0; + ASSERT_EQ(0, WebRtcVad_InitCore(self)); + for (size_t j = 0; j < kFrameLengthsSize; ++j) { + if (ValidRatesAndFrameLengths(8000, kFrameLengths[j])) { + EXPECT_EQ(kReference[frame_length_index], + WebRtcVad_CalculateFeatures(self, speech, kFrameLengths[j], + features)); + for (int k = 0; k < kNumChannels; ++k) { + EXPECT_EQ(kFeatures[k + frame_length_index * kNumChannels], + features[k]); + } + frame_length_index++; + } + } + EXPECT_EQ(kNumValidFrameLengths, frame_length_index); + + // Verify that all zeros in gives kOffsetVector out. + memset(speech, 0, sizeof(speech)); + ASSERT_EQ(0, WebRtcVad_InitCore(self)); + for (size_t j = 0; j < kFrameLengthsSize; ++j) { + if (ValidRatesAndFrameLengths(8000, kFrameLengths[j])) { + EXPECT_EQ(0, WebRtcVad_CalculateFeatures(self, speech, kFrameLengths[j], + features)); + for (int k = 0; k < kNumChannels; ++k) { + EXPECT_EQ(kOffsetVector[k], features[k]); + } + } + } + + // Verify that all ones in gives kOffsetVector out. Any other constant input + // will have a small impact in the sub bands. + for (size_t i = 0; i < kMaxFrameLength; ++i) { + speech[i] = 1; + } + for (size_t j = 0; j < kFrameLengthsSize; ++j) { + if (ValidRatesAndFrameLengths(8000, kFrameLengths[j])) { + ASSERT_EQ(0, WebRtcVad_InitCore(self)); + EXPECT_EQ(0, WebRtcVad_CalculateFeatures(self, speech, kFrameLengths[j], + features)); + for (int k = 0; k < kNumChannels; ++k) { + EXPECT_EQ(kOffsetVector[k], features[k]); + } + } + } + + free(self); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/vad/vad_gmm.c b/third_party/libwebrtc/common_audio/vad/vad_gmm.c new file mode 100644 index 0000000000..4a7fe67d09 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_gmm.c @@ -0,0 +1,82 @@ +/* + * 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. + */ + +#include "common_audio/vad/vad_gmm.h" + +#include "common_audio/signal_processing/include/signal_processing_library.h" + +static const int32_t kCompVar = 22005; +static const int16_t kLog2Exp = 5909; // log2(exp(1)) in Q12. + +// For a normal distribution, the probability of `input` is calculated and +// returned (in Q20). The formula for normal distributed probability is +// +// 1 / s * exp(-(x - m)^2 / (2 * s^2)) +// +// where the parameters are given in the following Q domains: +// m = `mean` (Q7) +// s = `std` (Q7) +// x = `input` (Q4) +// in addition to the probability we output `delta` (in Q11) used when updating +// the noise/speech model. +int32_t WebRtcVad_GaussianProbability(int16_t input, + int16_t mean, + int16_t std, + int16_t* delta) { + int16_t tmp16, inv_std, inv_std2, exp_value = 0; + int32_t tmp32; + + // Calculate `inv_std` = 1 / s, in Q10. + // 131072 = 1 in Q17, and (`std` >> 1) is for rounding instead of truncation. + // Q-domain: Q17 / Q7 = Q10. + tmp32 = (int32_t) 131072 + (int32_t) (std >> 1); + inv_std = (int16_t) WebRtcSpl_DivW32W16(tmp32, std); + + // Calculate `inv_std2` = 1 / s^2, in Q14. + tmp16 = (inv_std >> 2); // Q10 -> Q8. + // Q-domain: (Q8 * Q8) >> 2 = Q14. + inv_std2 = (int16_t)((tmp16 * tmp16) >> 2); + // TODO(bjornv): Investigate if changing to + // inv_std2 = (int16_t)((inv_std * inv_std) >> 6); + // gives better accuracy. + + tmp16 = (input << 3); // Q4 -> Q7 + tmp16 = tmp16 - mean; // Q7 - Q7 = Q7 + + // To be used later, when updating noise/speech model. + // `delta` = (x - m) / s^2, in Q11. + // Q-domain: (Q14 * Q7) >> 10 = Q11. + *delta = (int16_t)((inv_std2 * tmp16) >> 10); + + // Calculate the exponent `tmp32` = (x - m)^2 / (2 * s^2), in Q10. Replacing + // division by two with one shift. + // Q-domain: (Q11 * Q7) >> 8 = Q10. + tmp32 = (*delta * tmp16) >> 9; + + // If the exponent is small enough to give a non-zero probability we calculate + // `exp_value` ~= exp(-(x - m)^2 / (2 * s^2)) + // ~= exp2(-log2(exp(1)) * `tmp32`). + if (tmp32 < kCompVar) { + // Calculate `tmp16` = log2(exp(1)) * `tmp32`, in Q10. + // Q-domain: (Q12 * Q10) >> 12 = Q10. + tmp16 = (int16_t)((kLog2Exp * tmp32) >> 12); + tmp16 = -tmp16; + exp_value = (0x0400 | (tmp16 & 0x03FF)); + tmp16 ^= 0xFFFF; + tmp16 >>= 10; + tmp16 += 1; + // Get `exp_value` = exp(-`tmp32`) in Q10. + exp_value >>= tmp16; + } + + // Calculate and return (1 / s) * exp(-(x - m)^2 / (2 * s^2)), in Q20. + // Q-domain: Q10 * Q10 = Q20. + return inv_std * exp_value; +} diff --git a/third_party/libwebrtc/common_audio/vad/vad_gmm.h b/third_party/libwebrtc/common_audio/vad/vad_gmm.h new file mode 100644 index 0000000000..ada5189756 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_gmm.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// Gaussian probability calculations internally used in vad_core.c. + +#ifndef COMMON_AUDIO_VAD_VAD_GMM_H_ +#define COMMON_AUDIO_VAD_VAD_GMM_H_ + +#include <stdint.h> + +// Calculates the probability for `input`, given that `input` comes from a +// normal distribution with mean and standard deviation (`mean`, `std`). +// +// Inputs: +// - input : input sample in Q4. +// - mean : mean input in the statistical model, Q7. +// - std : standard deviation, Q7. +// +// Output: +// +// - delta : input used when updating the model, Q11. +// `delta` = (`input` - `mean`) / `std`^2. +// +// Return: +// (probability for `input`) = +// 1 / `std` * exp(-(`input` - `mean`)^2 / (2 * `std`^2)); +int32_t WebRtcVad_GaussianProbability(int16_t input, + int16_t mean, + int16_t std, + int16_t* delta); + +#endif // COMMON_AUDIO_VAD_VAD_GMM_H_ diff --git a/third_party/libwebrtc/common_audio/vad/vad_gmm_unittest.cc b/third_party/libwebrtc/common_audio/vad/vad_gmm_unittest.cc new file mode 100644 index 0000000000..be61f7f971 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_gmm_unittest.cc @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#include "common_audio/vad/vad_unittest.h" +#include "test/gtest.h" + +extern "C" { +#include "common_audio/vad/vad_gmm.h" +} + +namespace webrtc { +namespace test { + +TEST_F(VadTest, vad_gmm) { + int16_t delta = 0; + // Input value at mean. + EXPECT_EQ(1048576, WebRtcVad_GaussianProbability(0, 0, 128, &delta)); + EXPECT_EQ(0, delta); + EXPECT_EQ(1048576, WebRtcVad_GaussianProbability(16, 128, 128, &delta)); + EXPECT_EQ(0, delta); + EXPECT_EQ(1048576, WebRtcVad_GaussianProbability(-16, -128, 128, &delta)); + EXPECT_EQ(0, delta); + + // Largest possible input to give non-zero probability. + EXPECT_EQ(1024, WebRtcVad_GaussianProbability(59, 0, 128, &delta)); + EXPECT_EQ(7552, delta); + EXPECT_EQ(1024, WebRtcVad_GaussianProbability(75, 128, 128, &delta)); + EXPECT_EQ(7552, delta); + EXPECT_EQ(1024, WebRtcVad_GaussianProbability(-75, -128, 128, &delta)); + EXPECT_EQ(-7552, delta); + + // Too large input, should give zero probability. + EXPECT_EQ(0, WebRtcVad_GaussianProbability(105, 0, 128, &delta)); + EXPECT_EQ(13440, delta); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/vad/vad_sp.c b/third_party/libwebrtc/common_audio/vad/vad_sp.c new file mode 100644 index 0000000000..3d24cf64b3 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_sp.c @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/vad/vad_sp.h" + +#include "rtc_base/checks.h" +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "common_audio/vad/vad_core.h" + +// Allpass filter coefficients, upper and lower, in Q13. +// Upper: 0.64, Lower: 0.17. +static const int16_t kAllPassCoefsQ13[2] = { 5243, 1392 }; // Q13. +static const int16_t kSmoothingDown = 6553; // 0.2 in Q15. +static const int16_t kSmoothingUp = 32439; // 0.99 in Q15. + +// TODO(bjornv): Move this function to vad_filterbank.c. +// Downsampling filter based on splitting filter and allpass functions. +void WebRtcVad_Downsampling(const int16_t* signal_in, + int16_t* signal_out, + int32_t* filter_state, + size_t in_length) { + int16_t tmp16_1 = 0, tmp16_2 = 0; + int32_t tmp32_1 = filter_state[0]; + int32_t tmp32_2 = filter_state[1]; + size_t n = 0; + // Downsampling by 2 gives half length. + size_t half_length = (in_length >> 1); + + // Filter coefficients in Q13, filter state in Q0. + for (n = 0; n < half_length; n++) { + // All-pass filtering upper branch. + tmp16_1 = (int16_t) ((tmp32_1 >> 1) + + ((kAllPassCoefsQ13[0] * *signal_in) >> 14)); + *signal_out = tmp16_1; + tmp32_1 = (int32_t)(*signal_in++) - ((kAllPassCoefsQ13[0] * tmp16_1) >> 12); + + // All-pass filtering lower branch. + tmp16_2 = (int16_t) ((tmp32_2 >> 1) + + ((kAllPassCoefsQ13[1] * *signal_in) >> 14)); + *signal_out++ += tmp16_2; + tmp32_2 = (int32_t)(*signal_in++) - ((kAllPassCoefsQ13[1] * tmp16_2) >> 12); + } + // Store the filter states. + filter_state[0] = tmp32_1; + filter_state[1] = tmp32_2; +} + +// Inserts `feature_value` into `low_value_vector`, if it is one of the 16 +// smallest values the last 100 frames. Then calculates and returns the median +// of the five smallest values. +int16_t WebRtcVad_FindMinimum(VadInstT* self, + int16_t feature_value, + int channel) { + int i = 0, j = 0; + int position = -1; + // Offset to beginning of the 16 minimum values in memory. + const int offset = (channel << 4); + int16_t current_median = 1600; + int16_t alpha = 0; + int32_t tmp32 = 0; + // Pointer to memory for the 16 minimum values and the age of each value of + // the `channel`. + int16_t* age = &self->index_vector[offset]; + int16_t* smallest_values = &self->low_value_vector[offset]; + + RTC_DCHECK_LT(channel, kNumChannels); + + // Each value in `smallest_values` is getting 1 loop older. Update `age`, and + // remove old values. + for (i = 0; i < 16; i++) { + if (age[i] != 100) { + age[i]++; + } else { + // Too old value. Remove from memory and shift larger values downwards. + for (j = i; j < 15; j++) { + smallest_values[j] = smallest_values[j + 1]; + age[j] = age[j + 1]; + } + age[15] = 101; + smallest_values[15] = 10000; + } + } + + // Check if `feature_value` is smaller than any of the values in + // `smallest_values`. If so, find the `position` where to insert the new value + // (`feature_value`). + if (feature_value < smallest_values[7]) { + if (feature_value < smallest_values[3]) { + if (feature_value < smallest_values[1]) { + if (feature_value < smallest_values[0]) { + position = 0; + } else { + position = 1; + } + } else if (feature_value < smallest_values[2]) { + position = 2; + } else { + position = 3; + } + } else if (feature_value < smallest_values[5]) { + if (feature_value < smallest_values[4]) { + position = 4; + } else { + position = 5; + } + } else if (feature_value < smallest_values[6]) { + position = 6; + } else { + position = 7; + } + } else if (feature_value < smallest_values[15]) { + if (feature_value < smallest_values[11]) { + if (feature_value < smallest_values[9]) { + if (feature_value < smallest_values[8]) { + position = 8; + } else { + position = 9; + } + } else if (feature_value < smallest_values[10]) { + position = 10; + } else { + position = 11; + } + } else if (feature_value < smallest_values[13]) { + if (feature_value < smallest_values[12]) { + position = 12; + } else { + position = 13; + } + } else if (feature_value < smallest_values[14]) { + position = 14; + } else { + position = 15; + } + } + + // If we have detected a new small value, insert it at the correct position + // and shift larger values up. + if (position > -1) { + for (i = 15; i > position; i--) { + smallest_values[i] = smallest_values[i - 1]; + age[i] = age[i - 1]; + } + smallest_values[position] = feature_value; + age[position] = 1; + } + + // Get `current_median`. + if (self->frame_counter > 2) { + current_median = smallest_values[2]; + } else if (self->frame_counter > 0) { + current_median = smallest_values[0]; + } + + // Smooth the median value. + if (self->frame_counter > 0) { + if (current_median < self->mean_value[channel]) { + alpha = kSmoothingDown; // 0.2 in Q15. + } else { + alpha = kSmoothingUp; // 0.99 in Q15. + } + } + tmp32 = (alpha + 1) * self->mean_value[channel]; + tmp32 += (WEBRTC_SPL_WORD16_MAX - alpha) * current_median; + tmp32 += 16384; + self->mean_value[channel] = (int16_t) (tmp32 >> 15); + + return self->mean_value[channel]; +} diff --git a/third_party/libwebrtc/common_audio/vad/vad_sp.h b/third_party/libwebrtc/common_audio/vad/vad_sp.h new file mode 100644 index 0000000000..89138c57cf --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_sp.h @@ -0,0 +1,54 @@ +/* + * 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. + */ + +// This file includes specific signal processing tools used in vad_core.c. + +#ifndef COMMON_AUDIO_VAD_VAD_SP_H_ +#define COMMON_AUDIO_VAD_VAD_SP_H_ + +#include "common_audio/vad/vad_core.h" + +// Downsamples the signal by a factor 2, eg. 32->16 or 16->8. +// +// Inputs: +// - signal_in : Input signal. +// - in_length : Length of input signal in samples. +// +// Input & Output: +// - filter_state : Current filter states of the two all-pass filters. The +// `filter_state` is updated after all samples have been +// processed. +// +// Output: +// - signal_out : Downsampled signal (of length `in_length` / 2). +void WebRtcVad_Downsampling(const int16_t* signal_in, + int16_t* signal_out, + int32_t* filter_state, + size_t in_length); + +// Updates and returns the smoothed feature minimum. As minimum we use the +// median of the five smallest feature values in a 100 frames long window. +// As long as `handle->frame_counter` is zero, that is, we haven't received any +// "valid" data, FindMinimum() outputs the default value of 1600. +// +// Inputs: +// - feature_value : New feature value to update with. +// - channel : Channel number. +// +// Input & Output: +// - handle : State information of the VAD. +// +// Returns: +// : Smoothed minimum value for a moving window. +int16_t WebRtcVad_FindMinimum(VadInstT* handle, + int16_t feature_value, + int channel); + +#endif // COMMON_AUDIO_VAD_VAD_SP_H_ diff --git a/third_party/libwebrtc/common_audio/vad/vad_sp_unittest.cc b/third_party/libwebrtc/common_audio/vad/vad_sp_unittest.cc new file mode 100644 index 0000000000..bf208af3e1 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_sp_unittest.cc @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include <stdlib.h> + +#include "common_audio/vad/vad_unittest.h" +#include "test/gtest.h" + +extern "C" { +#include "common_audio/vad/vad_core.h" +#include "common_audio/vad/vad_sp.h" +} + +namespace webrtc { +namespace test { + +TEST_F(VadTest, vad_sp) { + VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT))); + const size_t kMaxFrameLenSp = 960; // Maximum frame length in this unittest. + int16_t zeros[kMaxFrameLenSp] = {0}; + int32_t state[2] = {0}; + int16_t data_in[kMaxFrameLenSp]; + int16_t data_out[kMaxFrameLenSp]; + + // We expect the first value to be 1600 as long as `frame_counter` is zero, + // which is true for the first iteration. + static const int16_t kReferenceMin[32] = { + 1600, 720, 509, 512, 532, 552, 570, 588, 606, 624, 642, + 659, 675, 691, 707, 723, 1600, 544, 502, 522, 542, 561, + 579, 597, 615, 633, 651, 667, 683, 699, 715, 731}; + + // Construct a speech signal that will trigger the VAD in all modes. It is + // known that (i * i) will wrap around, but that doesn't matter in this case. + for (size_t i = 0; i < kMaxFrameLenSp; ++i) { + data_in[i] = static_cast<int16_t>(i * i); + } + // Input values all zeros, expect all zeros out. + WebRtcVad_Downsampling(zeros, data_out, state, kMaxFrameLenSp); + EXPECT_EQ(0, state[0]); + EXPECT_EQ(0, state[1]); + for (size_t i = 0; i < kMaxFrameLenSp / 2; ++i) { + EXPECT_EQ(0, data_out[i]); + } + // Make a simple non-zero data test. + WebRtcVad_Downsampling(data_in, data_out, state, kMaxFrameLenSp); + EXPECT_EQ(207, state[0]); + EXPECT_EQ(2270, state[1]); + + ASSERT_EQ(0, WebRtcVad_InitCore(self)); + // TODO(bjornv): Replace this part of the test with taking values from an + // array and calculate the reference value here. Make sure the values are not + // ordered. + for (int16_t i = 0; i < 16; ++i) { + int16_t value = 500 * (i + 1); + for (int j = 0; j < kNumChannels; ++j) { + // Use values both above and below initialized value. + EXPECT_EQ(kReferenceMin[i], WebRtcVad_FindMinimum(self, value, j)); + EXPECT_EQ(kReferenceMin[i + 16], WebRtcVad_FindMinimum(self, 12000, j)); + } + self->frame_counter++; + } + + free(self); +} +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/vad/vad_unittest.cc b/third_party/libwebrtc/common_audio/vad/vad_unittest.cc new file mode 100644 index 0000000000..c54014efce --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_unittest.cc @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/vad/vad_unittest.h" + +#include <stdlib.h> + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "common_audio/vad/include/webrtc_vad.h" +#include "rtc_base/arraysize.h" +#include "rtc_base/checks.h" +#include "test/gtest.h" + +VadTest::VadTest() {} + +void VadTest::SetUp() {} + +void VadTest::TearDown() {} + +// Returns true if the rate and frame length combination is valid. +bool VadTest::ValidRatesAndFrameLengths(int rate, size_t frame_length) { + if (rate == 8000) { + if (frame_length == 80 || frame_length == 160 || frame_length == 240) { + return true; + } + return false; + } else if (rate == 16000) { + if (frame_length == 160 || frame_length == 320 || frame_length == 480) { + return true; + } + return false; + } else if (rate == 32000) { + if (frame_length == 320 || frame_length == 640 || frame_length == 960) { + return true; + } + return false; + } else if (rate == 48000) { + if (frame_length == 480 || frame_length == 960 || frame_length == 1440) { + return true; + } + return false; + } + + return false; +} + +namespace webrtc { +namespace test { + +TEST_F(VadTest, ApiTest) { + // This API test runs through the APIs for all possible valid and invalid + // combinations. + + VadInst* handle = WebRtcVad_Create(); + int16_t zeros[kMaxFrameLength] = {0}; + + // Construct a speech signal that will trigger the VAD in all modes. It is + // known that (i * i) will wrap around, but that doesn't matter in this case. + int16_t speech[kMaxFrameLength]; + for (size_t i = 0; i < kMaxFrameLength; i++) { + speech[i] = static_cast<int16_t>(i * i); + } + + // nullptr instance tests + EXPECT_EQ(-1, WebRtcVad_Init(nullptr)); + EXPECT_EQ(-1, WebRtcVad_set_mode(nullptr, kModes[0])); + EXPECT_EQ(-1, + WebRtcVad_Process(nullptr, kRates[0], speech, kFrameLengths[0])); + + // WebRtcVad_Create() + RTC_CHECK(handle); + + // Not initialized tests + EXPECT_EQ(-1, WebRtcVad_Process(handle, kRates[0], speech, kFrameLengths[0])); + EXPECT_EQ(-1, WebRtcVad_set_mode(handle, kModes[0])); + + // WebRtcVad_Init() test + ASSERT_EQ(0, WebRtcVad_Init(handle)); + + // WebRtcVad_set_mode() invalid modes tests. Tries smallest supported value + // minus one and largest supported value plus one. + EXPECT_EQ(-1, WebRtcVad_set_mode( + handle, WebRtcSpl_MinValueW32(kModes, kModesSize) - 1)); + EXPECT_EQ(-1, WebRtcVad_set_mode( + handle, WebRtcSpl_MaxValueW32(kModes, kModesSize) + 1)); + + // WebRtcVad_Process() tests + // nullptr as speech pointer + EXPECT_EQ(-1, + WebRtcVad_Process(handle, kRates[0], nullptr, kFrameLengths[0])); + // Invalid sampling rate + EXPECT_EQ(-1, WebRtcVad_Process(handle, 9999, speech, kFrameLengths[0])); + // All zeros as input should work + EXPECT_EQ(0, WebRtcVad_Process(handle, kRates[0], zeros, kFrameLengths[0])); + for (size_t k = 0; k < kModesSize; k++) { + // Test valid modes + EXPECT_EQ(0, WebRtcVad_set_mode(handle, kModes[k])); + // Loop through sampling rate and frame length combinations + for (size_t i = 0; i < kRatesSize; i++) { + for (size_t j = 0; j < kFrameLengthsSize; j++) { + if (ValidRatesAndFrameLengths(kRates[i], kFrameLengths[j])) { + EXPECT_EQ(1, WebRtcVad_Process(handle, kRates[i], speech, + kFrameLengths[j])); + } else { + EXPECT_EQ(-1, WebRtcVad_Process(handle, kRates[i], speech, + kFrameLengths[j])); + } + } + } + } + + WebRtcVad_Free(handle); +} + +TEST_F(VadTest, ValidRatesFrameLengths) { + // This test verifies valid and invalid rate/frame_length combinations. We + // loop through some sampling rates and frame lengths from negative values to + // values larger than possible. + const int kRates[] = {-8000, -4000, 0, 4000, 8000, 8001, + 15999, 16000, 32000, 48000, 48001, 96000}; + + const size_t kFrameLengths[] = {0, 80, 81, 159, 160, 240, + 320, 480, 640, 960, 1440, 2000}; + + for (size_t i = 0; i < arraysize(kRates); i++) { + for (size_t j = 0; j < arraysize(kFrameLengths); j++) { + if (ValidRatesAndFrameLengths(kRates[i], kFrameLengths[j])) { + EXPECT_EQ( + 0, WebRtcVad_ValidRateAndFrameLength(kRates[i], kFrameLengths[j])); + } else { + EXPECT_EQ( + -1, WebRtcVad_ValidRateAndFrameLength(kRates[i], kFrameLengths[j])); + } + } + } +} + +// TODO(bjornv): Add a process test, run on file. + +} // namespace test +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/vad/vad_unittest.h b/third_party/libwebrtc/common_audio/vad/vad_unittest.h new file mode 100644 index 0000000000..ee642063af --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/vad_unittest.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef COMMON_AUDIO_VAD_VAD_UNITTEST_H_ +#define COMMON_AUDIO_VAD_VAD_UNITTEST_H_ + +#include <stddef.h> // size_t + +#include "test/gtest.h" + +namespace webrtc { +namespace test { + +// Modes we support +const int kModes[] = {0, 1, 2, 3}; +const size_t kModesSize = sizeof(kModes) / sizeof(*kModes); + +// Rates we support. +const int kRates[] = {8000, 12000, 16000, 24000, 32000, 48000}; +const size_t kRatesSize = sizeof(kRates) / sizeof(*kRates); + +// Frame lengths we support. +const size_t kMaxFrameLength = 1440; +const size_t kFrameLengths[] = { + 80, 120, 160, 240, 320, 480, 640, 960, kMaxFrameLength}; +const size_t kFrameLengthsSize = sizeof(kFrameLengths) / sizeof(*kFrameLengths); + +} // namespace test +} // namespace webrtc + +class VadTest : public ::testing::Test { + protected: + VadTest(); + void SetUp() override; + void TearDown() override; + + // Returns true if the rate and frame length combination is valid. + bool ValidRatesAndFrameLengths(int rate, size_t frame_length); +}; + +#endif // COMMON_AUDIO_VAD_VAD_UNITTEST_H_ diff --git a/third_party/libwebrtc/common_audio/vad/webrtc_vad.c b/third_party/libwebrtc/common_audio/vad/webrtc_vad.c new file mode 100644 index 0000000000..6dd14d8b55 --- /dev/null +++ b/third_party/libwebrtc/common_audio/vad/webrtc_vad.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "common_audio/vad/include/webrtc_vad.h" + +#include <stdlib.h> +#include <string.h> + +#include "common_audio/signal_processing/include/signal_processing_library.h" +#include "common_audio/vad/vad_core.h" + +static const int kInitCheck = 42; +static const int kValidRates[] = { 8000, 16000, 32000, 48000 }; +static const size_t kRatesSize = sizeof(kValidRates) / sizeof(*kValidRates); +static const int kMaxFrameLengthMs = 30; + +VadInst* WebRtcVad_Create(void) { + VadInstT* self = (VadInstT*)malloc(sizeof(VadInstT)); + + self->init_flag = 0; + + return (VadInst*)self; +} + +void WebRtcVad_Free(VadInst* handle) { + free(handle); +} + +// TODO(bjornv): Move WebRtcVad_InitCore() code here. +int WebRtcVad_Init(VadInst* handle) { + // Initialize the core VAD component. + return WebRtcVad_InitCore((VadInstT*) handle); +} + +// TODO(bjornv): Move WebRtcVad_set_mode_core() code here. +int WebRtcVad_set_mode(VadInst* handle, int mode) { + VadInstT* self = (VadInstT*) handle; + + if (handle == NULL) { + return -1; + } + if (self->init_flag != kInitCheck) { + return -1; + } + + return WebRtcVad_set_mode_core(self, mode); +} + +int WebRtcVad_Process(VadInst* handle, int fs, const int16_t* audio_frame, + size_t frame_length) { + int vad = -1; + VadInstT* self = (VadInstT*) handle; + + if (handle == NULL) { + return -1; + } + + if (self->init_flag != kInitCheck) { + return -1; + } + if (audio_frame == NULL) { + return -1; + } + if (WebRtcVad_ValidRateAndFrameLength(fs, frame_length) != 0) { + return -1; + } + + if (fs == 48000) { + vad = WebRtcVad_CalcVad48khz(self, audio_frame, frame_length); + } else if (fs == 32000) { + vad = WebRtcVad_CalcVad32khz(self, audio_frame, frame_length); + } else if (fs == 16000) { + vad = WebRtcVad_CalcVad16khz(self, audio_frame, frame_length); + } else if (fs == 8000) { + vad = WebRtcVad_CalcVad8khz(self, audio_frame, frame_length); + } + + if (vad > 0) { + vad = 1; + } + return vad; +} + +int WebRtcVad_ValidRateAndFrameLength(int rate, size_t frame_length) { + int return_value = -1; + size_t i; + int valid_length_ms; + size_t valid_length; + + // We only allow 10, 20 or 30 ms frames. Loop through valid frame rates and + // see if we have a matching pair. + for (i = 0; i < kRatesSize; i++) { + if (kValidRates[i] == rate) { + for (valid_length_ms = 10; valid_length_ms <= kMaxFrameLengthMs; + valid_length_ms += 10) { + valid_length = (size_t)(kValidRates[i] / 1000 * valid_length_ms); + if (frame_length == valid_length) { + return_value = 0; + break; + } + } + break; + } + } + + return return_value; +} diff --git a/third_party/libwebrtc/common_audio/wav_file.cc b/third_party/libwebrtc/common_audio/wav_file.cc new file mode 100644 index 0000000000..127c9c0757 --- /dev/null +++ b/third_party/libwebrtc/common_audio/wav_file.cc @@ -0,0 +1,290 @@ +/* + * 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 "common_audio/wav_file.h" + +#include <errno.h> + +#include <algorithm> +#include <array> +#include <cstdio> +#include <type_traits> +#include <utility> + +#include "common_audio/include/audio_util.h" +#include "rtc_base/checks.h" +#include "rtc_base/system/arch.h" + +namespace webrtc { +namespace { + +static_assert(std::is_trivially_destructible<WavFormat>::value, ""); + +// Checks whether the format is supported or not. +bool FormatSupported(WavFormat format) { + // Only PCM and IEEE Float formats are supported. + return format == WavFormat::kWavFormatPcm || + format == WavFormat::kWavFormatIeeeFloat; +} + +// Doesn't take ownership of the file handle and won't close it. +class WavHeaderFileReader : public WavHeaderReader { + public: + explicit WavHeaderFileReader(FileWrapper* file) : file_(file) {} + + WavHeaderFileReader(const WavHeaderFileReader&) = delete; + WavHeaderFileReader& operator=(const WavHeaderFileReader&) = delete; + + size_t Read(void* buf, size_t num_bytes) override { + size_t count = file_->Read(buf, num_bytes); + pos_ += count; + return count; + } + bool SeekForward(uint32_t num_bytes) override { + bool success = file_->SeekRelative(num_bytes); + if (success) { + pos_ += num_bytes; + } + return success; + } + int64_t GetPosition() override { return pos_; } + + private: + FileWrapper* file_; + int64_t pos_ = 0; +}; + +constexpr size_t kMaxChunksize = 4096; + +} // namespace + +WavReader::WavReader(absl::string_view filename) + : WavReader(FileWrapper::OpenReadOnly(filename)) {} + +WavReader::WavReader(FileWrapper file) : file_(std::move(file)) { + RTC_CHECK(file_.is_open()) + << "Invalid file. Could not create file handle for wav file."; + + WavHeaderFileReader readable(&file_); + size_t bytes_per_sample; + RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format_, + &bytes_per_sample, &num_samples_in_file_, + &data_start_pos_)); + num_unread_samples_ = num_samples_in_file_; + RTC_CHECK(FormatSupported(format_)) << "Non-implemented wav-format"; +} + +void WavReader::Reset() { + RTC_CHECK(file_.SeekTo(data_start_pos_)) + << "Failed to set position in the file to WAV data start position"; + num_unread_samples_ = num_samples_in_file_; +} + +size_t WavReader::ReadSamples(const size_t num_samples, + int16_t* const samples) { +#ifndef WEBRTC_ARCH_LITTLE_ENDIAN +#error "Need to convert samples to big-endian when reading from WAV file" +#endif + + size_t num_samples_left_to_read = num_samples; + size_t next_chunk_start = 0; + while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) { + const size_t chunk_size = std::min( + std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_); + size_t num_bytes_read; + size_t num_samples_read; + if (format_ == WavFormat::kWavFormatIeeeFloat) { + std::array<float, kMaxChunksize> samples_to_convert; + num_bytes_read = file_.Read(samples_to_convert.data(), + chunk_size * sizeof(samples_to_convert[0])); + num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]); + + for (size_t j = 0; j < num_samples_read; ++j) { + samples[next_chunk_start + j] = FloatToS16(samples_to_convert[j]); + } + } else { + RTC_CHECK_EQ(format_, WavFormat::kWavFormatPcm); + num_bytes_read = file_.Read(&samples[next_chunk_start], + chunk_size * sizeof(samples[0])); + num_samples_read = num_bytes_read / sizeof(samples[0]); + } + RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0) + << "Corrupt file: file ended in the middle of a sample."; + RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof()) + << "Corrupt file: payload size does not match header."; + + next_chunk_start += num_samples_read; + num_unread_samples_ -= num_samples_read; + num_samples_left_to_read -= num_samples_read; + } + + return num_samples - num_samples_left_to_read; +} + +size_t WavReader::ReadSamples(const size_t num_samples, float* const samples) { +#ifndef WEBRTC_ARCH_LITTLE_ENDIAN +#error "Need to convert samples to big-endian when reading from WAV file" +#endif + + size_t num_samples_left_to_read = num_samples; + size_t next_chunk_start = 0; + while (num_samples_left_to_read > 0 && num_unread_samples_ > 0) { + const size_t chunk_size = std::min( + std::min(kMaxChunksize, num_samples_left_to_read), num_unread_samples_); + size_t num_bytes_read; + size_t num_samples_read; + if (format_ == WavFormat::kWavFormatPcm) { + std::array<int16_t, kMaxChunksize> samples_to_convert; + num_bytes_read = file_.Read(samples_to_convert.data(), + chunk_size * sizeof(samples_to_convert[0])); + num_samples_read = num_bytes_read / sizeof(samples_to_convert[0]); + + for (size_t j = 0; j < num_samples_read; ++j) { + samples[next_chunk_start + j] = + static_cast<float>(samples_to_convert[j]); + } + } else { + RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat); + num_bytes_read = file_.Read(&samples[next_chunk_start], + chunk_size * sizeof(samples[0])); + num_samples_read = num_bytes_read / sizeof(samples[0]); + + for (size_t j = 0; j < num_samples_read; ++j) { + samples[next_chunk_start + j] = + FloatToFloatS16(samples[next_chunk_start + j]); + } + } + RTC_CHECK(num_samples_read == 0 || (num_bytes_read % num_samples_read) == 0) + << "Corrupt file: file ended in the middle of a sample."; + RTC_CHECK(num_samples_read == chunk_size || file_.ReadEof()) + << "Corrupt file: payload size does not match header."; + + next_chunk_start += num_samples_read; + num_unread_samples_ -= num_samples_read; + num_samples_left_to_read -= num_samples_read; + } + + return num_samples - num_samples_left_to_read; +} + +void WavReader::Close() { + file_.Close(); +} + +WavWriter::WavWriter(absl::string_view filename, + int sample_rate, + size_t num_channels, + SampleFormat sample_format) + // Unlike plain fopen, OpenWriteOnly takes care of filename utf8 -> + // wchar conversion on windows. + : WavWriter(FileWrapper::OpenWriteOnly(filename), + sample_rate, + num_channels, + sample_format) {} + +WavWriter::WavWriter(FileWrapper file, + int sample_rate, + size_t num_channels, + SampleFormat sample_format) + : sample_rate_(sample_rate), + num_channels_(num_channels), + num_samples_written_(0), + format_(sample_format == SampleFormat::kInt16 + ? WavFormat::kWavFormatPcm + : WavFormat::kWavFormatIeeeFloat), + file_(std::move(file)) { + // Handle errors from the OpenWriteOnly call in above constructor. + RTC_CHECK(file_.is_open()) << "Invalid file. Could not create wav file."; + + RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, format_, + num_samples_written_)); + + // Write a blank placeholder header, since we need to know the total number + // of samples before we can fill in the real data. + static const uint8_t blank_header[MaxWavHeaderSize()] = {0}; + RTC_CHECK(file_.Write(blank_header, WavHeaderSize(format_))); +} + +void WavWriter::WriteSamples(const int16_t* samples, size_t num_samples) { +#ifndef WEBRTC_ARCH_LITTLE_ENDIAN +#error "Need to convert samples to little-endian when writing to WAV file" +#endif + + for (size_t i = 0; i < num_samples; i += kMaxChunksize) { + const size_t num_remaining_samples = num_samples - i; + const size_t num_samples_to_write = + std::min(kMaxChunksize, num_remaining_samples); + + if (format_ == WavFormat::kWavFormatPcm) { + RTC_CHECK( + file_.Write(&samples[i], num_samples_to_write * sizeof(samples[0]))); + } else { + RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat); + std::array<float, kMaxChunksize> converted_samples; + for (size_t j = 0; j < num_samples_to_write; ++j) { + converted_samples[j] = S16ToFloat(samples[i + j]); + } + RTC_CHECK( + file_.Write(converted_samples.data(), + num_samples_to_write * sizeof(converted_samples[0]))); + } + + num_samples_written_ += num_samples_to_write; + RTC_CHECK_GE(num_samples_written_, + num_samples_to_write); // detect size_t overflow + } +} + +void WavWriter::WriteSamples(const float* samples, size_t num_samples) { +#ifndef WEBRTC_ARCH_LITTLE_ENDIAN +#error "Need to convert samples to little-endian when writing to WAV file" +#endif + + for (size_t i = 0; i < num_samples; i += kMaxChunksize) { + const size_t num_remaining_samples = num_samples - i; + const size_t num_samples_to_write = + std::min(kMaxChunksize, num_remaining_samples); + + if (format_ == WavFormat::kWavFormatPcm) { + std::array<int16_t, kMaxChunksize> converted_samples; + for (size_t j = 0; j < num_samples_to_write; ++j) { + converted_samples[j] = FloatS16ToS16(samples[i + j]); + } + RTC_CHECK( + file_.Write(converted_samples.data(), + num_samples_to_write * sizeof(converted_samples[0]))); + } else { + RTC_CHECK_EQ(format_, WavFormat::kWavFormatIeeeFloat); + std::array<float, kMaxChunksize> converted_samples; + for (size_t j = 0; j < num_samples_to_write; ++j) { + converted_samples[j] = FloatS16ToFloat(samples[i + j]); + } + RTC_CHECK( + file_.Write(converted_samples.data(), + num_samples_to_write * sizeof(converted_samples[0]))); + } + + num_samples_written_ += num_samples_to_write; + RTC_CHECK(num_samples_written_ >= + num_samples_to_write); // detect size_t overflow + } +} + +void WavWriter::Close() { + RTC_CHECK(file_.Rewind()); + std::array<uint8_t, MaxWavHeaderSize()> header; + size_t header_size; + WriteWavHeader(num_channels_, sample_rate_, format_, num_samples_written_, + header.data(), &header_size); + RTC_CHECK(file_.Write(header.data(), header_size)); + RTC_CHECK(file_.Close()); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/wav_file.h b/third_party/libwebrtc/common_audio/wav_file.h new file mode 100644 index 0000000000..72a4db79c2 --- /dev/null +++ b/third_party/libwebrtc/common_audio/wav_file.h @@ -0,0 +1,115 @@ +/* + * 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 COMMON_AUDIO_WAV_FILE_H_ +#define COMMON_AUDIO_WAV_FILE_H_ + +#include <stdint.h> + +#include <cstddef> +#include <string> + +#include "common_audio/wav_header.h" +#include "rtc_base/system/file_wrapper.h" + +namespace webrtc { + +// Interface to provide access WAV file parameters. +class WavFile { + public: + enum class SampleFormat { kInt16, kFloat }; + + virtual ~WavFile() {} + + virtual int sample_rate() const = 0; + virtual size_t num_channels() const = 0; + virtual size_t num_samples() const = 0; +}; + +// Simple C++ class for writing 16-bit integer and 32 bit floating point PCM WAV +// files. All error handling is by calls to RTC_CHECK(), making it unsuitable +// for anything but debug code. +class WavWriter final : public WavFile { + public: + // Opens a new WAV file for writing. + WavWriter(absl::string_view filename, + int sample_rate, + size_t num_channels, + SampleFormat sample_format = SampleFormat::kInt16); + WavWriter(FileWrapper file, + int sample_rate, + size_t num_channels, + SampleFormat sample_format = SampleFormat::kInt16); + + // Closes the WAV file, after writing its header. + ~WavWriter() { Close(); } + + WavWriter(const WavWriter&) = delete; + WavWriter& operator=(const WavWriter&) = delete; + + // Write additional samples to the file. Each sample is in the range + // [-32768.0,32767.0], and there must be the previously specified number of + // interleaved channels. + void WriteSamples(const float* samples, size_t num_samples); + void WriteSamples(const int16_t* samples, size_t num_samples); + + int sample_rate() const override { return sample_rate_; } + size_t num_channels() const override { return num_channels_; } + size_t num_samples() const override { return num_samples_written_; } + + private: + void Close(); + const int sample_rate_; + const size_t num_channels_; + size_t num_samples_written_; + WavFormat format_; + FileWrapper file_; +}; + +// Follows the conventions of WavWriter. +class WavReader final : public WavFile { + public: + // Opens an existing WAV file for reading. + explicit WavReader(absl::string_view filename); + explicit WavReader(FileWrapper file); + + // Close the WAV file. + ~WavReader() { Close(); } + + WavReader(const WavReader&) = delete; + WavReader& operator=(const WavReader&) = delete; + + // Resets position to the beginning of the file. + void Reset(); + + // Returns the number of samples read. If this is less than requested, + // verifies that the end of the file was reached. + size_t ReadSamples(size_t num_samples, float* samples); + size_t ReadSamples(size_t num_samples, int16_t* samples); + + int sample_rate() const override { return sample_rate_; } + size_t num_channels() const override { return num_channels_; } + size_t num_samples() const override { return num_samples_in_file_; } + + private: + void Close(); + int sample_rate_; + size_t num_channels_; + WavFormat format_; + size_t num_samples_in_file_; + size_t num_unread_samples_; + FileWrapper file_; + int64_t + data_start_pos_; // Position in the file immediately after WAV header. +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_WAV_FILE_H_ diff --git a/third_party/libwebrtc/common_audio/wav_file_unittest.cc b/third_party/libwebrtc/common_audio/wav_file_unittest.cc new file mode 100644 index 0000000000..97cecc345f --- /dev/null +++ b/third_party/libwebrtc/common_audio/wav_file_unittest.cc @@ -0,0 +1,251 @@ +/* + * 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. + */ + +// MSVC++ requires this to be set before any other includes to get M_PI. +#define _USE_MATH_DEFINES + +#include "common_audio/wav_file.h" + +#include <cmath> +#include <limits> + +#include "common_audio/wav_header.h" +#include "test/gtest.h" +#include "test/testsupport/file_utils.h" + +// WavWriterTest.CPP flaky on Mac. See webrtc:9247. +#if defined(WEBRTC_MAC) +#define MAYBE_CPP DISABLED_CPP +#define MAYBE_CPPReset DISABLED_CPPReset +#else +#define MAYBE_CPP CPP +#define MAYBE_CPPReset CPPReset +#endif + +namespace webrtc { + +static const float kSamples[] = {0.0, 10.0, 4e4, -1e9}; + +// Write a tiny WAV file with the C++ interface and verify the result. +TEST(WavWriterTest, MAYBE_CPP) { + const std::string outfile = test::OutputPath() + "wavtest1.wav"; + static const size_t kNumSamples = 3; + { + WavWriter w(outfile, 14099, 1); + EXPECT_EQ(14099, w.sample_rate()); + EXPECT_EQ(1u, w.num_channels()); + EXPECT_EQ(0u, w.num_samples()); + w.WriteSamples(kSamples, kNumSamples); + EXPECT_EQ(kNumSamples, w.num_samples()); + } + // Write some extra "metadata" to the file that should be silently ignored + // by WavReader. We don't use WavWriter directly for this because it doesn't + // support metadata. + static const uint8_t kMetadata[] = {101, 202}; + { + FILE* f = fopen(outfile.c_str(), "ab"); + ASSERT_TRUE(f); + ASSERT_EQ(1u, fwrite(kMetadata, sizeof(kMetadata), 1, f)); + fclose(f); + } + static const uint8_t kExpectedContents[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 42, 0, 0, 0, // size of whole file - 8: 6 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 1, 0, // channels: 1 + 0x13, 0x37, 0, 0, // sample rate: 14099 + 0x26, 0x6e, 0, 0, // byte rate: 2 * 14099 + 2, 0, // block align: NumChannels * BytesPerSample + 16, 0, // bits per sample: 2 * 8 + 'd', 'a', 't', 'a', + 6, 0, 0, 0, // size of payload: 6 + 0, 0, // first sample: 0.0 + 10, 0, // second sample: 10.0 + 0xff, 0x7f, // third sample: 4e4 (saturated) + kMetadata[0], kMetadata[1], + // clang-format on + }; + static const size_t kContentSize = + kPcmWavHeaderSize + kNumSamples * sizeof(int16_t) + sizeof(kMetadata); + static_assert(sizeof(kExpectedContents) == kContentSize, "content size"); + EXPECT_EQ(kContentSize, test::GetFileSize(outfile)); + FILE* f = fopen(outfile.c_str(), "rb"); + ASSERT_TRUE(f); + uint8_t contents[kContentSize]; + ASSERT_EQ(1u, fread(contents, kContentSize, 1, f)); + EXPECT_EQ(0, fclose(f)); + EXPECT_EQ(0, memcmp(kExpectedContents, contents, kContentSize)); + + { + WavReader r(outfile); + EXPECT_EQ(14099, r.sample_rate()); + EXPECT_EQ(1u, r.num_channels()); + EXPECT_EQ(kNumSamples, r.num_samples()); + static const float kTruncatedSamples[] = {0.0, 10.0, 32767.0}; + float samples[kNumSamples]; + EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, samples)); + EXPECT_EQ(0, memcmp(kTruncatedSamples, samples, sizeof(samples))); + EXPECT_EQ(0u, r.ReadSamples(kNumSamples, samples)); + } +} + +// Write a larger WAV file. You can listen to this file to sanity-check it. +TEST(WavWriterTest, LargeFile) { + constexpr int kSampleRate = 8000; + constexpr size_t kNumChannels = 2; + constexpr size_t kNumSamples = 3 * kSampleRate * kNumChannels; + for (WavFile::SampleFormat wav_format : + {WavFile::SampleFormat::kInt16, WavFile::SampleFormat::kFloat}) { + for (WavFile::SampleFormat write_format : + {WavFile::SampleFormat::kInt16, WavFile::SampleFormat::kFloat}) { + for (WavFile::SampleFormat read_format : + {WavFile::SampleFormat::kInt16, WavFile::SampleFormat::kFloat}) { + std::string outfile = test::OutputPath() + "wavtest3.wav"; + float samples[kNumSamples]; + for (size_t i = 0; i < kNumSamples; i += kNumChannels) { + // A nice periodic beeping sound. + static const double kToneHz = 440; + const double t = + static_cast<double>(i) / (kNumChannels * kSampleRate); + const double x = std::numeric_limits<int16_t>::max() * + std::sin(t * kToneHz * 2 * M_PI); + samples[i] = std::pow(std::sin(t * 2 * 2 * M_PI), 10) * x; + samples[i + 1] = std::pow(std::cos(t * 2 * 2 * M_PI), 10) * x; + } + { + WavWriter w(outfile, kSampleRate, kNumChannels, wav_format); + EXPECT_EQ(kSampleRate, w.sample_rate()); + EXPECT_EQ(kNumChannels, w.num_channels()); + EXPECT_EQ(0u, w.num_samples()); + if (write_format == WavFile::SampleFormat::kFloat) { + float truncated_samples[kNumSamples]; + for (size_t k = 0; k < kNumSamples; ++k) { + truncated_samples[k] = static_cast<int16_t>(samples[k]); + } + w.WriteSamples(truncated_samples, kNumSamples); + } else { + w.WriteSamples(samples, kNumSamples); + } + EXPECT_EQ(kNumSamples, w.num_samples()); + } + if (wav_format == WavFile::SampleFormat::kFloat) { + EXPECT_EQ(sizeof(float) * kNumSamples + kIeeeFloatWavHeaderSize, + test::GetFileSize(outfile)); + } else { + EXPECT_EQ(sizeof(int16_t) * kNumSamples + kPcmWavHeaderSize, + test::GetFileSize(outfile)); + } + + { + WavReader r(outfile); + EXPECT_EQ(kSampleRate, r.sample_rate()); + EXPECT_EQ(kNumChannels, r.num_channels()); + EXPECT_EQ(kNumSamples, r.num_samples()); + + if (read_format == WavFile::SampleFormat::kFloat) { + float read_samples[kNumSamples]; + EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, read_samples)); + for (size_t i = 0; i < kNumSamples; ++i) { + EXPECT_NEAR(samples[i], read_samples[i], 1); + } + EXPECT_EQ(0u, r.ReadSamples(kNumSamples, read_samples)); + } else { + int16_t read_samples[kNumSamples]; + EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, read_samples)); + for (size_t i = 0; i < kNumSamples; ++i) { + EXPECT_NEAR(samples[i], static_cast<float>(read_samples[i]), 1); + } + EXPECT_EQ(0u, r.ReadSamples(kNumSamples, read_samples)); + } + } + } + } + } +} + +// Write a tiny WAV file with the C++ interface then read-reset-read. +TEST(WavReaderTest, MAYBE_CPPReset) { + const std::string outfile = test::OutputPath() + "wavtest4.wav"; + static const size_t kNumSamples = 3; + { + WavWriter w(outfile, 14099, 1); + EXPECT_EQ(14099, w.sample_rate()); + EXPECT_EQ(1u, w.num_channels()); + EXPECT_EQ(0u, w.num_samples()); + w.WriteSamples(kSamples, kNumSamples); + EXPECT_EQ(kNumSamples, w.num_samples()); + } + // Write some extra "metadata" to the file that should be silently ignored + // by WavReader. We don't use WavWriter directly for this because it doesn't + // support metadata. + static const uint8_t kMetadata[] = {101, 202}; + { + FILE* f = fopen(outfile.c_str(), "ab"); + ASSERT_TRUE(f); + ASSERT_EQ(1u, fwrite(kMetadata, sizeof(kMetadata), 1, f)); + fclose(f); + } + static const uint8_t kExpectedContents[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 42, 0, 0, 0, // size of whole file - 8: 6 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 1, 0, // channels: 1 + 0x13, 0x37, 0, 0, // sample rate: 14099 + 0x26, 0x6e, 0, 0, // byte rate: 2 * 14099 + 2, 0, // block align: NumChannels * BytesPerSample + 16, 0, // bits per sample: 2 * 8 + 'd', 'a', 't', 'a', + 6, 0, 0, 0, // size of payload: 6 + 0, 0, // first sample: 0.0 + 10, 0, // second sample: 10.0 + 0xff, 0x7f, // third sample: 4e4 (saturated) + kMetadata[0], kMetadata[1], + // clang-format on + }; + static const size_t kContentSize = + kPcmWavHeaderSize + kNumSamples * sizeof(int16_t) + sizeof(kMetadata); + static_assert(sizeof(kExpectedContents) == kContentSize, "content size"); + EXPECT_EQ(kContentSize, test::GetFileSize(outfile)); + FILE* f = fopen(outfile.c_str(), "rb"); + ASSERT_TRUE(f); + uint8_t contents[kContentSize]; + ASSERT_EQ(1u, fread(contents, kContentSize, 1, f)); + EXPECT_EQ(0, fclose(f)); + EXPECT_EQ(0, memcmp(kExpectedContents, contents, kContentSize)); + + { + WavReader r(outfile); + EXPECT_EQ(14099, r.sample_rate()); + EXPECT_EQ(1u, r.num_channels()); + EXPECT_EQ(kNumSamples, r.num_samples()); + static const float kTruncatedSamples[] = {0.0, 10.0, 32767.0}; + float samples[kNumSamples]; + EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, samples)); + EXPECT_EQ(0, memcmp(kTruncatedSamples, samples, sizeof(samples))); + EXPECT_EQ(0u, r.ReadSamples(kNumSamples, samples)); + + r.Reset(); + EXPECT_EQ(kNumSamples, r.ReadSamples(kNumSamples, samples)); + EXPECT_EQ(0, memcmp(kTruncatedSamples, samples, sizeof(samples))); + EXPECT_EQ(0u, r.ReadSamples(kNumSamples, samples)); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/wav_header.cc b/third_party/libwebrtc/common_audio/wav_header.cc new file mode 100644 index 0000000000..bca209a665 --- /dev/null +++ b/third_party/libwebrtc/common_audio/wav_header.cc @@ -0,0 +1,435 @@ +/* + * 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. + */ + +// Based on the WAV file format documentation at +// https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ and +// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html + +#include "common_audio/wav_header.h" + +#include <cstring> +#include <limits> +#include <string> + +#include "rtc_base/checks.h" +#include "rtc_base/logging.h" +#include "rtc_base/sanitizer.h" +#include "rtc_base/system/arch.h" + +namespace webrtc { +namespace { + +#ifndef WEBRTC_ARCH_LITTLE_ENDIAN +#error "Code not working properly for big endian platforms." +#endif + +#pragma pack(2) +struct ChunkHeader { + uint32_t ID; + uint32_t Size; +}; +static_assert(sizeof(ChunkHeader) == 8, "ChunkHeader size"); + +#pragma pack(2) +struct RiffHeader { + ChunkHeader header; + uint32_t Format; +}; +static_assert(sizeof(RiffHeader) == sizeof(ChunkHeader) + 4, "RiffHeader size"); + +// We can't nest this definition in WavHeader, because VS2013 gives an error +// on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand". +#pragma pack(2) +struct FmtPcmSubchunk { + ChunkHeader header; + uint16_t AudioFormat; + uint16_t NumChannels; + uint32_t SampleRate; + uint32_t ByteRate; + uint16_t BlockAlign; + uint16_t BitsPerSample; +}; +static_assert(sizeof(FmtPcmSubchunk) == 24, "FmtPcmSubchunk size"); +const uint32_t kFmtPcmSubchunkSize = + sizeof(FmtPcmSubchunk) - sizeof(ChunkHeader); + +// Pack struct to avoid additional padding bytes. +#pragma pack(2) +struct FmtIeeeFloatSubchunk { + ChunkHeader header; + uint16_t AudioFormat; + uint16_t NumChannels; + uint32_t SampleRate; + uint32_t ByteRate; + uint16_t BlockAlign; + uint16_t BitsPerSample; + uint16_t ExtensionSize; +}; +static_assert(sizeof(FmtIeeeFloatSubchunk) == 26, "FmtIeeeFloatSubchunk size"); +const uint32_t kFmtIeeeFloatSubchunkSize = + sizeof(FmtIeeeFloatSubchunk) - sizeof(ChunkHeader); + +// Simple PCM wav header. It does not include chunks that are not essential to +// read audio samples. +#pragma pack(2) +struct WavHeaderPcm { + RiffHeader riff; + FmtPcmSubchunk fmt; + struct { + ChunkHeader header; + } data; +}; +static_assert(sizeof(WavHeaderPcm) == kPcmWavHeaderSize, + "no padding in header"); + +// IEEE Float Wav header, includes extra chunks necessary for proper non-PCM +// WAV implementation. +#pragma pack(2) +struct WavHeaderIeeeFloat { + RiffHeader riff; + FmtIeeeFloatSubchunk fmt; + struct { + ChunkHeader header; + uint32_t SampleLength; + } fact; + struct { + ChunkHeader header; + } data; +}; +static_assert(sizeof(WavHeaderIeeeFloat) == kIeeeFloatWavHeaderSize, + "no padding in header"); + +uint32_t PackFourCC(char a, char b, char c, char d) { + uint32_t packed_value = + static_cast<uint32_t>(a) | static_cast<uint32_t>(b) << 8 | + static_cast<uint32_t>(c) << 16 | static_cast<uint32_t>(d) << 24; + return packed_value; +} + +std::string ReadFourCC(uint32_t x) { + return std::string(reinterpret_cast<char*>(&x), 4); +} + +uint16_t MapWavFormatToHeaderField(WavFormat format) { + switch (format) { + case WavFormat::kWavFormatPcm: + return 1; + case WavFormat::kWavFormatIeeeFloat: + return 3; + case WavFormat::kWavFormatALaw: + return 6; + case WavFormat::kWavFormatMuLaw: + return 7; + } + RTC_CHECK_NOTREACHED(); +} + +WavFormat MapHeaderFieldToWavFormat(uint16_t format_header_value) { + if (format_header_value == 1) { + return WavFormat::kWavFormatPcm; + } + if (format_header_value == 3) { + return WavFormat::kWavFormatIeeeFloat; + } + + RTC_CHECK(false) << "Unsupported WAV format"; +} + +uint32_t RiffChunkSize(size_t bytes_in_payload, size_t header_size) { + return static_cast<uint32_t>(bytes_in_payload + header_size - + sizeof(ChunkHeader)); +} + +uint32_t ByteRate(size_t num_channels, + int sample_rate, + size_t bytes_per_sample) { + return static_cast<uint32_t>(num_channels * sample_rate * bytes_per_sample); +} + +uint16_t BlockAlign(size_t num_channels, size_t bytes_per_sample) { + return static_cast<uint16_t>(num_channels * bytes_per_sample); +} + +// Finds a chunk having the sought ID. If found, then `readable` points to the +// first byte of the sought chunk data. If not found, the end of the file is +// reached. +bool FindWaveChunk(ChunkHeader* chunk_header, + WavHeaderReader* readable, + const std::string sought_chunk_id) { + RTC_DCHECK_EQ(sought_chunk_id.size(), 4); + while (true) { + if (readable->Read(chunk_header, sizeof(*chunk_header)) != + sizeof(*chunk_header)) + return false; // EOF. + if (ReadFourCC(chunk_header->ID) == sought_chunk_id) + return true; // Sought chunk found. + // Ignore current chunk by skipping its payload. + if (!readable->SeekForward(chunk_header->Size)) + return false; // EOF or error. + } +} + +bool ReadFmtChunkData(FmtPcmSubchunk* fmt_subchunk, WavHeaderReader* readable) { + // Reads "fmt " chunk payload. + if (readable->Read(&(fmt_subchunk->AudioFormat), kFmtPcmSubchunkSize) != + kFmtPcmSubchunkSize) + return false; + const uint32_t fmt_size = fmt_subchunk->header.Size; + if (fmt_size != kFmtPcmSubchunkSize) { + // There is an optional two-byte extension field permitted to be present + // with PCM, but which must be zero. + int16_t ext_size; + if (kFmtPcmSubchunkSize + sizeof(ext_size) != fmt_size) + return false; + if (readable->Read(&ext_size, sizeof(ext_size)) != sizeof(ext_size)) + return false; + if (ext_size != 0) + return false; + } + return true; +} + +void WritePcmWavHeader(size_t num_channels, + int sample_rate, + size_t bytes_per_sample, + size_t num_samples, + uint8_t* buf, + size_t* header_size) { + RTC_CHECK(buf); + RTC_CHECK(header_size); + *header_size = kPcmWavHeaderSize; + auto header = rtc::MsanUninitialized<WavHeaderPcm>({}); + const size_t bytes_in_payload = bytes_per_sample * num_samples; + + header.riff.header.ID = PackFourCC('R', 'I', 'F', 'F'); + header.riff.header.Size = RiffChunkSize(bytes_in_payload, *header_size); + header.riff.Format = PackFourCC('W', 'A', 'V', 'E'); + header.fmt.header.ID = PackFourCC('f', 'm', 't', ' '); + header.fmt.header.Size = kFmtPcmSubchunkSize; + header.fmt.AudioFormat = MapWavFormatToHeaderField(WavFormat::kWavFormatPcm); + header.fmt.NumChannels = static_cast<uint16_t>(num_channels); + header.fmt.SampleRate = sample_rate; + header.fmt.ByteRate = ByteRate(num_channels, sample_rate, bytes_per_sample); + header.fmt.BlockAlign = BlockAlign(num_channels, bytes_per_sample); + header.fmt.BitsPerSample = static_cast<uint16_t>(8 * bytes_per_sample); + header.data.header.ID = PackFourCC('d', 'a', 't', 'a'); + header.data.header.Size = static_cast<uint32_t>(bytes_in_payload); + + // Do an extra copy rather than writing everything to buf directly, since buf + // might not be correctly aligned. + memcpy(buf, &header, *header_size); +} + +void WriteIeeeFloatWavHeader(size_t num_channels, + int sample_rate, + size_t bytes_per_sample, + size_t num_samples, + uint8_t* buf, + size_t* header_size) { + RTC_CHECK(buf); + RTC_CHECK(header_size); + *header_size = kIeeeFloatWavHeaderSize; + auto header = rtc::MsanUninitialized<WavHeaderIeeeFloat>({}); + const size_t bytes_in_payload = bytes_per_sample * num_samples; + + header.riff.header.ID = PackFourCC('R', 'I', 'F', 'F'); + header.riff.header.Size = RiffChunkSize(bytes_in_payload, *header_size); + header.riff.Format = PackFourCC('W', 'A', 'V', 'E'); + header.fmt.header.ID = PackFourCC('f', 'm', 't', ' '); + header.fmt.header.Size = kFmtIeeeFloatSubchunkSize; + header.fmt.AudioFormat = + MapWavFormatToHeaderField(WavFormat::kWavFormatIeeeFloat); + header.fmt.NumChannels = static_cast<uint16_t>(num_channels); + header.fmt.SampleRate = sample_rate; + header.fmt.ByteRate = ByteRate(num_channels, sample_rate, bytes_per_sample); + header.fmt.BlockAlign = BlockAlign(num_channels, bytes_per_sample); + header.fmt.BitsPerSample = static_cast<uint16_t>(8 * bytes_per_sample); + header.fmt.ExtensionSize = 0; + header.fact.header.ID = PackFourCC('f', 'a', 'c', 't'); + header.fact.header.Size = 4; + header.fact.SampleLength = static_cast<uint32_t>(num_channels * num_samples); + header.data.header.ID = PackFourCC('d', 'a', 't', 'a'); + header.data.header.Size = static_cast<uint32_t>(bytes_in_payload); + + // Do an extra copy rather than writing everything to buf directly, since buf + // might not be correctly aligned. + memcpy(buf, &header, *header_size); +} + +// Returns the number of bytes per sample for the format. +size_t GetFormatBytesPerSample(WavFormat format) { + switch (format) { + case WavFormat::kWavFormatPcm: + // Other values may be OK, but for now we're conservative. + return 2; + case WavFormat::kWavFormatALaw: + case WavFormat::kWavFormatMuLaw: + return 1; + case WavFormat::kWavFormatIeeeFloat: + return 4; + } + RTC_CHECK_NOTREACHED(); +} + +bool CheckWavParameters(size_t num_channels, + int sample_rate, + WavFormat format, + size_t bytes_per_sample, + size_t num_samples) { + // num_channels, sample_rate, and bytes_per_sample must be positive, must fit + // in their respective fields, and their product must fit in the 32-bit + // ByteRate field. + if (num_channels == 0 || sample_rate <= 0 || bytes_per_sample == 0) + return false; + if (static_cast<uint64_t>(sample_rate) > std::numeric_limits<uint32_t>::max()) + return false; + if (num_channels > std::numeric_limits<uint16_t>::max()) + return false; + if (static_cast<uint64_t>(bytes_per_sample) * 8 > + std::numeric_limits<uint16_t>::max()) + return false; + if (static_cast<uint64_t>(sample_rate) * num_channels * bytes_per_sample > + std::numeric_limits<uint32_t>::max()) + return false; + + // format and bytes_per_sample must agree. + switch (format) { + case WavFormat::kWavFormatPcm: + // Other values may be OK, but for now we're conservative: + if (bytes_per_sample != 1 && bytes_per_sample != 2) + return false; + break; + case WavFormat::kWavFormatALaw: + case WavFormat::kWavFormatMuLaw: + if (bytes_per_sample != 1) + return false; + break; + case WavFormat::kWavFormatIeeeFloat: + if (bytes_per_sample != 4) + return false; + break; + default: + return false; + } + + // The number of bytes in the file, not counting the first ChunkHeader, must + // be less than 2^32; otherwise, the ChunkSize field overflows. + const size_t header_size = kPcmWavHeaderSize - sizeof(ChunkHeader); + const size_t max_samples = + (std::numeric_limits<uint32_t>::max() - header_size) / bytes_per_sample; + if (num_samples > max_samples) + return false; + + // Each channel must have the same number of samples. + if (num_samples % num_channels != 0) + return false; + + return true; +} + +} // namespace + +bool CheckWavParameters(size_t num_channels, + int sample_rate, + WavFormat format, + size_t num_samples) { + return CheckWavParameters(num_channels, sample_rate, format, + GetFormatBytesPerSample(format), num_samples); +} + +void WriteWavHeader(size_t num_channels, + int sample_rate, + WavFormat format, + size_t num_samples, + uint8_t* buf, + size_t* header_size) { + RTC_CHECK(buf); + RTC_CHECK(header_size); + + const size_t bytes_per_sample = GetFormatBytesPerSample(format); + RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format, + bytes_per_sample, num_samples)); + if (format == WavFormat::kWavFormatPcm) { + WritePcmWavHeader(num_channels, sample_rate, bytes_per_sample, num_samples, + buf, header_size); + } else { + RTC_CHECK_EQ(format, WavFormat::kWavFormatIeeeFloat); + WriteIeeeFloatWavHeader(num_channels, sample_rate, bytes_per_sample, + num_samples, buf, header_size); + } +} + +bool ReadWavHeader(WavHeaderReader* readable, + size_t* num_channels, + int* sample_rate, + WavFormat* format, + size_t* bytes_per_sample, + size_t* num_samples, + int64_t* data_start_pos) { + // Read using the PCM header, even though it might be float Wav file + auto header = rtc::MsanUninitialized<WavHeaderPcm>({}); + + // Read RIFF chunk. + if (readable->Read(&header.riff, sizeof(header.riff)) != sizeof(header.riff)) + return false; + if (ReadFourCC(header.riff.header.ID) != "RIFF") + return false; + if (ReadFourCC(header.riff.Format) != "WAVE") + return false; + + // Find "fmt " and "data" chunks. While the official Wave file specification + // does not put requirements on the chunks order, it is uncommon to find the + // "data" chunk before the "fmt " one. The code below fails if this is not the + // case. + if (!FindWaveChunk(&header.fmt.header, readable, "fmt ")) { + RTC_LOG(LS_ERROR) << "Cannot find 'fmt ' chunk."; + return false; + } + if (!ReadFmtChunkData(&header.fmt, readable)) { + RTC_LOG(LS_ERROR) << "Cannot read 'fmt ' chunk."; + return false; + } + if (!FindWaveChunk(&header.data.header, readable, "data")) { + RTC_LOG(LS_ERROR) << "Cannot find 'data' chunk."; + return false; + } + + // Parse needed fields. + *format = MapHeaderFieldToWavFormat(header.fmt.AudioFormat); + *num_channels = header.fmt.NumChannels; + *sample_rate = header.fmt.SampleRate; + *bytes_per_sample = header.fmt.BitsPerSample / 8; + const size_t bytes_in_payload = header.data.header.Size; + if (*bytes_per_sample == 0) + return false; + *num_samples = bytes_in_payload / *bytes_per_sample; + + const size_t header_size = *format == WavFormat::kWavFormatPcm + ? kPcmWavHeaderSize + : kIeeeFloatWavHeaderSize; + + if (header.riff.header.Size < RiffChunkSize(bytes_in_payload, header_size)) + return false; + if (header.fmt.ByteRate != + ByteRate(*num_channels, *sample_rate, *bytes_per_sample)) + return false; + if (header.fmt.BlockAlign != BlockAlign(*num_channels, *bytes_per_sample)) + return false; + + if (!CheckWavParameters(*num_channels, *sample_rate, *format, + *bytes_per_sample, *num_samples)) { + return false; + } + + *data_start_pos = readable->GetPosition(); + return true; +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/wav_header.h b/third_party/libwebrtc/common_audio/wav_header.h new file mode 100644 index 0000000000..2cccd7d34b --- /dev/null +++ b/third_party/libwebrtc/common_audio/wav_header.h @@ -0,0 +1,90 @@ +/* + * 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 COMMON_AUDIO_WAV_HEADER_H_ +#define COMMON_AUDIO_WAV_HEADER_H_ + +#include <stddef.h> +#include <stdint.h> +#include <algorithm> + +#include "rtc_base/checks.h" + +namespace webrtc { + +// Interface providing header reading functionality. +class WavHeaderReader { + public: + // Returns the number of bytes read. + virtual size_t Read(void* buf, size_t num_bytes) = 0; + virtual bool SeekForward(uint32_t num_bytes) = 0; + virtual ~WavHeaderReader() = default; + virtual int64_t GetPosition() = 0; +}; + +// Possible WAV formats. +enum class WavFormat { + kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample. + kWavFormatIeeeFloat = 3, // IEEE float. + kWavFormatALaw = 6, // 8-bit ITU-T G.711 A-law. + kWavFormatMuLaw = 7, // 8-bit ITU-T G.711 mu-law. +}; + +// Header sizes for supported WAV formats. +constexpr size_t kPcmWavHeaderSize = 44; +constexpr size_t kIeeeFloatWavHeaderSize = 58; + +// Returns the size of the WAV header for the specified format. +constexpr size_t WavHeaderSize(WavFormat format) { + if (format == WavFormat::kWavFormatPcm) { + return kPcmWavHeaderSize; + } + RTC_CHECK_EQ(format, WavFormat::kWavFormatIeeeFloat); + return kIeeeFloatWavHeaderSize; +} + +// Returns the maximum size of the supported WAV formats. +constexpr size_t MaxWavHeaderSize() { + return std::max(WavHeaderSize(WavFormat::kWavFormatPcm), + WavHeaderSize(WavFormat::kWavFormatIeeeFloat)); +} + +// Return true if the given parameters will make a well-formed WAV header. +bool CheckWavParameters(size_t num_channels, + int sample_rate, + WavFormat format, + size_t num_samples); + +// Write a kWavHeaderSize bytes long WAV header to buf. The payload that +// follows the header is supposed to have the specified number of interleaved +// channels and contain the specified total number of samples of the specified +// type. The size of the header is returned in header_size. CHECKs the input +// parameters for validity. +void WriteWavHeader(size_t num_channels, + int sample_rate, + WavFormat format, + size_t num_samples, + uint8_t* buf, + size_t* header_size); + +// Read a WAV header from an implemented WavHeaderReader and parse the values +// into the provided output parameters. WavHeaderReader is used because the +// header can be variably sized. Returns false if the header is invalid. +bool ReadWavHeader(WavHeaderReader* readable, + size_t* num_channels, + int* sample_rate, + WavFormat* format, + size_t* bytes_per_sample, + size_t* num_samples, + int64_t* data_start_pos); + +} // namespace webrtc + +#endif // COMMON_AUDIO_WAV_HEADER_H_ diff --git a/third_party/libwebrtc/common_audio/wav_header_unittest.cc b/third_party/libwebrtc/common_audio/wav_header_unittest.cc new file mode 100644 index 0000000000..95721dac65 --- /dev/null +++ b/third_party/libwebrtc/common_audio/wav_header_unittest.cc @@ -0,0 +1,447 @@ +/* + * 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 "common_audio/wav_header.h" + +#include <string.h> + +#include <limits> + +#include "test/gtest.h" + +namespace webrtc { + +// Doesn't take ownership of the buffer. +class WavHeaderBufferReader : public WavHeaderReader { + public: + WavHeaderBufferReader(const uint8_t* buf, size_t size, bool check_read_size) + : buf_(buf), + size_(size), + pos_(0), + buf_exhausted_(false), + check_read_size_(check_read_size) {} + + ~WavHeaderBufferReader() override { + // Verify the entire buffer has been read. + if (check_read_size_) + EXPECT_EQ(size_, pos_); + } + + size_t Read(void* buf, size_t num_bytes) override { + EXPECT_FALSE(buf_exhausted_); + + const size_t bytes_remaining = size_ - pos_; + if (num_bytes > bytes_remaining) { + // The caller is signalled about an exhausted buffer when we return fewer + // bytes than requested. There should not be another read attempt after + // this point. + buf_exhausted_ = true; + num_bytes = bytes_remaining; + } + memcpy(buf, &buf_[pos_], num_bytes); + pos_ += num_bytes; + return num_bytes; + } + + bool SeekForward(uint32_t num_bytes) override { + // Verify we don't try to read outside of a properly sized header. + if (size_ >= kPcmWavHeaderSize) + EXPECT_GE(size_, pos_ + num_bytes); + EXPECT_FALSE(buf_exhausted_); + + const size_t bytes_remaining = size_ - pos_; + if (num_bytes > bytes_remaining) { + // Error: cannot seek beyond EOF. + return false; + } + if (num_bytes == bytes_remaining) { + // There should not be another read attempt after this point. + buf_exhausted_ = true; + } + pos_ += num_bytes; + return true; + } + + int64_t GetPosition() override { return pos_; } + + private: + const uint8_t* buf_; + const size_t size_; + size_t pos_; + bool buf_exhausted_; + const bool check_read_size_; +}; + +// Try various choices of WAV header parameters, and make sure that the good +// ones are accepted and the bad ones rejected. +TEST(WavHeaderTest, CheckWavParameters) { + // Try some really stupid values for one parameter at a time. + EXPECT_TRUE(CheckWavParameters(1, 8000, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(0, 8000, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(0x10000, 8000, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(1, 0, WavFormat::kWavFormatPcm, 0)); + + // Too large values. + EXPECT_FALSE( + CheckWavParameters(1 << 20, 1 << 20, WavFormat::kWavFormatPcm, 0)); + EXPECT_FALSE(CheckWavParameters(1, 8000, WavFormat::kWavFormatPcm, + std::numeric_limits<uint32_t>::max())); + + // Not the same number of samples for each channel. + EXPECT_FALSE(CheckWavParameters(3, 8000, WavFormat::kWavFormatPcm, 5)); +} + +TEST(WavHeaderTest, ReadWavHeaderWithErrors) { + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + + // Test a few ways the header can be invalid. We start with the valid header + // used in WriteAndReadWavHeader, and invalidate one field per test. The + // invalid field is indicated in the array name, and in the comments with + // *BAD*. + { + constexpr uint8_t kBadRiffID[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'i', 'f', 'f', // *BAD* + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadRiffID, sizeof(kBadRiffID), + /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kBadBitsPerSample[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 1, 0, // bits per sample: *BAD* + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadBitsPerSample, sizeof(kBadBitsPerSample), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kBadByteRate[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0x00, 0x33, 0x03, 0, // byte rate: *BAD* + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadByteRate, sizeof(kBadByteRate), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kBadFmtHeaderSize[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 17, 0, 0, 0, // size of fmt block *BAD*. Only 16 and 18 permitted. + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 0, // extra (though invalid) header byte + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), + /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kNonZeroExtensionField[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 18, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + 1, 0, // non-zero extension field *BAD* + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // size of payload: 123457689 + // clang-format on + }; + WavHeaderBufferReader r(kNonZeroExtensionField, + sizeof(kNonZeroExtensionField), + /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kMissingDataChunk[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0xc9, 0x33, 0x03, 0, // byte rate: 1 * 17 * 12345 + 17, 0, // block align: NumChannels * BytesPerSample + 8, 0, // bits per sample: 1 * 8 + // clang-format on + }; + WavHeaderBufferReader r(kMissingDataChunk, sizeof(kMissingDataChunk), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } + { + constexpr uint8_t kMissingFmtAndDataChunks[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + // clang-format on + }; + WavHeaderBufferReader r(kMissingFmtAndDataChunks, + sizeof(kMissingFmtAndDataChunks), + /*check_read_size=*/true); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, + &data_start_pos)); + } +} + +// Try writing and reading a valid WAV header and make sure it looks OK. +TEST(WavHeaderTest, WriteAndReadWavHeader) { + constexpr int kSize = 4 + kPcmWavHeaderSize + 4; + uint8_t buf[kSize]; + size_t header_size; + memset(buf, 0xa4, sizeof(buf)); + WriteWavHeader(17, 12345, WavFormat::kWavFormatPcm, 123457689, buf + 4, + &header_size); + constexpr uint8_t kExpectedBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header + 'R', 'I', 'F', 'F', + 0x56, 0xa1, 0xb7, 0x0e, // size of whole file - 8: 123457689 + 44 - 8 + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // size of fmt block - 8: 24 - 8 + 1, 0, // format: PCM (1) + 17, 0, // channels: 17 + 0x39, 0x30, 0, 0, // sample rate: 12345 + 0x92, 0x67, 0x06, 0, // byte rate: 2 * 17 * 12345 + 34, 0, // block align: NumChannels * BytesPerSample + 16, 0, // bits per sample: 2 * 8 + 'd', 'a', 't', 'a', + 0x32, 0xa1, 0xb7, 0x0e, // size of payload: 2 * 123457689 + 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header + // clang-format on + }; + static_assert(sizeof(kExpectedBuf) == kSize, "buffer size"); + EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize)); + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(buf + 4, sizeof(buf) - 8, + /*check_read_size=*/true); + EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); + EXPECT_EQ(17u, num_channels); + EXPECT_EQ(12345, sample_rate); + EXPECT_EQ(WavFormat::kWavFormatPcm, format); + EXPECT_EQ(2u, bytes_per_sample); + EXPECT_EQ(123457689u, num_samples); +} + +// Try reading an atypical but valid WAV header and make sure it's parsed OK. +TEST(WavHeaderTest, ReadAtypicalWavHeader) { + constexpr uint8_t kBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xbf, 0xd0, 0x5b, 0x07, // Size of whole file - 8 + extra 2 bytes of zero + // extension: 123457689 + 44 - 8 + 2 (atypical). + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 18, 0, 0, 0, // Size of fmt block (with an atypical extension + // size field). + 1, 0, // Format: PCM (1). + 17, 0, // Channels: 17. + 0x39, 0x30, 0, 0, // Sample rate: 12345. + 0xc9, 0x33, 0x03, 0, // Byte rate: 1 * 17 * 12345. + 17, 0, // Block align: NumChannels * BytesPerSample. + 8, 0, // Bits per sample: 1 * 8. + 0, 0, // Zero extension size field (atypical). + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // Size of payload: 123457689. + // clang-format on + }; + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/true); + EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); + EXPECT_EQ(17u, num_channels); + EXPECT_EQ(12345, sample_rate); + EXPECT_EQ(WavFormat::kWavFormatPcm, format); + EXPECT_EQ(1u, bytes_per_sample); + EXPECT_EQ(123457689u, num_samples); +} + +// Try reading a valid WAV header which contains an optional chunk and make sure +// it's parsed OK. +TEST(WavHeaderTest, ReadWavHeaderWithOptionalChunk) { + constexpr uint8_t kBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 0xcd, 0xd0, 0x5b, 0x07, // Size of whole file - 8 + an extra 16 bytes of + // "metadata" (8 bytes header, 16 bytes payload): + // 123457689 + 44 - 8 + 16. + 'W', 'A', 'V', 'E', + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // Size of fmt block. + 1, 0, // Format: PCM (1). + 17, 0, // Channels: 17. + 0x39, 0x30, 0, 0, // Sample rate: 12345. + 0xc9, 0x33, 0x03, 0, // Byte rate: 1 * 17 * 12345. + 17, 0, // Block align: NumChannels * BytesPerSample. + 8, 0, // Bits per sample: 1 * 8. + 'L', 'I', 'S', 'T', // Metadata chunk ID. + 16, 0, 0, 0, // Metadata chunk payload size. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Metadata (16 bytes). + 'd', 'a', 't', 'a', + 0x99, 0xd0, 0x5b, 0x07, // Size of payload: 123457689. + // clang-format on + }; + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/true); + EXPECT_TRUE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); + EXPECT_EQ(17u, num_channels); + EXPECT_EQ(12345, sample_rate); + EXPECT_EQ(WavFormat::kWavFormatPcm, format); + EXPECT_EQ(1u, bytes_per_sample); + EXPECT_EQ(123457689u, num_samples); +} + +// Try reading an invalid WAV header which has the the data chunk before the +// format one and make sure it's not parsed. +TEST(WavHeaderTest, ReadWavHeaderWithDataBeforeFormat) { + constexpr uint8_t kBuf[] = { + // clang-format off + // clang formatting doesn't respect inline comments. + 'R', 'I', 'F', 'F', + 52, 0, 0, 0, // Size of whole file - 8: 16 + 44 - 8. + 'W', 'A', 'V', 'E', + 'd', 'a', 't', 'a', + 16, 0, 0, 0, // Data chunk payload size. + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // Data 16 bytes. + 'f', 'm', 't', ' ', + 16, 0, 0, 0, // Size of fmt block. + 1, 0, // Format: Pcm (1). + 1, 0, // Channels: 1. + 60, 0, 0, 0, // Sample rate: 60. + 60, 0, 0, 0, // Byte rate: 1 * 1 * 60. + 1, 0, // Block align: NumChannels * BytesPerSample. + 8, 0, // Bits per sample: 1 * 8. + // clang-format on + }; + + size_t num_channels = 0; + int sample_rate = 0; + WavFormat format = WavFormat::kWavFormatPcm; + size_t bytes_per_sample = 0; + size_t num_samples = 0; + int64_t data_start_pos = 0; + WavHeaderBufferReader r(kBuf, sizeof(kBuf), /*check_read_size=*/false); + EXPECT_FALSE(ReadWavHeader(&r, &num_channels, &sample_rate, &format, + &bytes_per_sample, &num_samples, &data_start_pos)); +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/window_generator.cc b/third_party/libwebrtc/common_audio/window_generator.cc new file mode 100644 index 0000000000..da5603d9e7 --- /dev/null +++ b/third_party/libwebrtc/common_audio/window_generator.cc @@ -0,0 +1,71 @@ +/* + * 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. + */ + +#define _USE_MATH_DEFINES + +#include "common_audio/window_generator.h" + +#include <cmath> +#include <complex> + +#include "rtc_base/checks.h" + +using std::complex; + +namespace { + +// Modified Bessel function of order 0 for complex inputs. +complex<float> I0(complex<float> x) { + complex<float> y = x / 3.75f; + y *= y; + return 1.0f + y * (3.5156229f + + y * (3.0899424f + + y * (1.2067492f + + y * (0.2659732f + + y * (0.360768e-1f + y * 0.45813e-2f))))); +} + +} // namespace + +namespace webrtc { + +void WindowGenerator::Hanning(int length, float* window) { + RTC_CHECK_GT(length, 1); + RTC_CHECK(window != nullptr); + for (int i = 0; i < length; ++i) { + window[i] = + 0.5f * (1 - cosf(2 * static_cast<float>(M_PI) * i / (length - 1))); + } +} + +void WindowGenerator::KaiserBesselDerived(float alpha, + size_t length, + float* window) { + RTC_CHECK_GT(length, 1U); + RTC_CHECK(window != nullptr); + + const size_t half = (length + 1) / 2; + float sum = 0.0f; + + for (size_t i = 0; i <= half; ++i) { + complex<float> r = (4.0f * i) / length - 1.0f; + sum += I0(static_cast<float>(M_PI) * alpha * sqrt(1.0f - r * r)).real(); + window[i] = sum; + } + for (size_t i = length - 1; i >= half; --i) { + window[length - i - 1] = sqrtf(window[length - i - 1] / sum); + window[i] = window[length - i - 1]; + } + if (length % 2 == 1) { + window[half - 1] = sqrtf(window[half - 1] / sum); + } +} + +} // namespace webrtc diff --git a/third_party/libwebrtc/common_audio/window_generator.h b/third_party/libwebrtc/common_audio/window_generator.h new file mode 100644 index 0000000000..c0a89c4f93 --- /dev/null +++ b/third_party/libwebrtc/common_audio/window_generator.h @@ -0,0 +1,31 @@ +/* + * 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 COMMON_AUDIO_WINDOW_GENERATOR_H_ +#define COMMON_AUDIO_WINDOW_GENERATOR_H_ + +#include <stddef.h> + +namespace webrtc { + +// Helper class with generators for various signal transform windows. +class WindowGenerator { + public: + WindowGenerator() = delete; + WindowGenerator(const WindowGenerator&) = delete; + WindowGenerator& operator=(const WindowGenerator&) = delete; + + static void Hanning(int length, float* window); + static void KaiserBesselDerived(float alpha, size_t length, float* window); +}; + +} // namespace webrtc + +#endif // COMMON_AUDIO_WINDOW_GENERATOR_H_ diff --git a/third_party/libwebrtc/common_audio/window_generator_unittest.cc b/third_party/libwebrtc/common_audio/window_generator_unittest.cc new file mode 100644 index 0000000000..cf339327c6 --- /dev/null +++ b/third_party/libwebrtc/common_audio/window_generator_unittest.cc @@ -0,0 +1,91 @@ +/* + * 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 "common_audio/window_generator.h" + +#include <cstring> + +#include "test/gtest.h" + +namespace webrtc { + +TEST(WindowGeneratorTest, KaiserBesselDerived) { + float window[7]; + + memset(window, 0, sizeof(window)); + + WindowGenerator::KaiserBesselDerived(0.397856f, 2, window); + ASSERT_NEAR(window[0], 0.707106f, 1e-6f); + ASSERT_NEAR(window[1], 0.707106f, 1e-6f); + ASSERT_NEAR(window[2], 0.0f, 1e-6f); + ASSERT_NEAR(window[3], 0.0f, 1e-6f); + ASSERT_NEAR(window[4], 0.0f, 1e-6f); + ASSERT_NEAR(window[5], 0.0f, 1e-6f); + ASSERT_NEAR(window[6], 0.0f, 1e-6f); + + WindowGenerator::KaiserBesselDerived(0.397856f, 3, window); + ASSERT_NEAR(window[0], 0.598066f, 1e-6f); + ASSERT_NEAR(window[1], 0.922358f, 1e-6f); + ASSERT_NEAR(window[2], 0.598066f, 1e-6f); + ASSERT_NEAR(window[3], 0.0f, 1e-6f); + ASSERT_NEAR(window[4], 0.0f, 1e-6f); + ASSERT_NEAR(window[5], 0.0f, 1e-6f); + ASSERT_NEAR(window[6], 0.0f, 1e-6f); + + WindowGenerator::KaiserBesselDerived(0.397856f, 6, window); + ASSERT_NEAR(window[0], 0.458495038865344f, 1e-6f); + ASSERT_NEAR(window[1], 0.707106781186548f, 1e-6f); + ASSERT_NEAR(window[2], 0.888696967101760f, 1e-6f); + ASSERT_NEAR(window[3], 0.888696967101760f, 1e-6f); + ASSERT_NEAR(window[4], 0.707106781186548f, 1e-6f); + ASSERT_NEAR(window[5], 0.458495038865344f, 1e-6f); + ASSERT_NEAR(window[6], 0.0f, 1e-6f); +} + +TEST(WindowGeneratorTest, Hanning) { + float window[7]; + + memset(window, 0, sizeof(window)); + + window[0] = -1.0f; + window[1] = -1.0f; + WindowGenerator::Hanning(2, window); + ASSERT_NEAR(window[0], 0.0f, 1e-6f); + ASSERT_NEAR(window[1], 0.0f, 1e-6f); + ASSERT_NEAR(window[2], 0.0f, 1e-6f); + ASSERT_NEAR(window[3], 0.0f, 1e-6f); + ASSERT_NEAR(window[4], 0.0f, 1e-6f); + ASSERT_NEAR(window[5], 0.0f, 1e-6f); + ASSERT_NEAR(window[6], 0.0f, 1e-6f); + + window[0] = -1.0f; + window[2] = -1.0f; + WindowGenerator::Hanning(3, window); + ASSERT_NEAR(window[0], 0.0f, 1e-6f); + ASSERT_NEAR(window[1], 1.0f, 1e-6f); + ASSERT_NEAR(window[2], 0.0f, 1e-6f); + ASSERT_NEAR(window[3], 0.0f, 1e-6f); + ASSERT_NEAR(window[4], 0.0f, 1e-6f); + ASSERT_NEAR(window[5], 0.0f, 1e-6f); + ASSERT_NEAR(window[6], 0.0f, 1e-6f); + + window[0] = -1.0f; + window[5] = -1.0f; + WindowGenerator::Hanning(6, window); + ASSERT_NEAR(window[0], 0.0f, 1e-6f); + ASSERT_NEAR(window[1], 0.345491f, 1e-6f); + ASSERT_NEAR(window[2], 0.904508f, 1e-6f); + ASSERT_NEAR(window[3], 0.904508f, 1e-6f); + ASSERT_NEAR(window[4], 0.345491f, 1e-6f); + ASSERT_NEAR(window[5], 0.0f, 1e-6f); + ASSERT_NEAR(window[6], 0.0f, 1e-6f); +} + +} // namespace webrtc |