aboutsummaryrefslogtreecommitdiff
path: root/webrtc/common_audio
diff options
context:
space:
mode:
Diffstat (limited to 'webrtc/common_audio')
-rw-r--r--webrtc/common_audio/Android.mk61
-rw-r--r--webrtc/common_audio/BUILD.gn243
-rw-r--r--webrtc/common_audio/OWNERS14
-rw-r--r--webrtc/common_audio/audio_converter.cc200
-rw-r--r--webrtc/common_audio/audio_converter.h66
-rw-r--r--webrtc/common_audio/audio_converter_unittest.cc159
-rw-r--r--webrtc/common_audio/audio_ring_buffer.cc75
-rw-r--r--webrtc/common_audio/audio_ring_buffer.h56
-rw-r--r--webrtc/common_audio/audio_ring_buffer_unittest.cc110
-rw-r--r--webrtc/common_audio/audio_util.cc51
-rw-r--r--webrtc/common_audio/audio_util_unittest.cc231
-rw-r--r--webrtc/common_audio/blocker.cc236
-rw-r--r--webrtc/common_audio/blocker.h123
-rw-r--r--webrtc/common_audio/blocker_unittest.cc342
-rw-r--r--webrtc/common_audio/channel_buffer.cc73
-rw-r--r--webrtc/common_audio/channel_buffer.h169
-rw-r--r--webrtc/common_audio/common_audio.gyp313
-rw-r--r--webrtc/common_audio/common_audio_unittests.isolate23
-rw-r--r--webrtc/common_audio/fft4g.c1332
-rw-r--r--webrtc/common_audio/fft4g.h25
-rw-r--r--webrtc/common_audio/fir_filter.cc116
-rw-r--r--webrtc/common_audio/fir_filter.h40
-rw-r--r--webrtc/common_audio/fir_filter_neon.cc72
-rw-r--r--webrtc/common_audio/fir_filter_neon.h37
-rw-r--r--webrtc/common_audio/fir_filter_sse.cc80
-rw-r--r--webrtc/common_audio/fir_filter_sse.h37
-rw-r--r--webrtc/common_audio/fir_filter_unittest.cc210
-rw-r--r--webrtc/common_audio/include/audio_util.h188
-rw-r--r--webrtc/common_audio/lapped_transform.cc101
-rw-r--r--webrtc/common_audio/lapped_transform.h123
-rw-r--r--webrtc/common_audio/lapped_transform_unittest.cc208
-rw-r--r--webrtc/common_audio/real_fourier.cc57
-rw-r--r--webrtc/common_audio/real_fourier.h75
-rw-r--r--webrtc/common_audio/real_fourier_ooura.cc85
-rw-r--r--webrtc/common_audio/real_fourier_ooura.h45
-rw-r--r--webrtc/common_audio/real_fourier_openmax.cc69
-rw-r--r--webrtc/common_audio/real_fourier_openmax.h44
-rw-r--r--webrtc/common_audio/real_fourier_unittest.cc110
-rw-r--r--webrtc/common_audio/resampler/Android.mk51
-rw-r--r--webrtc/common_audio/resampler/include/push_resampler.h52
-rw-r--r--webrtc/common_audio/resampler/include/resampler.h95
-rw-r--r--webrtc/common_audio/resampler/push_resampler.cc110
-rw-r--r--webrtc/common_audio/resampler/push_resampler_unittest.cc28
-rw-r--r--webrtc/common_audio/resampler/push_sinc_resampler.cc103
-rw-r--r--webrtc/common_audio/resampler/push_sinc_resampler.h76
-rw-r--r--webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc335
-rw-r--r--webrtc/common_audio/resampler/resampler.cc959
-rw-r--r--webrtc/common_audio/resampler/resampler_unittest.cc139
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler.cc378
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler.h170
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler_neon.cc47
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler_sse.cc59
-rw-r--r--webrtc/common_audio/resampler/sinc_resampler_unittest.cc389
-rw-r--r--webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc58
-rw-r--r--webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h55
-rw-r--r--webrtc/common_audio/ring_buffer.c247
-rw-r--r--webrtc/common_audio/ring_buffer.h66
-rw-r--r--webrtc/common_audio/ring_buffer_unittest.cc149
-rw-r--r--webrtc/common_audio/signal_processing/Android.mk104
-rw-r--r--webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c103
-rw-r--r--webrtc/common_audio/signal_processing/auto_correlation.c65
-rw-r--r--webrtc/common_audio/signal_processing/complex_bit_reverse.c108
-rw-r--r--webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S119
-rw-r--r--webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c176
-rw-r--r--webrtc/common_audio/signal_processing/complex_fft.c298
-rw-r--r--webrtc/common_audio/signal_processing/complex_fft_mips.c328
-rw-r--r--webrtc/common_audio/signal_processing/complex_fft_tables.h148
-rw-r--r--webrtc/common_audio/signal_processing/copy_set_operations.c82
-rw-r--r--webrtc/common_audio/signal_processing/cross_correlation.c30
-rw-r--r--webrtc/common_audio/signal_processing/cross_correlation_mips.c104
-rw-r--r--webrtc/common_audio/signal_processing/cross_correlation_neon.c87
-rw-r--r--webrtc/common_audio/signal_processing/division_operations.c138
-rw-r--r--webrtc/common_audio/signal_processing/dot_product_with_scale.c32
-rw-r--r--webrtc/common_audio/signal_processing/downsample_fast.c48
-rw-r--r--webrtc/common_audio/signal_processing/downsample_fast_mips.c169
-rw-r--r--webrtc/common_audio/signal_processing/downsample_fast_neon.c217
-rw-r--r--webrtc/common_audio/signal_processing/energy.c39
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar.c89
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar_fast_q12.c42
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S218
-rw-r--r--webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c140
-rw-r--r--webrtc/common_audio/signal_processing/filter_ma_fast_q12.c45
-rw-r--r--webrtc/common_audio/signal_processing/get_hanning_window.c77
-rw-r--r--webrtc/common_audio/signal_processing/get_scaling_square.c46
-rw-r--r--webrtc/common_audio/signal_processing/ilbc_specific_functions.c90
-rw-r--r--webrtc/common_audio/signal_processing/include/real_fft.h97
-rw-r--r--webrtc/common_audio/signal_processing/include/signal_processing_library.h1645
-rw-r--r--webrtc/common_audio/signal_processing/include/spl_inl.h173
-rw-r--r--webrtc/common_audio/signal_processing/include/spl_inl_armv7.h136
-rw-r--r--webrtc/common_audio/signal_processing/include/spl_inl_mips.h225
-rw-r--r--webrtc/common_audio/signal_processing/levinson_durbin.c246
-rw-r--r--webrtc/common_audio/signal_processing/lpc_to_refl_coef.c56
-rw-r--r--webrtc/common_audio/signal_processing/min_max_operations.c224
-rw-r--r--webrtc/common_audio/signal_processing/min_max_operations_mips.c376
-rw-r--r--webrtc/common_audio/signal_processing/min_max_operations_neon.c283
-rw-r--r--webrtc/common_audio/signal_processing/randomization_functions.c115
-rw-r--r--webrtc/common_audio/signal_processing/real_fft.c102
-rw-r--r--webrtc/common_audio/signal_processing/real_fft_unittest.cc108
-rw-r--r--webrtc/common_audio/signal_processing/refl_coef_to_lpc.c59
-rw-r--r--webrtc/common_audio/signal_processing/resample.c505
-rw-r--r--webrtc/common_audio/signal_processing/resample_48khz.c186
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2.c183
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2_internal.c679
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2_internal.h47
-rw-r--r--webrtc/common_audio/signal_processing/resample_by_2_mips.c290
-rw-r--r--webrtc/common_audio/signal_processing/resample_fractional.c239
-rw-r--r--webrtc/common_audio/signal_processing/signal_processing_unittest.cc579
-rw-r--r--webrtc/common_audio/signal_processing/spl_init.c140
-rw-r--r--webrtc/common_audio/signal_processing/spl_sqrt.c184
-rw-r--r--webrtc/common_audio/signal_processing/spl_sqrt_floor.c77
-rw-r--r--webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S110
-rw-r--r--webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c207
-rw-r--r--webrtc/common_audio/signal_processing/splitting_filter.c208
-rw-r--r--webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c35
-rw-r--r--webrtc/common_audio/signal_processing/vector_scaling_operations.c165
-rw-r--r--webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c57
-rw-r--r--webrtc/common_audio/sparse_fir_filter.cc60
-rw-r--r--webrtc/common_audio/sparse_fir_filter.h52
-rw-r--r--webrtc/common_audio/sparse_fir_filter_unittest.cc231
-rw-r--r--webrtc/common_audio/vad/Android.mk48
-rw-r--r--webrtc/common_audio/vad/include/vad.h50
-rw-r--r--webrtc/common_audio/vad/include/webrtc_vad.h86
-rw-r--r--webrtc/common_audio/vad/mock/mock_vad.h34
-rw-r--r--webrtc/common_audio/vad/vad.cc63
-rw-r--r--webrtc/common_audio/vad/vad_core.c676
-rw-r--r--webrtc/common_audio/vad/vad_core.h115
-rw-r--r--webrtc/common_audio/vad/vad_core_unittest.cc105
-rw-r--r--webrtc/common_audio/vad/vad_filterbank.c331
-rw-r--r--webrtc/common_audio/vad/vad_filterbank.h44
-rw-r--r--webrtc/common_audio/vad/vad_filterbank_unittest.cc92
-rw-r--r--webrtc/common_audio/vad/vad_gmm.c83
-rw-r--r--webrtc/common_audio/vad/vad_gmm.h39
-rw-r--r--webrtc/common_audio/vad/vad_gmm_unittest.cc43
-rw-r--r--webrtc/common_audio/vad/vad_sp.c178
-rw-r--r--webrtc/common_audio/vad/vad_sp.h56
-rw-r--r--webrtc/common_audio/vad/vad_sp_unittest.cc74
-rw-r--r--webrtc/common_audio/vad/vad_unittest.cc156
-rw-r--r--webrtc/common_audio/vad/vad_unittest.h48
-rw-r--r--webrtc/common_audio/vad/webrtc_vad.c116
-rw-r--r--webrtc/common_audio/wav_file.cc174
-rw-r--r--webrtc/common_audio/wav_file.h115
-rw-r--r--webrtc/common_audio/wav_file_unittest.cc177
-rw-r--r--webrtc/common_audio/wav_header.cc242
-rw-r--r--webrtc/common_audio/wav_header.h64
-rw-r--r--webrtc/common_audio/wav_header_unittest.cc323
-rw-r--r--webrtc/common_audio/window_generator.cc72
-rw-r--r--webrtc/common_audio/window_generator.h33
-rw-r--r--webrtc/common_audio/window_generator_unittest.cc92
148 files changed, 24115 insertions, 0 deletions
diff --git a/webrtc/common_audio/Android.mk b/webrtc/common_audio/Android.mk
new file mode 100644
index 0000000000..9e62684ba9
--- /dev/null
+++ b/webrtc/common_audio/Android.mk
@@ -0,0 +1,61 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(LOCAL_PATH)/../../android-webrtc.mk
+
+LOCAL_ARM_MODE := arm
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := libwebrtc_common
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+ audio_converter.cc \
+ audio_util.cc \
+ blocker.cc \
+ channel_buffer.cc \
+ fft4g.c \
+ fir_filter.cc \
+ lapped_transform.cc \
+ real_fourier_ooura.cc \
+ real_fourier.cc \
+ ring_buffer.c \
+ audio_ring_buffer.cc \
+ sparse_fir_filter.cc \
+ window_generator.cc \
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH),x86 x86_64))
+LOCAL_SRC_FILES += fir_filter_sse.cc
+endif
+
+# Flags passed to both C and C++ files.
+LOCAL_CFLAGS := \
+ $(MY_WEBRTC_COMMON_DEFS)
+
+LOCAL_CFLAGS_arm := $(MY_WEBRTC_COMMON_DEFS_arm)
+LOCAL_CFLAGS_x86 := $(MY_WEBRTC_COMMON_DEFS_x86)
+LOCAL_CFLAGS_mips := $(MY_WEBRTC_COMMON_DEFS_mips)
+LOCAL_CFLAGS_arm64 := $(MY_WEBRTC_COMMON_DEFS_arm64)
+LOCAL_CFLAGS_x86_64 := $(MY_WEBRTC_COMMON_DEFS_x86_64)
+LOCAL_CFLAGS_mips64 := $(MY_WEBRTC_COMMON_DEFS_mips64)
+
+# Include paths placed before CFLAGS/CPPFLAGS
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../.. \
+
+ifdef WEBRTC_STL
+LOCAL_NDK_STL_VARIANT := $(WEBRTC_STL)
+LOCAL_SDK_VERSION := 14
+LOCAL_MODULE := $(LOCAL_MODULE)_$(WEBRTC_STL)
+endif
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc/common_audio/BUILD.gn b/webrtc/common_audio/BUILD.gn
new file mode 100644
index 0000000000..b01b31816b
--- /dev/null
+++ b/webrtc/common_audio/BUILD.gn
@@ -0,0 +1,243 @@
+# 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("//build/config/arm.gni")
+import("../build/webrtc.gni")
+
+config("common_audio_config") {
+ include_dirs = [
+ "resampler/include",
+ "signal_processing/include",
+ "vad/include",
+ ]
+}
+
+source_set("common_audio") {
+ sources = [
+ "audio_converter.cc",
+ "audio_converter.h",
+ "audio_ring_buffer.cc",
+ "audio_ring_buffer.h",
+ "audio_util.cc",
+ "blocker.cc",
+ "blocker.h",
+ "channel_buffer.cc",
+ "channel_buffer.h",
+ "fft4g.c",
+ "fft4g.h",
+ "fir_filter.cc",
+ "fir_filter.h",
+ "fir_filter_neon.h",
+ "fir_filter_sse.h",
+ "include/audio_util.h",
+ "lapped_transform.cc",
+ "lapped_transform.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",
+ "resampler/sinc_resampler.h",
+ "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/dot_product_with_scale.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/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_sqrt.c",
+ "signal_processing/splitting_filter.c",
+ "signal_processing/sqrt_of_one_minus_x_squared.c",
+ "signal_processing/vector_scaling_operations.c",
+ "sparse_fir_filter.cc",
+ "sparse_fir_filter.h",
+ "vad/include/vad.h",
+ "vad/include/webrtc_vad.h",
+ "vad/vad.cc",
+ "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",
+ "wav_file.cc",
+ "wav_file.h",
+ "wav_header.cc",
+ "wav_header.h",
+ "window_generator.cc",
+ "window_generator.h",
+ ]
+
+ deps = [
+ "../system_wrappers",
+ ]
+
+ defines = []
+ if (rtc_use_openmax_dl) {
+ sources += [
+ "real_fourier_openmax.cc",
+ "real_fourier_openmax.h",
+ ]
+ defines += [ "RTC_USE_OPENMAX_DL" ]
+ if (rtc_build_openmax_dl) {
+ deps += [ "//third_party/openmax_dl/dl" ]
+ }
+ }
+
+ if (current_cpu == "arm") {
+ sources += [
+ "signal_processing/complex_bit_reverse_arm.S",
+ "signal_processing/spl_sqrt_floor_arm.S",
+ ]
+
+ if (arm_version >= 7) {
+ sources += [ "signal_processing/filter_ar_fast_q12_armv7.S" ]
+ } else {
+ sources += [ "signal_processing/filter_ar_fast_q12.c" ]
+ }
+ }
+
+ if (rtc_build_with_neon) {
+ deps += [ ":common_audio_neon" ]
+ }
+
+ if (current_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",
+ "signal_processing/spl_sqrt_floor_mips.c",
+ ]
+ if (mips_dsp_rev > 0) {
+ sources += [ "signal_processing/vector_scaling_operations_mips.c" ]
+ }
+ } else {
+ sources += [ "signal_processing/complex_fft.c" ]
+ }
+
+ if (current_cpu != "arm" && current_cpu != "mipsel") {
+ sources += [
+ "signal_processing/complex_bit_reverse.c",
+ "signal_processing/filter_ar_fast_q12.c",
+ "signal_processing/spl_sqrt_floor.c",
+ ]
+ }
+
+ if (is_win) {
+ cflags = [ "/wd4334" ] # Ignore warning on shift operator promotion.
+ }
+
+ configs += [ "..:common_config" ]
+
+ public_configs = [
+ "..:common_inherited_config",
+ ":common_audio_config",
+ ]
+
+ if (is_clang) {
+ # Suppress warnings from Chrome's Clang plugins.
+ # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
+ configs -= [ "//build/config/clang:find_bad_constructs" ]
+ }
+
+ if (current_cpu == "x86" || current_cpu == "x64") {
+ deps += [ ":common_audio_sse2" ]
+ }
+}
+
+if (current_cpu == "x86" || current_cpu == "x64") {
+ source_set("common_audio_sse2") {
+ sources = [
+ "fir_filter_sse.cc",
+ "resampler/sinc_resampler_sse.cc",
+ ]
+
+ if (is_posix) {
+ cflags = [ "-msse2" ]
+ }
+
+ configs += [ "..:common_inherited_config" ]
+
+ if (is_clang) {
+ # Suppress warnings from Chrome's Clang plugins.
+ # See http://code.google.com/p/webrtc/issues/detail?id=163 for details.
+ configs -= [ "//build/config/clang:find_bad_constructs" ]
+ }
+ }
+}
+
+if (rtc_build_with_neon) {
+ source_set("common_audio_neon") {
+ sources = [
+ "fir_filter_neon.cc",
+ "resampler/sinc_resampler_neon.cc",
+ "signal_processing/cross_correlation_neon.c",
+ "signal_processing/downsample_fast_neon.c",
+ "signal_processing/min_max_operations_neon.c",
+ ]
+
+ if (current_cpu != "arm64") {
+ # Enable compilation for the NEON instruction set. This is needed
+ # since //build/config/arm.gni only enables NEON for iOS, not Android.
+ # This provides the same functionality as webrtc/build/arm_neon.gypi.
+ configs -= [ "//build/config/compiler:compiler_arm_fpu" ]
+ cflags = [ "-mfpu=neon" ]
+ }
+
+ # Disable LTO on NEON targets due to compiler bug.
+ # TODO(fdegans): Enable this. See crbug.com/408997.
+ if (rtc_use_lto) {
+ cflags -= [
+ "-flto",
+ "-ffat-lto-objects",
+ ]
+ }
+
+ configs += [ "..:common_config" ]
+ public_configs = [ "..:common_inherited_config" ]
+ }
+}
diff --git a/webrtc/common_audio/OWNERS b/webrtc/common_audio/OWNERS
new file mode 100644
index 0000000000..20f640041e
--- /dev/null
+++ b/webrtc/common_audio/OWNERS
@@ -0,0 +1,14 @@
+andrew@webrtc.org
+henrik.lundin@webrtc.org
+jan.skoglund@webrtc.org
+kwiberg@webrtc.org
+tina.legrand@webrtc.org
+
+per-file *.isolate=kjellander@webrtc.org
+
+# These are for the common case of adding or renaming files. If you're doing
+# structural changes, please get a review from a reviewer in this file.
+per-file *.gyp=*
+per-file *.gypi=*
+
+per-file BUILD.gn=kjellander@webrtc.org
diff --git a/webrtc/common_audio/audio_converter.cc b/webrtc/common_audio/audio_converter.cc
new file mode 100644
index 0000000000..f1709ae653
--- /dev/null
+++ b/webrtc/common_audio/audio_converter.cc
@@ -0,0 +1,200 @@
+/*
+ * 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 "webrtc/common_audio/audio_converter.h"
+
+#include <cstring>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/common_audio/channel_buffer.h"
+#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
+#include "webrtc/system_wrappers/include/scoped_vector.h"
+
+using rtc::checked_cast;
+
+namespace webrtc {
+
+class CopyConverter : public AudioConverter {
+ public:
+ CopyConverter(int src_channels, size_t src_frames, int 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 (int i = 0; i < src_channels(); ++i)
+ std::memcpy(dst[i], src[i], dst_frames() * sizeof(*dst[i]));
+ }
+ }
+};
+
+class UpmixConverter : public AudioConverter {
+ public:
+ UpmixConverter(int src_channels, size_t src_frames, int 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 (int j = 0; j < dst_channels(); ++j)
+ dst[j][i] = value;
+ }
+ }
+};
+
+class DownmixConverter : public AudioConverter {
+ public:
+ DownmixConverter(int src_channels, size_t src_frames, int 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 (int j = 0; j < src_channels(); ++j)
+ sum += src[j][i];
+ dst_mono[i] = sum / src_channels();
+ }
+ }
+};
+
+class ResampleConverter : public AudioConverter {
+ public:
+ ResampleConverter(int src_channels, size_t src_frames, int dst_channels,
+ size_t dst_frames)
+ : AudioConverter(src_channels, src_frames, dst_channels, dst_frames) {
+ resamplers_.reserve(src_channels);
+ for (int i = 0; i < src_channels; ++i)
+ resamplers_.push_back(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:
+ ScopedVector<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:
+ CompositionConverter(ScopedVector<AudioConverter> converters)
+ : converters_(converters.Pass()) {
+ RTC_CHECK_GE(converters_.size(), 2u);
+ // We need an intermediate buffer after every converter.
+ for (auto it = converters_.begin(); it != converters_.end() - 1; ++it)
+ buffers_.push_back(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:
+ ScopedVector<AudioConverter> converters_;
+ ScopedVector<ChannelBuffer<float>> buffers_;
+};
+
+rtc::scoped_ptr<AudioConverter> AudioConverter::Create(int src_channels,
+ size_t src_frames,
+ int dst_channels,
+ size_t dst_frames) {
+ rtc::scoped_ptr<AudioConverter> sp;
+ if (src_channels > dst_channels) {
+ if (src_frames != dst_frames) {
+ ScopedVector<AudioConverter> converters;
+ converters.push_back(new DownmixConverter(src_channels, src_frames,
+ dst_channels, src_frames));
+ converters.push_back(new ResampleConverter(dst_channels, src_frames,
+ dst_channels, dst_frames));
+ sp.reset(new CompositionConverter(converters.Pass()));
+ } else {
+ sp.reset(new DownmixConverter(src_channels, src_frames, dst_channels,
+ dst_frames));
+ }
+ } else if (src_channels < dst_channels) {
+ if (src_frames != dst_frames) {
+ ScopedVector<AudioConverter> converters;
+ converters.push_back(new ResampleConverter(src_channels, src_frames,
+ src_channels, dst_frames));
+ converters.push_back(new UpmixConverter(src_channels, dst_frames,
+ dst_channels, dst_frames));
+ sp.reset(new CompositionConverter(converters.Pass()));
+ } 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.Pass();
+}
+
+// For CompositionConverter.
+AudioConverter::AudioConverter()
+ : src_channels_(0),
+ src_frames_(0),
+ dst_channels_(0),
+ dst_frames_(0) {}
+
+AudioConverter::AudioConverter(int src_channels, size_t src_frames,
+ int 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/webrtc/common_audio/audio_converter.h b/webrtc/common_audio/audio_converter.h
new file mode 100644
index 0000000000..7d1513bc02
--- /dev/null
+++ b/webrtc/common_audio/audio_converter.h
@@ -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.
+ */
+
+#ifndef WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
+#define WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/base/scoped_ptr.h"
+
+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 rtc::scoped_ptr<AudioConverter> Create(int src_channels,
+ size_t src_frames,
+ int dst_channels,
+ size_t dst_frames);
+ virtual ~AudioConverter() {};
+
+ // 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;
+
+ int src_channels() const { return src_channels_; }
+ size_t src_frames() const { return src_frames_; }
+ int dst_channels() const { return dst_channels_; }
+ size_t dst_frames() const { return dst_frames_; }
+
+ protected:
+ AudioConverter();
+ AudioConverter(int src_channels, size_t src_frames, int 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 int src_channels_;
+ const size_t src_frames_;
+ const int dst_channels_;
+ const size_t dst_frames_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(AudioConverter);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_AUDIO_CONVERTER_H_
diff --git a/webrtc/common_audio/audio_converter_unittest.cc b/webrtc/common_audio/audio_converter_unittest.cc
new file mode 100644
index 0000000000..c85b96e285
--- /dev/null
+++ b/webrtc/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 <cmath>
+#include <algorithm>
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/format_macros.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/audio_converter.h"
+#include "webrtc/common_audio/channel_buffer.h"
+#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
+
+namespace webrtc {
+
+typedef rtc::scoped_ptr<ChannelBuffer<float>> ScopedBuffer;
+
+// Sets the signal value to increase by |data| with every sample.
+ScopedBuffer CreateBuffer(const std::vector<float>& data, int frames) {
+ const int num_channels = static_cast<int>(data.size());
+ ScopedBuffer sb(new ChannelBuffer<float>(frames, num_channels));
+ for (int i = 0; i < num_channels; ++i)
+ for (int 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 (int 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=%" PRIuS "\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(int src_channels,
+ int src_sample_rate_hz,
+ int 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 int src_frames = src_sample_rate_hz / 100;
+ const int dst_frames = 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);
+ printf("(%d, %d Hz) -> (%d, %d Hz) ", // SNR reported on the same line later.
+ src_channels, src_sample_rate_hz, dst_channels, dst_sample_rate_hz);
+
+ rtc::scoped_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, 16000, 32000, 44100, 48000};
+ const int kSampleRatesSize = sizeof(kSampleRates) / sizeof(*kSampleRates);
+ const int kChannels[] = {1, 2};
+ const int kChannelsSize = sizeof(kChannels) / sizeof(*kChannels);
+ for (int src_rate = 0; src_rate < kSampleRatesSize; ++src_rate) {
+ for (int dst_rate = 0; dst_rate < kSampleRatesSize; ++dst_rate) {
+ for (int src_channel = 0; src_channel < kChannelsSize; ++src_channel) {
+ for (int dst_channel = 0; dst_channel < kChannelsSize; ++dst_channel) {
+ RunAudioConverterTest(kChannels[src_channel], kSampleRates[src_rate],
+ kChannels[dst_channel], kSampleRates[dst_rate]);
+ }
+ }
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/audio_ring_buffer.cc b/webrtc/common_audio/audio_ring_buffer.cc
new file mode 100644
index 0000000000..a29e53a61c
--- /dev/null
+++ b/webrtc/common_audio/audio_ring_buffer.cc
@@ -0,0 +1,75 @@
+/*
+ * 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 "webrtc/common_audio/audio_ring_buffer.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/ring_buffer.h"
+
+// This is a simple multi-channel wrapper over the ring_buffer.h C interface.
+
+namespace webrtc {
+
+AudioRingBuffer::AudioRingBuffer(size_t channels, size_t max_frames) {
+ buffers_.reserve(channels);
+ for (size_t i = 0; i < channels; ++i)
+ buffers_.push_back(WebRtc_CreateBuffer(max_frames, sizeof(float)));
+}
+
+AudioRingBuffer::~AudioRingBuffer() {
+ for (auto buf : buffers_)
+ WebRtc_FreeBuffer(buf);
+}
+
+void AudioRingBuffer::Write(const float* const* data, size_t channels,
+ size_t frames) {
+ RTC_DCHECK_EQ(buffers_.size(), channels);
+ for (size_t i = 0; i < channels; ++i) {
+ const size_t written = WebRtc_WriteBuffer(buffers_[i], data[i], frames);
+ RTC_CHECK_EQ(written, frames);
+ }
+}
+
+void AudioRingBuffer::Read(float* const* data, size_t channels, size_t frames) {
+ RTC_DCHECK_EQ(buffers_.size(), channels);
+ for (size_t i = 0; i < channels; ++i) {
+ const size_t read =
+ WebRtc_ReadBuffer(buffers_[i], nullptr, data[i], frames);
+ RTC_CHECK_EQ(read, frames);
+ }
+}
+
+size_t AudioRingBuffer::ReadFramesAvailable() const {
+ // All buffers have the same amount available.
+ return WebRtc_available_read(buffers_[0]);
+}
+
+size_t AudioRingBuffer::WriteFramesAvailable() const {
+ // All buffers have the same amount available.
+ return WebRtc_available_write(buffers_[0]);
+}
+
+void AudioRingBuffer::MoveReadPositionForward(size_t frames) {
+ for (auto buf : buffers_) {
+ const size_t moved =
+ static_cast<size_t>(WebRtc_MoveReadPtr(buf, static_cast<int>(frames)));
+ RTC_CHECK_EQ(moved, frames);
+ }
+}
+
+void AudioRingBuffer::MoveReadPositionBackward(size_t frames) {
+ for (auto buf : buffers_) {
+ const size_t moved = static_cast<size_t>(
+ -WebRtc_MoveReadPtr(buf, -static_cast<int>(frames)));
+ RTC_CHECK_EQ(moved, frames);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/audio_ring_buffer.h b/webrtc/common_audio/audio_ring_buffer.h
new file mode 100644
index 0000000000..58e543adea
--- /dev/null
+++ b/webrtc/common_audio/audio_ring_buffer.h
@@ -0,0 +1,56 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_AUDIO_RING_BUFFER_H_
+#define WEBRTC_COMMON_AUDIO_AUDIO_RING_BUFFER_H_
+
+#include <stddef.h>
+#include <vector>
+
+struct RingBuffer;
+
+namespace webrtc {
+
+// A ring buffer tailored for float deinterleaved audio. Any operation that
+// cannot be performed as requested will cause a crash (e.g. insufficient data
+// in the buffer to fulfill a read request.)
+class AudioRingBuffer final {
+ public:
+ // Specify the number of channels and maximum number of frames the buffer will
+ // contain.
+ AudioRingBuffer(size_t channels, size_t max_frames);
+ ~AudioRingBuffer();
+
+ // Copies |data| to the buffer and advances the write pointer. |channels| must
+ // be the same as at creation time.
+ void Write(const float* const* data, size_t channels, size_t frames);
+
+ // Copies from the buffer to |data| and advances the read pointer. |channels|
+ // must be the same as at creation time.
+ void Read(float* const* data, size_t channels, size_t frames);
+
+ size_t ReadFramesAvailable() const;
+ size_t WriteFramesAvailable() const;
+
+ // Moves the read position. The forward version advances the read pointer
+ // towards the write pointer and the backward verison withdraws the read
+ // pointer away from the write pointer (i.e. flushing and stuffing the buffer
+ // respectively.)
+ void MoveReadPositionForward(size_t frames);
+ void MoveReadPositionBackward(size_t frames);
+
+ private:
+ // We don't use a ScopedVector because it doesn't support a specialized
+ // deleter (like scoped_ptr for instance.)
+ std::vector<RingBuffer*> buffers_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_AUDIO_RING_BUFFER_H_
diff --git a/webrtc/common_audio/audio_ring_buffer_unittest.cc b/webrtc/common_audio/audio_ring_buffer_unittest.cc
new file mode 100644
index 0000000000..a7a6a9442b
--- /dev/null
+++ b/webrtc/common_audio/audio_ring_buffer_unittest.cc
@@ -0,0 +1,110 @@
+/*
+ * 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 "webrtc/common_audio/audio_ring_buffer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/channel_buffer.h"
+
+namespace webrtc {
+
+class AudioRingBufferTest :
+ public ::testing::TestWithParam< ::testing::tuple<int, int, int, int> > {
+};
+
+void ReadAndWriteTest(const ChannelBuffer<float>& input,
+ size_t num_write_chunk_frames,
+ size_t num_read_chunk_frames,
+ size_t buffer_frames,
+ ChannelBuffer<float>* output) {
+ const size_t num_channels = input.num_channels();
+ const size_t total_frames = input.num_frames();
+ AudioRingBuffer buf(num_channels, buffer_frames);
+ rtc::scoped_ptr<float* []> slice(new float* [num_channels]);
+
+ size_t input_pos = 0;
+ size_t output_pos = 0;
+ while (input_pos + buf.WriteFramesAvailable() < total_frames) {
+ // Write until the buffer is as full as possible.
+ while (buf.WriteFramesAvailable() >= num_write_chunk_frames) {
+ buf.Write(input.Slice(slice.get(), input_pos), num_channels,
+ num_write_chunk_frames);
+ input_pos += num_write_chunk_frames;
+ }
+ // Read until the buffer is as empty as possible.
+ while (buf.ReadFramesAvailable() >= num_read_chunk_frames) {
+ EXPECT_LT(output_pos, total_frames);
+ buf.Read(output->Slice(slice.get(), output_pos), num_channels,
+ num_read_chunk_frames);
+ output_pos += num_read_chunk_frames;
+ }
+ }
+
+ // Write and read the last bit.
+ if (input_pos < total_frames) {
+ buf.Write(input.Slice(slice.get(), input_pos), num_channels,
+ total_frames - input_pos);
+ }
+ if (buf.ReadFramesAvailable()) {
+ buf.Read(output->Slice(slice.get(), output_pos), num_channels,
+ buf.ReadFramesAvailable());
+ }
+ EXPECT_EQ(0u, buf.ReadFramesAvailable());
+}
+
+TEST_P(AudioRingBufferTest, ReadDataMatchesWrittenData) {
+ const size_t kFrames = 5000;
+ const size_t num_channels = ::testing::get<3>(GetParam());
+
+ // Initialize the input data to an increasing sequence.
+ ChannelBuffer<float> input(kFrames, static_cast<int>(num_channels));
+ for (size_t i = 0; i < num_channels; ++i)
+ for (size_t j = 0; j < kFrames; ++j)
+ input.channels()[i][j] = (i + 1) * (j + 1);
+
+ ChannelBuffer<float> output(kFrames, static_cast<int>(num_channels));
+ ReadAndWriteTest(input,
+ ::testing::get<0>(GetParam()),
+ ::testing::get<1>(GetParam()),
+ ::testing::get<2>(GetParam()),
+ &output);
+
+ // Verify the read data matches the input.
+ for (size_t i = 0; i < num_channels; ++i)
+ for (size_t j = 0; j < kFrames; ++j)
+ EXPECT_EQ(input.channels()[i][j], output.channels()[i][j]);
+}
+
+INSTANTIATE_TEST_CASE_P(
+ AudioRingBufferTest, AudioRingBufferTest,
+ ::testing::Combine(::testing::Values(10, 20, 42), // num_write_chunk_frames
+ ::testing::Values(1, 10, 17), // num_read_chunk_frames
+ ::testing::Values(100, 256), // buffer_frames
+ ::testing::Values(1, 4))); // num_channels
+
+TEST_F(AudioRingBufferTest, MoveReadPosition) {
+ const size_t kNumChannels = 1;
+ const float kInputArray[] = {1, 2, 3, 4};
+ const size_t kNumFrames = sizeof(kInputArray) / sizeof(*kInputArray);
+ ChannelBuffer<float> input(kNumFrames, kNumChannels);
+ input.SetDataForTesting(kInputArray, kNumFrames);
+ AudioRingBuffer buf(kNumChannels, kNumFrames);
+ buf.Write(input.channels(), kNumChannels, kNumFrames);
+
+ buf.MoveReadPositionForward(3);
+ ChannelBuffer<float> output(1, kNumChannels);
+ buf.Read(output.channels(), kNumChannels, 1);
+ EXPECT_EQ(4, output.channels()[0][0]);
+ buf.MoveReadPositionBackward(3);
+ buf.Read(output.channels(), kNumChannels, 1);
+ EXPECT_EQ(2, output.channels()[0][0]);
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/audio_util.cc b/webrtc/common_audio/audio_util.cc
new file mode 100644
index 0000000000..2ce2eba994
--- /dev/null
+++ b/webrtc/common_audio/audio_util.cc
@@ -0,0 +1,51 @@
+/*
+ * 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 "webrtc/common_audio/include/audio_util.h"
+
+#include "webrtc/typedefs.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 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/webrtc/common_audio/audio_util_unittest.cc b/webrtc/common_audio/audio_util_unittest.cc
new file mode 100644
index 0000000000..5583778b28
--- /dev/null
+++ b/webrtc/common_audio/audio_util_unittest.cc
@@ -0,0 +1,231 @@
+/*
+ * 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 "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/include/audio_util.h"
+#include "webrtc/typedefs.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_FLOAT_EQ(ref[i], test[i]);
+ }
+}
+
+TEST(AudioUtilTest, FloatToS16) {
+ const size_t kSize = 9;
+ const float kInput[kSize] = {0.f,
+ 0.4f / 32767.f,
+ 0.6f / 32767.f,
+ -0.4f / 32768.f,
+ -0.6f / 32768.f,
+ 1.f,
+ -1.f,
+ 1.1f,
+ -1.1f};
+ const int16_t kReference[kSize] = {0, 0, 1, 0, -1,
+ 32767, -32768, 32767, -32768};
+ int16_t output[kSize];
+ FloatToS16(kInput, kSize, output);
+ ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, S16ToFloat) {
+ const size_t kSize = 7;
+ const int16_t kInput[kSize] = {0, 1, -1, 16384, -16384, 32767, -32768};
+ const float kReference[kSize] = {
+ 0.f, 1.f / 32767.f, -1.f / 32768.f, 16384.f / 32767.f, -0.5f, 1.f, -1.f};
+ float output[kSize];
+ S16ToFloat(kInput, kSize, output);
+ ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, FloatS16ToS16) {
+ const size_t kSize = 7;
+ const float kInput[kSize] = {0.f, 0.4f, 0.5f, -0.4f,
+ -0.5f, 32768.f, -32769.f};
+ const int16_t kReference[kSize] = {0, 0, 1, 0, -1, 32767, -32768};
+ int16_t output[kSize];
+ FloatS16ToS16(kInput, kSize, output);
+ ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, FloatToFloatS16) {
+ const size_t kSize = 9;
+ const float kInput[kSize] = {0.f,
+ 0.4f / 32767.f,
+ 0.6f / 32767.f,
+ -0.4f / 32768.f,
+ -0.6f / 32768.f,
+ 1.f,
+ -1.f,
+ 1.1f,
+ -1.1f};
+ const float kReference[kSize] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f,
+ 32767.f, -32768.f, 36043.7f, -36044.8f};
+ float output[kSize];
+ FloatToFloatS16(kInput, kSize, output);
+ ExpectArraysEq(kReference, output, kSize);
+}
+
+TEST(AudioUtilTest, FloatS16ToFloat) {
+ const size_t kSize = 9;
+ const float kInput[kSize] = {0.f, 0.4f, 0.6f, -0.4f, -0.6f,
+ 32767.f, -32768.f, 36043.7f, -36044.8f};
+ const float kReference[kSize] = {0.f,
+ 0.4f / 32767.f,
+ 0.6f / 32767.f,
+ -0.4f / 32768.f,
+ -0.6f / 32768.f,
+ 1.f,
+ -1.f,
+ 1.1f,
+ -1.1f};
+ float output[kSize];
+ FloatS16ToFloat(kInput, kSize, output);
+ 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/webrtc/common_audio/blocker.cc b/webrtc/common_audio/blocker.cc
new file mode 100644
index 0000000000..0133550beb
--- /dev/null
+++ b/webrtc/common_audio/blocker.cc
@@ -0,0 +1,236 @@
+/*
+ * 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 "webrtc/common_audio/blocker.h"
+
+#include <string.h>
+
+#include "webrtc/base/checks.h"
+
+namespace {
+
+// Adds |a| and |b| frame by frame into |result| (basically matrix addition).
+void AddFrames(const float* const* a,
+ size_t a_start_index,
+ const float* const* b,
+ int b_start_index,
+ size_t num_frames,
+ int num_channels,
+ float* const* result,
+ size_t result_start_index) {
+ for (int i = 0; i < num_channels; ++i) {
+ for (size_t j = 0; j < num_frames; ++j) {
+ result[i][j + result_start_index] =
+ a[i][j + a_start_index] + b[i][j + b_start_index];
+ }
+ }
+}
+
+// Copies |src| into |dst| channel by channel.
+void CopyFrames(const float* const* src,
+ size_t src_start_index,
+ size_t num_frames,
+ int num_channels,
+ float* const* dst,
+ size_t dst_start_index) {
+ for (int i = 0; i < num_channels; ++i) {
+ memcpy(&dst[i][dst_start_index],
+ &src[i][src_start_index],
+ num_frames * sizeof(dst[i][dst_start_index]));
+ }
+}
+
+// Moves |src| into |dst| channel by channel.
+void MoveFrames(const float* const* src,
+ size_t src_start_index,
+ size_t num_frames,
+ int num_channels,
+ float* const* dst,
+ size_t dst_start_index) {
+ for (int i = 0; i < num_channels; ++i) {
+ memmove(&dst[i][dst_start_index],
+ &src[i][src_start_index],
+ num_frames * sizeof(dst[i][dst_start_index]));
+ }
+}
+
+void ZeroOut(float* const* buffer,
+ size_t starting_idx,
+ size_t num_frames,
+ int num_channels) {
+ for (int i = 0; i < num_channels; ++i) {
+ memset(&buffer[i][starting_idx], 0,
+ num_frames * sizeof(buffer[i][starting_idx]));
+ }
+}
+
+// Pointwise multiplies each channel of |frames| with |window|. Results are
+// stored in |frames|.
+void ApplyWindow(const float* window,
+ size_t num_frames,
+ int num_channels,
+ float* const* frames) {
+ for (int i = 0; i < num_channels; ++i) {
+ for (size_t j = 0; j < num_frames; ++j) {
+ frames[i][j] = frames[i][j] * window[j];
+ }
+ }
+}
+
+size_t gcd(size_t a, size_t b) {
+ size_t tmp;
+ while (b) {
+ tmp = a;
+ a = b;
+ b = tmp % b;
+ }
+ return a;
+}
+
+} // namespace
+
+namespace webrtc {
+
+Blocker::Blocker(size_t chunk_size,
+ size_t block_size,
+ int num_input_channels,
+ int num_output_channels,
+ const float* window,
+ size_t shift_amount,
+ BlockerCallback* callback)
+ : chunk_size_(chunk_size),
+ block_size_(block_size),
+ num_input_channels_(num_input_channels),
+ num_output_channels_(num_output_channels),
+ initial_delay_(block_size_ - gcd(chunk_size, shift_amount)),
+ frame_offset_(0),
+ input_buffer_(num_input_channels_, chunk_size_ + initial_delay_),
+ output_buffer_(chunk_size_ + initial_delay_, num_output_channels_),
+ input_block_(block_size_, num_input_channels_),
+ output_block_(block_size_, num_output_channels_),
+ window_(new float[block_size_]),
+ shift_amount_(shift_amount),
+ callback_(callback) {
+ RTC_CHECK_LE(num_output_channels_, num_input_channels_);
+ RTC_CHECK_LE(shift_amount_, block_size_);
+
+ memcpy(window_.get(), window, block_size_ * sizeof(*window_.get()));
+ input_buffer_.MoveReadPositionBackward(initial_delay_);
+}
+
+// When block_size < chunk_size the input and output buffers look like this:
+//
+// delay* chunk_size chunk_size + delay*
+// buffer: <-------------|---------------------|---------------|>
+// _a_ _b_ _c_
+//
+// On each call to ProcessChunk():
+// 1. New input gets read into sections _b_ and _c_ of the input buffer.
+// 2. We block starting from frame_offset.
+// 3. We block until we reach a block |bl| that doesn't contain any frames
+// from sections _a_ or _b_ of the input buffer.
+// 4. We window the current block, fire the callback for processing, window
+// again, and overlap/add to the output buffer.
+// 5. We copy sections _a_ and _b_ of the output buffer into output.
+// 6. For both the input and the output buffers, we copy section _c_ into
+// section _a_.
+// 7. We set the new frame_offset to be the difference between the first frame
+// of |bl| and the border between sections _b_ and _c_.
+//
+// When block_size > chunk_size the input and output buffers look like this:
+//
+// chunk_size delay* chunk_size + delay*
+// buffer: <-------------|---------------------|---------------|>
+// _a_ _b_ _c_
+//
+// On each call to ProcessChunk():
+// The procedure is the same as above, except for:
+// 1. New input gets read into section _c_ of the input buffer.
+// 3. We block until we reach a block |bl| that doesn't contain any frames
+// from section _a_ of the input buffer.
+// 5. We copy section _a_ of the output buffer into output.
+// 6. For both the input and the output buffers, we copy sections _b_ and _c_
+// into section _a_ and _b_.
+// 7. We set the new frame_offset to be the difference between the first frame
+// of |bl| and the border between sections _a_ and _b_.
+//
+// * delay here refers to inintial_delay_
+//
+// TODO(claguna): Look at using ring buffers to eliminate some copies.
+void Blocker::ProcessChunk(const float* const* input,
+ size_t chunk_size,
+ int num_input_channels,
+ int num_output_channels,
+ float* const* output) {
+ RTC_CHECK_EQ(chunk_size, chunk_size_);
+ RTC_CHECK_EQ(num_input_channels, num_input_channels_);
+ RTC_CHECK_EQ(num_output_channels, num_output_channels_);
+
+ input_buffer_.Write(input, num_input_channels, chunk_size_);
+ size_t first_frame_in_block = frame_offset_;
+
+ // Loop through blocks.
+ while (first_frame_in_block < chunk_size_) {
+ input_buffer_.Read(input_block_.channels(), num_input_channels,
+ block_size_);
+ input_buffer_.MoveReadPositionBackward(block_size_ - shift_amount_);
+
+ ApplyWindow(window_.get(),
+ block_size_,
+ num_input_channels_,
+ input_block_.channels());
+ callback_->ProcessBlock(input_block_.channels(),
+ block_size_,
+ num_input_channels_,
+ num_output_channels_,
+ output_block_.channels());
+ ApplyWindow(window_.get(),
+ block_size_,
+ num_output_channels_,
+ output_block_.channels());
+
+ AddFrames(output_buffer_.channels(),
+ first_frame_in_block,
+ output_block_.channels(),
+ 0,
+ block_size_,
+ num_output_channels_,
+ output_buffer_.channels(),
+ first_frame_in_block);
+
+ first_frame_in_block += shift_amount_;
+ }
+
+ // Copy output buffer to output
+ CopyFrames(output_buffer_.channels(),
+ 0,
+ chunk_size_,
+ num_output_channels_,
+ output,
+ 0);
+
+ // Copy output buffer [chunk_size_, chunk_size_ + initial_delay]
+ // to output buffer [0, initial_delay], zero the rest.
+ MoveFrames(output_buffer_.channels(),
+ chunk_size,
+ initial_delay_,
+ num_output_channels_,
+ output_buffer_.channels(),
+ 0);
+ ZeroOut(output_buffer_.channels(),
+ initial_delay_,
+ chunk_size_,
+ num_output_channels_);
+
+ // Calculate new starting frames.
+ frame_offset_ = first_frame_in_block - chunk_size_;
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/blocker.h b/webrtc/common_audio/blocker.h
new file mode 100644
index 0000000000..025638ae8c
--- /dev/null
+++ b/webrtc/common_audio/blocker.h
@@ -0,0 +1,123 @@
+/*
+ * 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 WEBRTC_INTERNAL_BEAMFORMER_BLOCKER_H_
+#define WEBRTC_INTERNAL_BEAMFORMER_BLOCKER_H_
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/audio_ring_buffer.h"
+#include "webrtc/common_audio/channel_buffer.h"
+
+namespace webrtc {
+
+// The callback function to process audio in the time domain. Input has already
+// been windowed, and output will be windowed. The number of input channels
+// must be >= the number of output channels.
+class BlockerCallback {
+ public:
+ virtual ~BlockerCallback() {}
+
+ virtual void ProcessBlock(const float* const* input,
+ size_t num_frames,
+ int num_input_channels,
+ int num_output_channels,
+ float* const* output) = 0;
+};
+
+// The main purpose of Blocker is to abstract away the fact that often we
+// receive a different number of audio frames than our transform takes. For
+// example, most FFTs work best when the fft-size is a power of 2, but suppose
+// we receive 20ms of audio at a sample rate of 48000. That comes to 960 frames
+// of audio, which is not a power of 2. Blocker allows us to specify the
+// transform and all other necessary processing via the Process() callback
+// function without any constraints on the transform-size
+// (read: |block_size_|) or received-audio-size (read: |chunk_size_|).
+// We handle this for the multichannel audio case, allowing for different
+// numbers of input and output channels (for example, beamforming takes 2 or
+// more input channels and returns 1 output channel). Audio signals are
+// represented as deinterleaved floats in the range [-1, 1].
+//
+// Blocker is responsible for:
+// - blocking audio while handling potential discontinuities on the edges
+// of chunks
+// - windowing blocks before sending them to Process()
+// - windowing processed blocks, and overlap-adding them together before
+// sending back a processed chunk
+//
+// To use blocker:
+// 1. Impelment a BlockerCallback object |bc|.
+// 2. Instantiate a Blocker object |b|, passing in |bc|.
+// 3. As you receive audio, call b.ProcessChunk() to get processed audio.
+//
+// A small amount of delay is added to the first received chunk to deal with
+// the difference in chunk/block sizes. This delay is <= chunk_size.
+//
+// Ownership of window is retained by the caller. That is, Blocker makes a
+// copy of window and does not attempt to delete it.
+class Blocker {
+ public:
+ Blocker(size_t chunk_size,
+ size_t block_size,
+ int num_input_channels,
+ int num_output_channels,
+ const float* window,
+ size_t shift_amount,
+ BlockerCallback* callback);
+
+ void ProcessChunk(const float* const* input,
+ size_t chunk_size,
+ int num_input_channels,
+ int num_output_channels,
+ float* const* output);
+
+ private:
+ const size_t chunk_size_;
+ const size_t block_size_;
+ const int num_input_channels_;
+ const int num_output_channels_;
+
+ // The number of frames of delay to add at the beginning of the first chunk.
+ const size_t initial_delay_;
+
+ // The frame index into the input buffer where the first block should be read
+ // from. This is necessary because shift_amount_ is not necessarily a
+ // multiple of chunk_size_, so blocks won't line up at the start of the
+ // buffer.
+ size_t frame_offset_;
+
+ // Since blocks nearly always overlap, there are certain blocks that require
+ // frames from the end of one chunk and the beginning of the next chunk. The
+ // input and output buffers are responsible for saving those frames between
+ // calls to ProcessChunk().
+ //
+ // Both contain |initial delay| + |chunk_size| frames. The input is a fairly
+ // standard FIFO, but due to the overlap-add it's harder to use an
+ // AudioRingBuffer for the output.
+ AudioRingBuffer input_buffer_;
+ ChannelBuffer<float> output_buffer_;
+
+ // Space for the input block (can't wrap because of windowing).
+ ChannelBuffer<float> input_block_;
+
+ // Space for the output block (can't wrap because of overlap/add).
+ ChannelBuffer<float> output_block_;
+
+ rtc::scoped_ptr<float[]> window_;
+
+ // The amount of frames between the start of contiguous blocks. For example,
+ // |shift_amount_| = |block_size_| / 2 for a Hann window.
+ size_t shift_amount_;
+
+ BlockerCallback* callback_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_INTERNAL_BEAMFORMER_BLOCKER_H_
diff --git a/webrtc/common_audio/blocker_unittest.cc b/webrtc/common_audio/blocker_unittest.cc
new file mode 100644
index 0000000000..397e269239
--- /dev/null
+++ b/webrtc/common_audio/blocker_unittest.cc
@@ -0,0 +1,342 @@
+/*
+ * 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 "webrtc/common_audio/blocker.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+// Callback Function to add 3 to every sample in the signal.
+class PlusThreeBlockerCallback : public webrtc::BlockerCallback {
+ public:
+ void ProcessBlock(const float* const* input,
+ size_t num_frames,
+ int num_input_channels,
+ int num_output_channels,
+ float* const* output) override {
+ for (int i = 0; i < num_output_channels; ++i) {
+ for (size_t j = 0; j < num_frames; ++j) {
+ output[i][j] = input[i][j] + 3;
+ }
+ }
+ }
+};
+
+// No-op Callback Function.
+class CopyBlockerCallback : public webrtc::BlockerCallback {
+ public:
+ void ProcessBlock(const float* const* input,
+ size_t num_frames,
+ int num_input_channels,
+ int num_output_channels,
+ float* const* output) override {
+ for (int i = 0; i < num_output_channels; ++i) {
+ for (size_t j = 0; j < num_frames; ++j) {
+ output[i][j] = input[i][j];
+ }
+ }
+ }
+};
+
+} // namespace
+
+namespace webrtc {
+
+// Tests blocking with a window that multiplies the signal by 2, a callback
+// that adds 3 to each sample in the signal, and different combinations of chunk
+// size, block size, and shift amount.
+class BlockerTest : public ::testing::Test {
+ protected:
+ void RunTest(Blocker* blocker,
+ int chunk_size,
+ int num_frames,
+ const float* const* input,
+ float* const* input_chunk,
+ float* const* output,
+ float* const* output_chunk,
+ int num_input_channels,
+ int num_output_channels) {
+ int start = 0;
+ int end = chunk_size - 1;
+ while (end < num_frames) {
+ CopyTo(input_chunk, 0, start, num_input_channels, chunk_size, input);
+ blocker->ProcessChunk(input_chunk,
+ chunk_size,
+ num_input_channels,
+ num_output_channels,
+ output_chunk);
+ CopyTo(output, start, 0, num_output_channels, chunk_size, output_chunk);
+
+ start = start + chunk_size;
+ end = end + chunk_size;
+ }
+ }
+
+ void ValidateSignalEquality(const float* const* expected,
+ const float* const* actual,
+ int num_channels,
+ int num_frames) {
+ for (int i = 0; i < num_channels; ++i) {
+ for (int j = 0; j < num_frames; ++j) {
+ EXPECT_FLOAT_EQ(expected[i][j], actual[i][j]);
+ }
+ }
+ }
+
+ void ValidateInitialDelay(const float* const* output,
+ int num_channels,
+ int num_frames,
+ int initial_delay) {
+ for (int i = 0; i < num_channels; ++i) {
+ for (int j = 0; j < num_frames; ++j) {
+ if (j < initial_delay) {
+ EXPECT_FLOAT_EQ(output[i][j], 0.f);
+ } else {
+ EXPECT_GT(output[i][j], 0.f);
+ }
+ }
+ }
+ }
+
+ static void CopyTo(float* const* dst,
+ int start_index_dst,
+ int start_index_src,
+ int num_channels,
+ int num_frames,
+ const float* const* src) {
+ for (int i = 0; i < num_channels; ++i) {
+ memcpy(&dst[i][start_index_dst],
+ &src[i][start_index_src],
+ num_frames * sizeof(float));
+ }
+ }
+};
+
+TEST_F(BlockerTest, TestBlockerMutuallyPrimeChunkandBlockSize) {
+ const int kNumInputChannels = 3;
+ const int kNumOutputChannels = 2;
+ const int kNumFrames = 10;
+ const int kBlockSize = 4;
+ const int kChunkSize = 5;
+ const int kShiftAmount = 2;
+
+ const float kInput[kNumInputChannels][kNumFrames] = {
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+ {3, 3, 3, 3, 3, 3, 3, 3, 3, 3}};
+ ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels);
+ input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput));
+
+ const float kExpectedOutput[kNumInputChannels][kNumFrames] = {
+ {6, 6, 12, 20, 20, 20, 20, 20, 20, 20},
+ {6, 6, 12, 28, 28, 28, 28, 28, 28, 28}};
+ ChannelBuffer<float> expected_output_cb(kNumFrames, kNumInputChannels);
+ expected_output_cb.SetDataForTesting(
+ kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput));
+
+ const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f};
+
+ ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels);
+ ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
+ ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
+
+ PlusThreeBlockerCallback callback;
+ Blocker blocker(kChunkSize,
+ kBlockSize,
+ kNumInputChannels,
+ kNumOutputChannels,
+ kWindow,
+ kShiftAmount,
+ &callback);
+
+ RunTest(&blocker,
+ kChunkSize,
+ kNumFrames,
+ input_cb.channels(),
+ input_chunk_cb.channels(),
+ actual_output_cb.channels(),
+ output_chunk_cb.channels(),
+ kNumInputChannels,
+ kNumOutputChannels);
+
+ ValidateSignalEquality(expected_output_cb.channels(),
+ actual_output_cb.channels(),
+ kNumOutputChannels,
+ kNumFrames);
+}
+
+TEST_F(BlockerTest, TestBlockerMutuallyPrimeShiftAndBlockSize) {
+ const int kNumInputChannels = 3;
+ const int kNumOutputChannels = 2;
+ const int kNumFrames = 12;
+ const int kBlockSize = 4;
+ const int kChunkSize = 6;
+ const int kShiftAmount = 3;
+
+ const float kInput[kNumInputChannels][kNumFrames] = {
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+ {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}};
+ ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels);
+ input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput));
+
+ const float kExpectedOutput[kNumOutputChannels][kNumFrames] = {
+ {6, 10, 10, 20, 10, 10, 20, 10, 10, 20, 10, 10},
+ {6, 14, 14, 28, 14, 14, 28, 14, 14, 28, 14, 14}};
+ ChannelBuffer<float> expected_output_cb(kNumFrames, kNumOutputChannels);
+ expected_output_cb.SetDataForTesting(
+ kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput));
+
+ const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f};
+
+ ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels);
+ ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
+ ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
+
+ PlusThreeBlockerCallback callback;
+ Blocker blocker(kChunkSize,
+ kBlockSize,
+ kNumInputChannels,
+ kNumOutputChannels,
+ kWindow,
+ kShiftAmount,
+ &callback);
+
+ RunTest(&blocker,
+ kChunkSize,
+ kNumFrames,
+ input_cb.channels(),
+ input_chunk_cb.channels(),
+ actual_output_cb.channels(),
+ output_chunk_cb.channels(),
+ kNumInputChannels,
+ kNumOutputChannels);
+
+ ValidateSignalEquality(expected_output_cb.channels(),
+ actual_output_cb.channels(),
+ kNumOutputChannels,
+ kNumFrames);
+}
+
+TEST_F(BlockerTest, TestBlockerNoOverlap) {
+ const int kNumInputChannels = 3;
+ const int kNumOutputChannels = 2;
+ const int kNumFrames = 12;
+ const int kBlockSize = 4;
+ const int kChunkSize = 4;
+ const int kShiftAmount = 4;
+
+ const float kInput[kNumInputChannels][kNumFrames] = {
+ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+ {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2},
+ {3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}};
+ ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels);
+ input_cb.SetDataForTesting(kInput[0], sizeof(kInput) / sizeof(**kInput));
+
+ const float kExpectedOutput[kNumOutputChannels][kNumFrames] = {
+ {10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10},
+ {14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14}};
+ ChannelBuffer<float> expected_output_cb(kNumFrames, kNumOutputChannels);
+ expected_output_cb.SetDataForTesting(
+ kExpectedOutput[0], sizeof(kExpectedOutput) / sizeof(**kExpectedOutput));
+
+ const float kWindow[kBlockSize] = {2.f, 2.f, 2.f, 2.f};
+
+ ChannelBuffer<float> actual_output_cb(kNumFrames, kNumOutputChannels);
+ ChannelBuffer<float> input_chunk_cb(kChunkSize, kNumInputChannels);
+ ChannelBuffer<float> output_chunk_cb(kChunkSize, kNumOutputChannels);
+
+ PlusThreeBlockerCallback callback;
+ Blocker blocker(kChunkSize,
+ kBlockSize,
+ kNumInputChannels,
+ kNumOutputChannels,
+ kWindow,
+ kShiftAmount,
+ &callback);
+
+ RunTest(&blocker,
+ kChunkSize,
+ kNumFrames,
+ input_cb.channels(),
+ input_chunk_cb.channels(),
+ actual_output_cb.channels(),
+ output_chunk_cb.channels(),
+ kNumInputChannels,
+ kNumOutputChannels);
+
+ ValidateSignalEquality(expected_output_cb.channels(),
+ actual_output_cb.channels(),
+ kNumOutputChannels,
+ kNumFrames);
+}
+
+TEST_F(BlockerTest, InitialDelaysAreMinimum) {
+ const int kNumInputChannels = 3;
+ const int kNumOutputChannels = 2;
+ const int kNumFrames = 1280;
+ const int kChunkSize[] =
+ {80, 80, 80, 80, 80, 80, 160, 160, 160, 160, 160, 160};
+ const int kBlockSize[] =
+ {64, 64, 64, 128, 128, 128, 128, 128, 128, 256, 256, 256};
+ const int kShiftAmount[] =
+ {16, 32, 64, 32, 64, 128, 32, 64, 128, 64, 128, 256};
+ const int kInitialDelay[] =
+ {48, 48, 48, 112, 112, 112, 96, 96, 96, 224, 224, 224};
+
+ float input[kNumInputChannels][kNumFrames];
+ for (int i = 0; i < kNumInputChannels; ++i) {
+ for (int j = 0; j < kNumFrames; ++j) {
+ input[i][j] = i + 1;
+ }
+ }
+ ChannelBuffer<float> input_cb(kNumFrames, kNumInputChannels);
+ input_cb.SetDataForTesting(input[0], sizeof(input) / sizeof(**input));
+
+ ChannelBuffer<float> output_cb(kNumFrames, kNumOutputChannels);
+
+ CopyBlockerCallback callback;
+
+ for (size_t i = 0; i < (sizeof(kChunkSize) / sizeof(*kChunkSize)); ++i) {
+ rtc::scoped_ptr<float[]> window(new float[kBlockSize[i]]);
+ for (int j = 0; j < kBlockSize[i]; ++j) {
+ window[j] = 1.f;
+ }
+
+ ChannelBuffer<float> input_chunk_cb(kChunkSize[i], kNumInputChannels);
+ ChannelBuffer<float> output_chunk_cb(kChunkSize[i], kNumOutputChannels);
+
+ Blocker blocker(kChunkSize[i],
+ kBlockSize[i],
+ kNumInputChannels,
+ kNumOutputChannels,
+ window.get(),
+ kShiftAmount[i],
+ &callback);
+
+ RunTest(&blocker,
+ kChunkSize[i],
+ kNumFrames,
+ input_cb.channels(),
+ input_chunk_cb.channels(),
+ output_cb.channels(),
+ output_chunk_cb.channels(),
+ kNumInputChannels,
+ kNumOutputChannels);
+
+ ValidateInitialDelay(output_cb.channels(),
+ kNumOutputChannels,
+ kNumFrames,
+ kInitialDelay[i]);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/channel_buffer.cc b/webrtc/common_audio/channel_buffer.cc
new file mode 100644
index 0000000000..d3dc7c04f7
--- /dev/null
+++ b/webrtc/common_audio/channel_buffer.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 "webrtc/common_audio/channel_buffer.h"
+
+namespace webrtc {
+
+IFChannelBuffer::IFChannelBuffer(size_t num_frames,
+ int num_channels,
+ size_t num_bands)
+ : ivalid_(true),
+ ibuf_(num_frames, num_channels, num_bands),
+ fvalid_(true),
+ fbuf_(num_frames, num_channels, num_bands) {}
+
+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_) {
+ assert(ivalid_);
+ const int16_t* const* int_channels = ibuf_.channels();
+ float* const* float_channels = fbuf_.channels();
+ for (int 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_) {
+ assert(fvalid_);
+ int16_t* const* int_channels = ibuf_.channels();
+ const float* const* float_channels = fbuf_.channels();
+ for (int i = 0; i < ibuf_.num_channels(); ++i) {
+ FloatS16ToS16(float_channels[i],
+ ibuf_.num_frames(),
+ int_channels[i]);
+ }
+ ivalid_ = true;
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/channel_buffer.h b/webrtc/common_audio/channel_buffer.h
new file mode 100644
index 0000000000..6050090876
--- /dev/null
+++ b/webrtc/common_audio/channel_buffer.h
@@ -0,0 +1,169 @@
+/*
+ * 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 WEBRTC_MODULES_AUDIO_PROCESSING_CHANNEL_BUFFER_H_
+#define WEBRTC_MODULES_AUDIO_PROCESSING_CHANNEL_BUFFER_H_
+
+#include <string.h>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/include/audio_util.h"
+#include "webrtc/test/testsupport/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,
+ int 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_channels_(num_channels),
+ num_bands_(num_bands) {
+ for (int i = 0; i < num_channels_; ++i) {
+ for (size_t j = 0; j < num_bands_; ++j) {
+ channels_[j * num_channels_ + i] =
+ &data_[i * num_frames_ + j * num_frames_per_band_];
+ bands_[i * num_bands_ + j] = channels_[j * num_channels_ + i];
+ }
+ }
+ }
+
+ // Returns a pointer array to the full-band channels (or lower band channels).
+ // Usage:
+ // channels()[channel][sample].
+ // Where:
+ // 0 <= channel < |num_channels_|
+ // 0 <= sample < |num_frames_|
+ T* const* channels() { return channels(0); }
+ const T* const* channels() const { return channels(0); }
+
+ // Returns a pointer array to the channels for a specific band.
+ // Usage:
+ // channels(band)[channel][sample].
+ // Where:
+ // 0 <= band < |num_bands_|
+ // 0 <= channel < |num_channels_|
+ // 0 <= sample < |num_frames_per_band_|
+ const T* const* channels(size_t band) const {
+ RTC_DCHECK_LT(band, num_bands_);
+ return &channels_[band * num_channels_];
+ }
+ T* const* channels(size_t band) {
+ const ChannelBuffer<T>* t = this;
+ return const_cast<T* const*>(t->channels(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(int channel) const {
+ RTC_DCHECK_LT(channel, num_channels_);
+ RTC_DCHECK_GE(channel, 0);
+ return &bands_[channel * num_bands_];
+ }
+ T* const* bands(int channel) {
+ const ChannelBuffer<T>* t = this;
+ return const_cast<T* const*>(t->bands(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 (int 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_; }
+ int num_channels() const { return num_channels_; }
+ size_t num_bands() const { return num_bands_; }
+ size_t size() const {return num_frames_ * num_channels_; }
+
+ void SetDataForTesting(const T* data, size_t size) {
+ RTC_CHECK_EQ(size, this->size());
+ memcpy(data_.get(), data, size * sizeof(*data));
+ }
+
+ private:
+ rtc::scoped_ptr<T[]> data_;
+ rtc::scoped_ptr<T* []> channels_;
+ rtc::scoped_ptr<T* []> bands_;
+ const size_t num_frames_;
+ const size_t num_frames_per_band_;
+ const int num_channels_;
+ const size_t num_bands_;
+};
+
+// 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, int num_channels, size_t num_bands = 1);
+
+ 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(); }
+ int num_channels() const { return ibuf_.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 // WEBRTC_MODULES_AUDIO_PROCESSING_CHANNEL_BUFFER_H_
diff --git a/webrtc/common_audio/common_audio.gyp b/webrtc/common_audio/common_audio.gyp
new file mode 100644
index 0000000000..884a8afcf8
--- /dev/null
+++ b/webrtc/common_audio/common_audio.gyp
@@ -0,0 +1,313 @@
+# 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.
+
+{
+ 'includes': [
+ '../build/common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'common_audio',
+ 'type': 'static_library',
+ 'dependencies': [
+ '<(webrtc_root)/system_wrappers/system_wrappers.gyp:system_wrappers',
+ ],
+ 'include_dirs': [
+ 'resampler/include',
+ 'signal_processing/include',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ 'resampler/include',
+ 'signal_processing/include',
+ 'vad/include',
+ ],
+ },
+ 'sources': [
+ 'audio_converter.cc',
+ 'audio_converter.h',
+ 'audio_ring_buffer.cc',
+ 'audio_ring_buffer.h',
+ 'audio_util.cc',
+ 'blocker.cc',
+ 'blocker.h',
+ 'channel_buffer.cc',
+ 'channel_buffer.h',
+ 'fft4g.c',
+ 'fft4g.h',
+ 'fir_filter.cc',
+ 'fir_filter.h',
+ 'fir_filter_neon.h',
+ 'fir_filter_sse.h',
+ 'include/audio_util.h',
+ 'lapped_transform.cc',
+ 'lapped_transform.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',
+ 'resampler/sinc_resampler.h',
+ 'ring_buffer.c',
+ 'ring_buffer.h',
+ 'signal_processing/include/real_fft.h',
+ 'signal_processing/include/signal_processing_library.h',
+ 'signal_processing/include/spl_inl.h',
+ 'signal_processing/auto_corr_to_refl_coef.c',
+ 'signal_processing/auto_correlation.c',
+ 'signal_processing/complex_fft.c',
+ 'signal_processing/complex_fft_tables.h',
+ 'signal_processing/complex_bit_reverse.c',
+ 'signal_processing/copy_set_operations.c',
+ 'signal_processing/cross_correlation.c',
+ 'signal_processing/division_operations.c',
+ 'signal_processing/dot_product_with_scale.c',
+ 'signal_processing/downsample_fast.c',
+ 'signal_processing/energy.c',
+ 'signal_processing/filter_ar.c',
+ 'signal_processing/filter_ar_fast_q12.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/levinson_durbin.c',
+ 'signal_processing/lpc_to_refl_coef.c',
+ 'signal_processing/min_max_operations.c',
+ 'signal_processing/randomization_functions.c',
+ 'signal_processing/refl_coef_to_lpc.c',
+ 'signal_processing/real_fft.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_sqrt.c',
+ 'signal_processing/spl_sqrt_floor.c',
+ 'signal_processing/splitting_filter.c',
+ 'signal_processing/sqrt_of_one_minus_x_squared.c',
+ 'signal_processing/vector_scaling_operations.c',
+ 'sparse_fir_filter.cc',
+ 'sparse_fir_filter.h',
+ 'vad/include/vad.h',
+ 'vad/include/webrtc_vad.h',
+ 'vad/vad.cc',
+ 'vad/webrtc_vad.c',
+ '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',
+ 'wav_header.cc',
+ 'wav_header.h',
+ 'wav_file.cc',
+ 'wav_file.h',
+ 'window_generator.cc',
+ 'window_generator.h',
+ ],
+ 'conditions': [
+ ['rtc_use_openmax_dl==1', {
+ 'sources': [
+ 'real_fourier_openmax.cc',
+ 'real_fourier_openmax.h',
+ ],
+ 'defines': ['RTC_USE_OPENMAX_DL',],
+ 'conditions': [
+ ['build_openmax_dl==1', {
+ 'dependencies': ['<(DEPTH)/third_party/openmax_dl/dl/dl.gyp:openmax_dl',],
+ }],
+ ],
+ }],
+ ['target_arch=="ia32" or target_arch=="x64"', {
+ 'dependencies': ['common_audio_sse2',],
+ }],
+ ['build_with_neon==1', {
+ 'dependencies': ['common_audio_neon',],
+ }],
+ ['target_arch=="arm"', {
+ 'sources': [
+ 'signal_processing/complex_bit_reverse_arm.S',
+ 'signal_processing/spl_sqrt_floor_arm.S',
+ ],
+ 'sources!': [
+ 'signal_processing/complex_bit_reverse.c',
+ 'signal_processing/spl_sqrt_floor.c',
+ ],
+ 'conditions': [
+ ['arm_version>=7', {
+ 'sources': [
+ 'signal_processing/filter_ar_fast_q12_armv7.S',
+ ],
+ 'sources!': [
+ 'signal_processing/filter_ar_fast_q12.c',
+ ],
+ }],
+ ], # conditions
+ }],
+ ['target_arch=="mipsel" and mips_arch_variant!="r6"', {
+ 'sources': [
+ 'signal_processing/include/spl_inl_mips.h',
+ '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/min_max_operations_mips.c',
+ 'signal_processing/resample_by_2_mips.c',
+ 'signal_processing/spl_sqrt_floor_mips.c',
+ ],
+ 'sources!': [
+ 'signal_processing/complex_bit_reverse.c',
+ 'signal_processing/complex_fft.c',
+ 'signal_processing/filter_ar_fast_q12.c',
+ 'signal_processing/spl_sqrt_floor.c',
+ ],
+ 'conditions': [
+ ['mips_dsp_rev>0', {
+ 'sources': [
+ 'signal_processing/vector_scaling_operations_mips.c',
+ ],
+ }],
+ ],
+ }],
+ ], # conditions
+ # Ignore warning on shift operator promotion.
+ 'msvs_disabled_warnings': [ 4334, ],
+ },
+ ], # targets
+ 'conditions': [
+ ['target_arch=="ia32" or target_arch=="x64"', {
+ 'targets': [
+ {
+ 'target_name': 'common_audio_sse2',
+ 'type': 'static_library',
+ 'sources': [
+ 'fir_filter_sse.cc',
+ 'resampler/sinc_resampler_sse.cc',
+ ],
+ 'conditions': [
+ ['os_posix==1', {
+ 'cflags': [ '-msse2', ],
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [ '-msse2', ],
+ },
+ }],
+ ],
+ },
+ ], # targets
+ }],
+ ['build_with_neon==1', {
+ 'targets': [
+ {
+ 'target_name': 'common_audio_neon',
+ 'type': 'static_library',
+ 'includes': ['../build/arm_neon.gypi',],
+ 'sources': [
+ 'fir_filter_neon.cc',
+ 'resampler/sinc_resampler_neon.cc',
+ 'signal_processing/cross_correlation_neon.c',
+ 'signal_processing/downsample_fast_neon.c',
+ 'signal_processing/min_max_operations_neon.c',
+ ],
+ },
+ ], # targets
+ }],
+ ['include_tests==1', {
+ 'targets' : [
+ {
+ 'target_name': 'common_audio_unittests',
+ 'type': '<(gtest_target_type)',
+ 'dependencies': [
+ 'common_audio',
+ '<(webrtc_root)/test/test.gyp:test_support_main',
+ '<(DEPTH)/testing/gmock.gyp:gmock',
+ '<(DEPTH)/testing/gtest.gyp:gtest',
+ ],
+ 'sources': [
+ 'audio_converter_unittest.cc',
+ 'audio_ring_buffer_unittest.cc',
+ 'audio_util_unittest.cc',
+ 'blocker_unittest.cc',
+ 'fir_filter_unittest.cc',
+ 'lapped_transform_unittest.cc',
+ 'real_fourier_unittest.cc',
+ 'resampler/resampler_unittest.cc',
+ 'resampler/push_resampler_unittest.cc',
+ 'resampler/push_sinc_resampler_unittest.cc',
+ 'resampler/sinc_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',
+ 'sparse_fir_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_header_unittest.cc',
+ 'wav_file_unittest.cc',
+ 'window_generator_unittest.cc',
+ ],
+ 'conditions': [
+ ['rtc_use_openmax_dl==1', {
+ 'defines': ['RTC_USE_OPENMAX_DL',],
+ }],
+ ['OS=="android"', {
+ 'dependencies': [
+ '<(DEPTH)/testing/android/native_test.gyp:native_test_native_code',
+ ],
+ }],
+ ],
+ },
+ ], # targets
+ 'conditions': [
+ ['OS=="android"', {
+ 'targets': [
+ {
+ 'target_name': 'common_audio_unittests_apk_target',
+ 'type': 'none',
+ 'dependencies': [
+ '<(apk_tests_path):common_audio_unittests_apk',
+ ],
+ },
+ ],
+ }],
+ ['test_isolation_mode != "noop"', {
+ 'targets': [
+ {
+ 'target_name': 'common_audio_unittests_run',
+ 'type': 'none',
+ 'dependencies': [
+ 'common_audio_unittests',
+ ],
+ 'includes': [
+ '../build/isolate.gypi',
+ ],
+ 'sources': [
+ 'common_audio_unittests.isolate',
+ ],
+ },
+ ],
+ }],
+ ],
+ }],
+ ], # conditions
+}
diff --git a/webrtc/common_audio/common_audio_unittests.isolate b/webrtc/common_audio/common_audio_unittests.isolate
new file mode 100644
index 0000000000..3bc26d5272
--- /dev/null
+++ b/webrtc/common_audio/common_audio_unittests.isolate
@@ -0,0 +1,23 @@
+# 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.
+{
+ 'conditions': [
+ ['OS=="linux" or OS=="mac" or OS=="win"', {
+ 'variables': {
+ 'command': [
+ '<(DEPTH)/testing/test_env.py',
+ '<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
+ ],
+ 'files': [
+ '<(DEPTH)/testing/test_env.py',
+ '<(PRODUCT_DIR)/common_audio_unittests<(EXECUTABLE_SUFFIX)',
+ ],
+ },
+ }],
+ ],
+}
diff --git a/webrtc/common_audio/fft4g.c b/webrtc/common_audio/fft4g.c
new file mode 100644
index 0000000000..9cf7b9f6ca
--- /dev/null
+++ b/webrtc/common_audio/fft4g.c
@@ -0,0 +1,1332 @@
+/*
+ * 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 <stddef.h>
+
+static void makewt(size_t nw, size_t *ip, float *w);
+static void makect(size_t nc, size_t *ip, float *c);
+static void bitrv2(size_t n, size_t *ip, float *a);
+#if 0 // Not used.
+static void bitrv2conj(int n, int *ip, float *a);
+#endif
+static void cftfsub(size_t n, float *a, float *w);
+static void cftbsub(size_t n, float *a, float *w);
+static void cft1st(size_t n, float *a, float *w);
+static void cftmdl(size_t n, size_t l, float *a, float *w);
+static void rftfsub(size_t n, float *a, size_t nc, float *c);
+static void rftbsub(size_t n, float *a, size_t nc, float *c);
+#if 0 // Not used.
+static void dctsub(int n, float *a, int nc, float *c)
+static void dstsub(int n, float *a, int nc, float *c)
+#endif
+
+
+#if 0 // Not used.
+void WebRtc_cdft(int n, int isgn, float *a, int *ip, float *w)
+{
+ if (n > (ip[0] << 2)) {
+ makewt(n >> 2, ip, w);
+ }
+ if (n > 4) {
+ if (isgn >= 0) {
+ bitrv2(n, ip + 2, a);
+ cftfsub(n, a, w);
+ } else {
+ bitrv2conj(n, ip + 2, a);
+ cftbsub(n, a, w);
+ }
+ } else if (n == 4) {
+ cftfsub(n, a, w);
+ }
+}
+#endif
+
+
+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);
+ }
+ }
+}
+
+#if 0 // Not used.
+static void ddct(int n, int isgn, float *a, int *ip, float *w)
+{
+ int j, nw, nc;
+ float xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = a[j] - a[j - 1];
+ a[j] += a[j - 1];
+ }
+ a[1] = a[0] - xr;
+ a[0] += xr;
+ 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);
+ }
+ }
+ dctsub(n, a, nc, 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);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = a[j] - a[j + 1];
+ a[j] += a[j + 1];
+ }
+ a[n - 1] = xr;
+ }
+}
+
+
+static void ddst(int n, int isgn, float *a, int *ip, float *w)
+{
+ int j, nw, nc;
+ float xr;
+
+ nw = ip[0];
+ if (n > (nw << 2)) {
+ nw = n >> 2;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > nc) {
+ nc = n;
+ makect(nc, ip, w + nw);
+ }
+ if (isgn < 0) {
+ xr = a[n - 1];
+ for (j = n - 2; j >= 2; j -= 2) {
+ a[j + 1] = -a[j] - a[j - 1];
+ a[j] -= a[j - 1];
+ }
+ a[1] = a[0] + xr;
+ a[0] -= xr;
+ 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);
+ }
+ }
+ dstsub(n, a, nc, 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);
+ }
+ xr = a[0] - a[1];
+ a[0] += a[1];
+ for (j = 2; j < n; j += 2) {
+ a[j - 1] = -a[j] - a[j + 1];
+ a[j] -= a[j + 1];
+ }
+ a[n - 1] = -xr;
+ }
+}
+
+
+static void dfct(int n, float *a, float *t, int *ip, float *w)
+{
+ int j, k, l, m, mh, nw, nc;
+ float xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ m = n >> 1;
+ yi = a[m];
+ xi = a[0] + a[n];
+ a[0] -= a[n];
+ t[0] = xi - yi;
+ t[m] = xi + yi;
+ if (n > 2) {
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] - a[n - j];
+ xi = a[j] + a[n - j];
+ yr = a[k] - a[n - k];
+ yi = a[k] + a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi - yi;
+ t[k] = xi + yi;
+ }
+ t[mh] = a[mh] + a[n - mh];
+ a[mh] -= a[n - mh];
+ dctsub(m, a, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, a);
+ cftfsub(m, a, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, w);
+ }
+ a[n - 1] = a[0] - a[1];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] + a[j + 1];
+ a[2 * j - 1] = a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dctsub(m, t, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, t);
+ cftfsub(m, t, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, w);
+ }
+ a[n - l] = t[0] - t[1];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = t[j] - t[j + 1];
+ a[k + l] = t[j] + t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 0; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] - t[m + j];
+ t[k] = t[m + k] + t[m + j];
+ }
+ t[mh] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ a[n] = t[2] - t[1];
+ a[0] = t[2] + t[1];
+ } else {
+ a[1] = a[0];
+ a[2] = t[0];
+ a[0] = t[1];
+ }
+}
+
+static void dfst(int n, float *a, float *t, int *ip, float *w)
+{
+ int j, k, l, m, mh, nw, nc;
+ float xr, xi, yr, yi;
+
+ nw = ip[0];
+ if (n > (nw << 3)) {
+ nw = n >> 3;
+ makewt(nw, ip, w);
+ }
+ nc = ip[1];
+ if (n > (nc << 1)) {
+ nc = n >> 1;
+ makect(nc, ip, w + nw);
+ }
+ if (n > 2) {
+ m = n >> 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ xr = a[j] + a[n - j];
+ xi = a[j] - a[n - j];
+ yr = a[k] + a[n - k];
+ yi = a[k] - a[n - k];
+ a[j] = xr;
+ a[k] = yr;
+ t[j] = xi + yi;
+ t[k] = xi - yi;
+ }
+ t[0] = a[mh] - a[n - mh];
+ a[mh] += a[n - mh];
+ a[0] = a[m];
+ dstsub(m, a, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, a);
+ cftfsub(m, a, w);
+ rftfsub(m, a, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, a, w);
+ }
+ a[n - 1] = a[1] - a[0];
+ a[1] = a[0] + a[1];
+ for (j = m - 2; j >= 2; j -= 2) {
+ a[2 * j + 1] = a[j] - a[j + 1];
+ a[2 * j - 1] = -a[j] - a[j + 1];
+ }
+ l = 2;
+ m = mh;
+ while (m >= 2) {
+ dstsub(m, t, nc, w + nw);
+ if (m > 4) {
+ bitrv2(m, ip + 2, t);
+ cftfsub(m, t, w);
+ rftfsub(m, t, nc, w + nw);
+ } else if (m == 4) {
+ cftfsub(m, t, w);
+ }
+ a[n - l] = t[1] - t[0];
+ a[l] = t[0] + t[1];
+ k = 0;
+ for (j = 2; j < m; j += 2) {
+ k += l << 2;
+ a[k - l] = -t[j] - t[j + 1];
+ a[k + l] = t[j] - t[j + 1];
+ }
+ l <<= 1;
+ mh = m >> 1;
+ for (j = 1; j < mh; j++) {
+ k = m - j;
+ t[j] = t[m + k] + t[m + j];
+ t[k] = t[m + k] - t[m + j];
+ }
+ t[0] = t[m + mh];
+ m = mh;
+ }
+ a[l] = t[0];
+ }
+ a[0] = 0;
+}
+#endif // Not used.
+
+
+/* -------- initializing routines -------- */
+
+
+#include <math.h>
+
+static 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);
+ }
+ }
+}
+
+
+static 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 -------- */
+
+
+static 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;
+ }
+ }
+ }
+}
+
+#if 0 // Not used.
+static void bitrv2conj(int n, int *ip, float *a)
+{
+ int 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;
+ }
+ k1 = 2 * k + ip[k];
+ a[k1 + 1] = -a[k1 + 1];
+ j1 = k1 + m2;
+ 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;
+ k1 += m2;
+ a[k1 + 1] = -a[k1 + 1];
+ }
+ } else {
+ a[1] = -a[1];
+ a[m2 + 1] = -a[m2 + 1];
+ 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;
+ }
+ k1 = 2 * k + ip[k];
+ a[k1 + 1] = -a[k1 + 1];
+ a[k1 + m2 + 1] = -a[k1 + m2 + 1];
+ }
+ }
+}
+#endif
+
+static 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;
+ }
+ }
+}
+
+
+static 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;
+ }
+ }
+}
+
+
+static 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;
+ }
+}
+
+
+static 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;
+ }
+ }
+}
+
+
+static 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;
+ }
+}
+
+
+static 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];
+}
+
+#if 0 // Not used.
+static void dctsub(int n, float *a, int nc, float *c)
+{
+ int j, k, kk, ks, m;
+ float wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[j] - wkr * a[k];
+ a[j] = wkr * a[j] + wki * a[k];
+ a[k] = xr;
+ }
+ a[m] *= c[0];
+}
+
+
+static void dstsub(int n, float *a, int nc, float *c)
+{
+ int j, k, kk, ks, m;
+ float wkr, wki, xr;
+
+ m = n >> 1;
+ ks = nc / n;
+ kk = 0;
+ for (j = 1; j < m; j++) {
+ k = n - j;
+ kk += ks;
+ wkr = c[kk] - c[nc - kk];
+ wki = c[kk] + c[nc - kk];
+ xr = wki * a[k] - wkr * a[j];
+ a[k] = wkr * a[k] + wki * a[j];
+ a[j] = xr;
+ }
+ a[m] *= c[0];
+}
+#endif // Not used.
diff --git a/webrtc/common_audio/fft4g.h b/webrtc/common_audio/fft4g.h
new file mode 100644
index 0000000000..6dd792f630
--- /dev/null
+++ b/webrtc/common_audio/fft4g.h
@@ -0,0 +1,25 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_FFT4G_H_
+#define WEBRTC_COMMON_AUDIO_FFT4G_H_
+
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+// Refer to fft4g.c for documentation.
+void WebRtc_rdft(size_t n, int isgn, float *a, size_t *ip, float *w);
+
+#if defined(__cplusplus)
+}
+#endif
+
+#endif // WEBRTC_COMMON_AUDIO_FFT4G_H_
diff --git a/webrtc/common_audio/fir_filter.cc b/webrtc/common_audio/fir_filter.cc
new file mode 100644
index 0000000000..dc1b776f99
--- /dev/null
+++ b/webrtc/common_audio/fir_filter.cc
@@ -0,0 +1,116 @@
+/*
+ * 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 "webrtc/common_audio/fir_filter.h"
+
+#include <assert.h>
+#include <string.h>
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/fir_filter_neon.h"
+#include "webrtc/common_audio/fir_filter_sse.h"
+#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
+
+namespace webrtc {
+
+class FIRFilterC : public FIRFilter {
+ public:
+ FIRFilterC(const float* coefficients,
+ size_t coefficients_length);
+
+ void Filter(const float* in, size_t length, float* out) override;
+
+ private:
+ size_t coefficients_length_;
+ size_t state_length_;
+ rtc::scoped_ptr<float[]> coefficients_;
+ rtc::scoped_ptr<float[]> state_;
+};
+
+FIRFilter* FIRFilter::Create(const float* coefficients,
+ size_t coefficients_length,
+ size_t max_input_length) {
+ if (!coefficients || coefficients_length <= 0 || max_input_length <= 0) {
+ assert(false);
+ return NULL;
+ }
+
+ FIRFilter* filter = NULL;
+// If we know the minimum architecture at compile time, avoid CPU detection.
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(__SSE2__)
+ filter =
+ new FIRFilterSSE2(coefficients, coefficients_length, max_input_length);
+#else
+ // x86 CPU detection required.
+ if (WebRtc_GetCPUInfo(kSSE2)) {
+ filter =
+ new FIRFilterSSE2(coefficients, coefficients_length, max_input_length);
+ } else {
+ filter = new FIRFilterC(coefficients, coefficients_length);
+ }
+#endif
+#elif defined(WEBRTC_HAS_NEON)
+ filter =
+ new FIRFilterNEON(coefficients, coefficients_length, max_input_length);
+#elif defined(WEBRTC_DETECT_NEON)
+ if (WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) {
+ filter =
+ new FIRFilterNEON(coefficients, coefficients_length, max_input_length);
+ } else {
+ filter = new FIRFilterC(coefficients, coefficients_length);
+ }
+#else
+ filter = new FIRFilterC(coefficients, coefficients_length);
+#endif
+
+ return filter;
+}
+
+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) {
+ assert(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/webrtc/common_audio/fir_filter.h b/webrtc/common_audio/fir_filter.h
new file mode 100644
index 0000000000..a5dc6eced1
--- /dev/null
+++ b/webrtc/common_audio/fir_filter.h
@@ -0,0 +1,40 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_FIR_FILTER_H_
+#define WEBRTC_COMMON_AUDIO_FIR_FILTER_H_
+
+#include <string.h>
+
+namespace webrtc {
+
+// Finite Impulse Response filter using floating-point arithmetic.
+class FIRFilter {
+ public:
+ // 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.
+ static FIRFilter* Create(const float* coefficients,
+ size_t coefficients_length,
+ size_t max_input_length);
+
+ 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 // WEBRTC_COMMON_AUDIO_FIR_FILTER_H_
diff --git a/webrtc/common_audio/fir_filter_neon.cc b/webrtc/common_audio/fir_filter_neon.cc
new file mode 100644
index 0000000000..a81562655b
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_neon.cc
@@ -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.
+ */
+
+#include "webrtc/common_audio/fir_filter_neon.h"
+
+#include <arm_neon.h>
+#include <assert.h>
+#include <string.h>
+
+#include "webrtc/system_wrappers/include/aligned_malloc.h"
+
+namespace webrtc {
+
+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) {
+ assert(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/webrtc/common_audio/fir_filter_neon.h b/webrtc/common_audio/fir_filter_neon.h
new file mode 100644
index 0000000000..3aa6168dd2
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_neon.h
@@ -0,0 +1,37 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_FIR_FILTER_NEON_H_
+#define WEBRTC_COMMON_AUDIO_FIR_FILTER_NEON_H_
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/fir_filter.h"
+#include "webrtc/system_wrappers/include/aligned_malloc.h"
+
+namespace webrtc {
+
+class FIRFilterNEON : public FIRFilter {
+ public:
+ FIRFilterNEON(const float* coefficients,
+ size_t coefficients_length,
+ size_t max_input_length);
+
+ void Filter(const float* in, size_t length, float* out) override;
+
+ private:
+ size_t coefficients_length_;
+ size_t state_length_;
+ rtc::scoped_ptr<float[], AlignedFreeDeleter> coefficients_;
+ rtc::scoped_ptr<float[], AlignedFreeDeleter> state_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_FIR_FILTER_NEON_H_
diff --git a/webrtc/common_audio/fir_filter_sse.cc b/webrtc/common_audio/fir_filter_sse.cc
new file mode 100644
index 0000000000..adbb2b75cc
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_sse.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 "webrtc/common_audio/fir_filter_sse.h"
+
+#include <assert.h>
+#include <string.h>
+#include <xmmintrin.h>
+
+#include "webrtc/system_wrappers/include/aligned_malloc.h"
+
+namespace webrtc {
+
+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) {
+ assert(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/webrtc/common_audio/fir_filter_sse.h b/webrtc/common_audio/fir_filter_sse.h
new file mode 100644
index 0000000000..a3325cd01d
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_sse.h
@@ -0,0 +1,37 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_FIR_FILTER_SSE_H_
+#define WEBRTC_COMMON_AUDIO_FIR_FILTER_SSE_H_
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/fir_filter.h"
+#include "webrtc/system_wrappers/include/aligned_malloc.h"
+
+namespace webrtc {
+
+class FIRFilterSSE2 : public FIRFilter {
+ public:
+ FIRFilterSSE2(const float* coefficients,
+ size_t coefficients_length,
+ size_t max_input_length);
+
+ void Filter(const float* in, size_t length, float* out) override;
+
+ private:
+ size_t coefficients_length_;
+ size_t state_length_;
+ rtc::scoped_ptr<float[], AlignedFreeDeleter> coefficients_;
+ rtc::scoped_ptr<float[], AlignedFreeDeleter> state_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_FIR_FILTER_SSE_H_
diff --git a/webrtc/common_audio/fir_filter_unittest.cc b/webrtc/common_audio/fir_filter_unittest.cc
new file mode 100644
index 0000000000..13f79d9482
--- /dev/null
+++ b/webrtc/common_audio/fir_filter_unittest.cc
@@ -0,0 +1,210 @@
+/*
+ * 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 "webrtc/common_audio/fir_filter.h"
+
+#include <string.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.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];
+ rtc::scoped_ptr<FIRFilter> filter(
+ FIRFilter::Create(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];
+ rtc::scoped_ptr<FIRFilter> filter(
+ FIRFilter::Create(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];
+ rtc::scoped_ptr<FIRFilter> filter(
+ FIRFilter::Create(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];
+ rtc::scoped_ptr<FIRFilter> filter(
+ FIRFilter::Create(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];
+ rtc::scoped_ptr<FIRFilter> filter(
+ FIRFilter::Create(kCoefficients, kCoefficientsLength, 2));
+ filter->Filter(kInput, 2, output);
+
+ EXPECT_FLOAT_EQ(0.2f, output[0]);
+ EXPECT_FLOAT_EQ(0.7f, output[1]);
+ filter.reset(FIRFilter::Create(
+ 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];
+ rtc::scoped_ptr<FIRFilter> filter(
+ FIRFilter::Create(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];
+ rtc::scoped_ptr<FIRFilter> filter(
+ FIRFilter::Create(kCoefficients, kCoefficientsLength, kInputLength));
+ filter->Filter(kInput, kInputLength, output_block_based);
+
+ float output_sample_based[kInputLength];
+ filter.reset(FIRFilter::Create(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];
+ rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(
+ 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];
+ rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(
+ 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];
+ rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(
+ kCoefficients, kCoefficientsLength, kCoefficientsLength));
+ // Use kCoefficientsLength for in_length to get same-length outputs.
+ filter->Filter(kInput, kCoefficientsLength, output);
+
+ filter.reset(FIRFilter::Create(
+ 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/webrtc/common_audio/include/audio_util.h b/webrtc/common_audio/include/audio_util.h
new file mode 100644
index 0000000000..2c0028ce90
--- /dev/null
+++ b/webrtc/common_audio/include/audio_util.h
@@ -0,0 +1,188 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
+#define WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
+
+#include <limits>
+#include <cstring>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/typedefs.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, 32767.0]
+static inline int16_t FloatToS16(float v) {
+ if (v > 0)
+ return v >= 1 ? limits_int16::max()
+ : static_cast<int16_t>(v * limits_int16::max() + 0.5f);
+ return v <= -1 ? limits_int16::min()
+ : static_cast<int16_t>(-v * limits_int16::min() - 0.5f);
+}
+
+static inline float S16ToFloat(int16_t v) {
+ static const float kMaxInt16Inverse = 1.f / limits_int16::max();
+ static const float kMinInt16Inverse = 1.f / limits_int16::min();
+ return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
+}
+
+static inline int16_t FloatS16ToS16(float v) {
+ static const float kMaxRound = limits_int16::max() - 0.5f;
+ static const float kMinRound = limits_int16::min() + 0.5f;
+ if (v > 0)
+ return v >= kMaxRound ? limits_int16::max()
+ : static_cast<int16_t>(v + 0.5f);
+ return v <= kMinRound ? limits_int16::min() : static_cast<int16_t>(v - 0.5f);
+}
+
+static inline float FloatToFloatS16(float v) {
+ return v * (v > 0 ? limits_int16::max() : -limits_int16::min());
+}
+
+static inline float FloatS16ToFloat(float v) {
+ static const float kMaxInt16Inverse = 1.f / limits_int16::max();
+ static const float kMinInt16Inverse = 1.f / limits_int16::min();
+ return v * (v > 0 ? kMaxInt16Inverse : -kMinInt16Inverse);
+}
+
+void FloatToS16(const float* src, size_t size, int16_t* dest);
+void S16ToFloat(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);
+
+// 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,
+ int num_channels,
+ T* const* deinterleaved) {
+ for (int i = 0; i < num_channels; ++i) {
+ T* channel = deinterleaved[i];
+ int 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,
+ int num_channels,
+ T* interleaved) {
+ for (int i = 0; i < num_channels; ++i) {
+ const T* channel = deinterleaved[i];
+ int 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, 0u);
+
+ 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 // WEBRTC_COMMON_AUDIO_INCLUDE_AUDIO_UTIL_H_
diff --git a/webrtc/common_audio/lapped_transform.cc b/webrtc/common_audio/lapped_transform.cc
new file mode 100644
index 0000000000..c01f1d9d8c
--- /dev/null
+++ b/webrtc/common_audio/lapped_transform.cc
@@ -0,0 +1,101 @@
+/*
+ * 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 "webrtc/common_audio/lapped_transform.h"
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/real_fourier.h"
+
+namespace webrtc {
+
+void LappedTransform::BlockThunk::ProcessBlock(const float* const* input,
+ size_t num_frames,
+ int num_input_channels,
+ int num_output_channels,
+ float* const* output) {
+ RTC_CHECK_EQ(num_input_channels, parent_->num_in_channels_);
+ RTC_CHECK_EQ(num_output_channels, parent_->num_out_channels_);
+ RTC_CHECK_EQ(parent_->block_length_, num_frames);
+
+ for (int i = 0; i < num_input_channels; ++i) {
+ memcpy(parent_->real_buf_.Row(i), input[i],
+ num_frames * sizeof(*input[0]));
+ parent_->fft_->Forward(parent_->real_buf_.Row(i),
+ parent_->cplx_pre_.Row(i));
+ }
+
+ size_t block_length = RealFourier::ComplexLength(
+ RealFourier::FftOrder(num_frames));
+ RTC_CHECK_EQ(parent_->cplx_length_, block_length);
+ parent_->block_processor_->ProcessAudioBlock(parent_->cplx_pre_.Array(),
+ num_input_channels,
+ parent_->cplx_length_,
+ num_output_channels,
+ parent_->cplx_post_.Array());
+
+ for (int i = 0; i < num_output_channels; ++i) {
+ parent_->fft_->Inverse(parent_->cplx_post_.Row(i),
+ parent_->real_buf_.Row(i));
+ memcpy(output[i], parent_->real_buf_.Row(i),
+ num_frames * sizeof(*input[0]));
+ }
+}
+
+LappedTransform::LappedTransform(int num_in_channels,
+ int num_out_channels,
+ size_t chunk_length,
+ const float* window,
+ size_t block_length,
+ size_t shift_amount,
+ Callback* callback)
+ : blocker_callback_(this),
+ num_in_channels_(num_in_channels),
+ num_out_channels_(num_out_channels),
+ block_length_(block_length),
+ chunk_length_(chunk_length),
+ block_processor_(callback),
+ blocker_(chunk_length_,
+ block_length_,
+ num_in_channels_,
+ num_out_channels_,
+ window,
+ shift_amount,
+ &blocker_callback_),
+ fft_(RealFourier::Create(RealFourier::FftOrder(block_length_))),
+ cplx_length_(RealFourier::ComplexLength(fft_->order())),
+ real_buf_(num_in_channels,
+ block_length_,
+ RealFourier::kFftBufferAlignment),
+ cplx_pre_(num_in_channels,
+ cplx_length_,
+ RealFourier::kFftBufferAlignment),
+ cplx_post_(num_out_channels,
+ cplx_length_,
+ RealFourier::kFftBufferAlignment) {
+ RTC_CHECK(num_in_channels_ > 0 && num_out_channels_ > 0);
+ RTC_CHECK_GT(block_length_, 0u);
+ RTC_CHECK_GT(chunk_length_, 0u);
+ RTC_CHECK(block_processor_);
+
+ // block_length_ power of 2?
+ RTC_CHECK_EQ(0u, block_length_ & (block_length_ - 1));
+}
+
+void LappedTransform::ProcessChunk(const float* const* in_chunk,
+ float* const* out_chunk) {
+ blocker_.ProcessChunk(in_chunk, chunk_length_, num_in_channels_,
+ num_out_channels_, out_chunk);
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/lapped_transform.h b/webrtc/common_audio/lapped_transform.h
new file mode 100644
index 0000000000..21e10e3911
--- /dev/null
+++ b/webrtc/common_audio/lapped_transform.h
@@ -0,0 +1,123 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_LAPPED_TRANSFORM_H_
+#define WEBRTC_COMMON_AUDIO_LAPPED_TRANSFORM_H_
+
+#include <complex>
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/blocker.h"
+#include "webrtc/common_audio/real_fourier.h"
+#include "webrtc/system_wrappers/include/aligned_array.h"
+
+namespace webrtc {
+
+// Helper class for audio processing modules which operate on frequency domain
+// input derived from the windowed time domain audio stream.
+//
+// The input audio chunk is sliced into possibly overlapping blocks, multiplied
+// by a window and transformed with an FFT implementation. The transformed data
+// is supplied to the given callback for processing. The processed output is
+// then inverse transformed into the time domain and spliced back into a chunk
+// which constitutes the final output of this processing module.
+class LappedTransform {
+ public:
+ class Callback {
+ public:
+ virtual ~Callback() {}
+
+ virtual void ProcessAudioBlock(const std::complex<float>* const* in_block,
+ int num_in_channels, size_t frames,
+ int num_out_channels,
+ std::complex<float>* const* out_block) = 0;
+ };
+
+ // Construct a transform instance. |chunk_length| is the number of samples in
+ // each channel. |window| defines the window, owned by the caller (a copy is
+ // made internally); |window| should have length equal to |block_length|.
+ // |block_length| defines the length of a block, in samples.
+ // |shift_amount| is in samples. |callback| is the caller-owned audio
+ // processing function called for each block of the input chunk.
+ LappedTransform(int num_in_channels,
+ int num_out_channels,
+ size_t chunk_length,
+ const float* window,
+ size_t block_length,
+ size_t shift_amount,
+ Callback* callback);
+ ~LappedTransform() {}
+
+ // Main audio processing helper method. Internally slices |in_chunk| into
+ // blocks, transforms them to frequency domain, calls the callback for each
+ // block and returns a de-blocked time domain chunk of audio through
+ // |out_chunk|. Both buffers are caller-owned.
+ void ProcessChunk(const float* const* in_chunk, float* const* out_chunk);
+
+ // Get the chunk length.
+ //
+ // The chunk length is the number of samples per channel that must be passed
+ // to ProcessChunk via the parameter in_chunk.
+ //
+ // Returns the same chunk_length passed to the LappedTransform constructor.
+ size_t chunk_length() const { return chunk_length_; }
+
+ // Get the number of input channels.
+ //
+ // This is the number of arrays that must be passed to ProcessChunk via
+ // in_chunk.
+ //
+ // Returns the same num_in_channels passed to the LappedTransform constructor.
+ int num_in_channels() const { return num_in_channels_; }
+
+ // Get the number of output channels.
+ //
+ // This is the number of arrays that must be passed to ProcessChunk via
+ // out_chunk.
+ //
+ // Returns the same num_out_channels passed to the LappedTransform
+ // constructor.
+ int num_out_channels() const { return num_out_channels_; }
+
+ private:
+ // Internal middleware callback, given to the blocker. Transforms each block
+ // and hands it over to the processing method given at construction time.
+ class BlockThunk : public BlockerCallback {
+ public:
+ explicit BlockThunk(LappedTransform* parent) : parent_(parent) {}
+
+ virtual void ProcessBlock(const float* const* input, size_t num_frames,
+ int num_input_channels, int num_output_channels,
+ float* const* output);
+
+ private:
+ LappedTransform* const parent_;
+ } blocker_callback_;
+
+ const int num_in_channels_;
+ const int num_out_channels_;
+
+ const size_t block_length_;
+ const size_t chunk_length_;
+
+ Callback* const block_processor_;
+ Blocker blocker_;
+
+ rtc::scoped_ptr<RealFourier> fft_;
+ const size_t cplx_length_;
+ AlignedArray<float> real_buf_;
+ AlignedArray<std::complex<float> > cplx_pre_;
+ AlignedArray<std::complex<float> > cplx_post_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_LAPPED_TRANSFORM_H_
+
diff --git a/webrtc/common_audio/lapped_transform_unittest.cc b/webrtc/common_audio/lapped_transform_unittest.cc
new file mode 100644
index 0000000000..f688cc240a
--- /dev/null
+++ b/webrtc/common_audio/lapped_transform_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 "webrtc/common_audio/lapped_transform.h"
+
+#include <algorithm>
+#include <cmath>
+#include <cstring>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+using std::complex;
+
+namespace {
+
+class NoopCallback : public webrtc::LappedTransform::Callback {
+ public:
+ NoopCallback() : block_num_(0) {}
+
+ virtual void ProcessAudioBlock(const complex<float>* const* in_block,
+ int in_channels,
+ size_t frames,
+ int out_channels,
+ complex<float>* const* out_block) {
+ RTC_CHECK_EQ(in_channels, out_channels);
+ for (int i = 0; i < out_channels; ++i) {
+ memcpy(out_block[i], in_block[i], sizeof(**in_block) * frames);
+ }
+ ++block_num_;
+ }
+
+ int block_num() {
+ return block_num_;
+ }
+
+ private:
+ int block_num_;
+};
+
+class FftCheckerCallback : public webrtc::LappedTransform::Callback {
+ public:
+ FftCheckerCallback() : block_num_(0) {}
+
+ virtual void ProcessAudioBlock(const complex<float>* const* in_block,
+ int in_channels,
+ size_t frames,
+ int out_channels,
+ complex<float>* const* out_block) {
+ RTC_CHECK_EQ(in_channels, out_channels);
+
+ size_t full_length = (frames - 1) * 2;
+ ++block_num_;
+
+ if (block_num_ > 0) {
+ ASSERT_NEAR(in_block[0][0].real(), static_cast<float>(full_length),
+ 1e-5f);
+ ASSERT_NEAR(in_block[0][0].imag(), 0.0f, 1e-5f);
+ for (size_t i = 1; i < frames; ++i) {
+ ASSERT_NEAR(in_block[0][i].real(), 0.0f, 1e-5f);
+ ASSERT_NEAR(in_block[0][i].imag(), 0.0f, 1e-5f);
+ }
+ }
+ }
+
+ int block_num() {
+ return block_num_;
+ }
+
+ private:
+ int block_num_;
+};
+
+void SetFloatArray(float value, int rows, int cols, float* const* array) {
+ for (int i = 0; i < rows; ++i) {
+ for (int j = 0; j < cols; ++j) {
+ array[i][j] = value;
+ }
+ }
+}
+
+} // namespace
+
+namespace webrtc {
+
+TEST(LappedTransformTest, Windowless) {
+ const int kChannels = 3;
+ const int kChunkLength = 512;
+ const int kBlockLength = 64;
+ const int kShiftAmount = 64;
+ NoopCallback noop;
+
+ // Rectangular window.
+ float window[kBlockLength];
+ std::fill(window, &window[kBlockLength], 1.0f);
+
+ LappedTransform trans(kChannels, kChannels, kChunkLength, window,
+ kBlockLength, kShiftAmount, &noop);
+ float in_buffer[kChannels][kChunkLength];
+ float* in_chunk[kChannels];
+ float out_buffer[kChannels][kChunkLength];
+ float* out_chunk[kChannels];
+
+ in_chunk[0] = in_buffer[0];
+ in_chunk[1] = in_buffer[1];
+ in_chunk[2] = in_buffer[2];
+ out_chunk[0] = out_buffer[0];
+ out_chunk[1] = out_buffer[1];
+ out_chunk[2] = out_buffer[2];
+ SetFloatArray(2.0f, kChannels, kChunkLength, in_chunk);
+ SetFloatArray(-1.0f, kChannels, kChunkLength, out_chunk);
+
+ trans.ProcessChunk(in_chunk, out_chunk);
+
+ for (int i = 0; i < kChannels; ++i) {
+ for (int j = 0; j < kChunkLength; ++j) {
+ ASSERT_NEAR(out_chunk[i][j], 2.0f, 1e-5f);
+ }
+ }
+
+ ASSERT_EQ(kChunkLength / kBlockLength, noop.block_num());
+}
+
+TEST(LappedTransformTest, IdentityProcessor) {
+ const int kChunkLength = 512;
+ const int kBlockLength = 64;
+ const int kShiftAmount = 32;
+ NoopCallback noop;
+
+ // Identity window for |overlap = block_size / 2|.
+ float window[kBlockLength];
+ std::fill(window, &window[kBlockLength], std::sqrt(0.5f));
+
+ LappedTransform trans(1, 1, kChunkLength, window, kBlockLength, kShiftAmount,
+ &noop);
+ float in_buffer[kChunkLength];
+ float* in_chunk = in_buffer;
+ float out_buffer[kChunkLength];
+ float* out_chunk = out_buffer;
+
+ SetFloatArray(2.0f, 1, kChunkLength, &in_chunk);
+ SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
+
+ trans.ProcessChunk(&in_chunk, &out_chunk);
+
+ for (int i = 0; i < kChunkLength; ++i) {
+ ASSERT_NEAR(out_chunk[i],
+ (i < kBlockLength - kShiftAmount) ? 0.0f : 2.0f,
+ 1e-5f);
+ }
+
+ ASSERT_EQ(kChunkLength / kShiftAmount, noop.block_num());
+}
+
+TEST(LappedTransformTest, Callbacks) {
+ const int kChunkLength = 512;
+ const int kBlockLength = 64;
+ FftCheckerCallback call;
+
+ // Rectangular window.
+ float window[kBlockLength];
+ std::fill(window, &window[kBlockLength], 1.0f);
+
+ LappedTransform trans(1, 1, kChunkLength, window, kBlockLength,
+ kBlockLength, &call);
+ float in_buffer[kChunkLength];
+ float* in_chunk = in_buffer;
+ float out_buffer[kChunkLength];
+ float* out_chunk = out_buffer;
+
+ SetFloatArray(1.0f, 1, kChunkLength, &in_chunk);
+ SetFloatArray(-1.0f, 1, kChunkLength, &out_chunk);
+
+ trans.ProcessChunk(&in_chunk, &out_chunk);
+
+ ASSERT_EQ(kChunkLength / kBlockLength, call.block_num());
+}
+
+TEST(LappedTransformTest, chunk_length) {
+ const int kBlockLength = 64;
+ FftCheckerCallback call;
+ const float window[kBlockLength] = {};
+
+ // Make sure that chunk_length returns the same value passed to the
+ // LappedTransform constructor.
+ {
+ const size_t kExpectedChunkLength = 512;
+ const LappedTransform trans(1, 1, kExpectedChunkLength, window,
+ kBlockLength, kBlockLength, &call);
+
+ EXPECT_EQ(kExpectedChunkLength, trans.chunk_length());
+ }
+ {
+ const size_t kExpectedChunkLength = 160;
+ const LappedTransform trans(1, 1, kExpectedChunkLength, window,
+ kBlockLength, kBlockLength, &call);
+
+ EXPECT_EQ(kExpectedChunkLength, trans.chunk_length());
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/real_fourier.cc b/webrtc/common_audio/real_fourier.cc
new file mode 100644
index 0000000000..fef3c60c4c
--- /dev/null
+++ b/webrtc/common_audio/real_fourier.cc
@@ -0,0 +1,57 @@
+/*
+ * 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 "webrtc/common_audio/real_fourier.h"
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/real_fourier_ooura.h"
+#include "webrtc/common_audio/real_fourier_openmax.h"
+#include "webrtc/common_audio/signal_processing/include/spl_inl.h"
+
+namespace webrtc {
+
+using std::complex;
+
+const int RealFourier::kFftBufferAlignment = 32;
+
+rtc::scoped_ptr<RealFourier> RealFourier::Create(int fft_order) {
+#if defined(RTC_USE_OPENMAX_DL)
+ return rtc::scoped_ptr<RealFourier>(new RealFourierOpenmax(fft_order));
+#else
+ return rtc::scoped_ptr<RealFourier>(new RealFourierOoura(fft_order));
+#endif
+}
+
+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 static_cast<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/webrtc/common_audio/real_fourier.h b/webrtc/common_audio/real_fourier.h
new file mode 100644
index 0000000000..ce3bbff679
--- /dev/null
+++ b/webrtc/common_audio/real_fourier.h
@@ -0,0 +1,75 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_REAL_FOURIER_H_
+#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_H_
+
+#include <complex>
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/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 rtc::scoped_ptr<float[], AlignedFreeDeleter> fft_real_scoper;
+ typedef rtc::scoped_ptr<std::complex<float>[], AlignedFreeDeleter>
+ fft_cplx_scoper;
+
+ // The alignment required for all input and output buffers, in bytes.
+ static const int kFftBufferAlignment;
+
+ // Construct a wrapper instance for the given input order, which must be
+ // between 1 and kMaxFftOrder, inclusively.
+ static rtc::scoped_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 // WEBRTC_COMMON_AUDIO_REAL_FOURIER_H_
+
diff --git a/webrtc/common_audio/real_fourier_ooura.cc b/webrtc/common_audio/real_fourier_ooura.cc
new file mode 100644
index 0000000000..8cd4c86b5b
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_ooura.cc
@@ -0,0 +1,85 @@
+/*
+ * 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 "webrtc/common_audio/real_fourier_ooura.h"
+
+#include <cmath>
+#include <algorithm>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/fft4g.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);
+}
+
+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; });
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/real_fourier_ooura.h b/webrtc/common_audio/real_fourier_ooura.h
new file mode 100644
index 0000000000..8d094bf494
--- /dev/null
+++ b/webrtc/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 WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+
+#include <complex>
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/real_fourier.h"
+
+namespace webrtc {
+
+class RealFourierOoura : public RealFourier {
+ public:
+ explicit RealFourierOoura(int fft_order);
+
+ 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 {
+ return order_;
+ }
+
+ 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
+ // fft4g.c.
+ const rtc::scoped_ptr<size_t[]> work_ip_;
+ const rtc::scoped_ptr<float[]> work_w_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OOURA_H_
+
diff --git a/webrtc/common_audio/real_fourier_openmax.cc b/webrtc/common_audio/real_fourier_openmax.cc
new file mode 100644
index 0000000000..bc3e7347cb
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_openmax.cc
@@ -0,0 +1,69 @@
+/*
+ * 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 "webrtc/common_audio/real_fourier_openmax.h"
+
+#include <cstdlib>
+
+#include "dl/sp/api/omxSP.h"
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+using std::complex;
+
+namespace {
+
+// Creates and initializes the Openmax state. Transfers ownership to caller.
+OMXFFTSpec_R_F32* CreateOpenmaxState(int order) {
+ RTC_CHECK_GE(order, 1);
+ // The omx implementation uses this macro to check order validity.
+ RTC_CHECK_LE(order, TWIDDLE_TABLE_ORDER);
+
+ OMX_INT buffer_size;
+ OMXResult r = omxSP_FFTGetBufSize_R_F32(order, &buffer_size);
+ RTC_CHECK_EQ(r, OMX_Sts_NoErr);
+
+ OMXFFTSpec_R_F32* omx_spec = malloc(buffer_size);
+ RTC_DCHECK(omx_spec);
+
+ r = omxSP_FFTInit_R_F32(omx_spec, order);
+ RTC_CHECK_EQ(r, OMX_Sts_NoErr);
+ return omx_spec;
+}
+
+} // namespace
+
+RealFourierOpenmax::RealFourierOpenmax(int fft_order)
+ : order_(fft_order),
+ omx_spec_(CreateOpenmaxState(order_)) {
+}
+
+RealFourierOpenmax::~RealFourierOpenmax() {
+ free(omx_spec_);
+}
+
+void RealFourierOpenmax::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
+ OMXResult r =
+ omxSP_FFTFwd_RToCCS_F32(src, reinterpret_cast<OMX_F32*>(dest), omx_spec_);
+ RTC_CHECK_EQ(r, OMX_Sts_NoErr);
+}
+
+void RealFourierOpenmax::Inverse(const complex<float>* src, float* dest) const {
+ OMXResult r =
+ omxSP_FFTInv_CCSToR_F32(reinterpret_cast<const OMX_F32*>(src), dest,
+ omx_spec_);
+ RTC_CHECK_EQ(r, OMX_Sts_NoErr);
+}
+
+} // namespace webrtc
+
diff --git a/webrtc/common_audio/real_fourier_openmax.h b/webrtc/common_audio/real_fourier_openmax.h
new file mode 100644
index 0000000000..63ce5ba0bc
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_openmax.h
@@ -0,0 +1,44 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
+#define WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
+
+#include <complex>
+
+#include "webrtc/common_audio/real_fourier.h"
+
+namespace webrtc {
+
+class RealFourierOpenmax : public RealFourier {
+ public:
+ explicit RealFourierOpenmax(int fft_order);
+ ~RealFourierOpenmax() 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 {
+ return order_;
+ }
+
+ private:
+ // Basically a forward declare of OMXFFTSpec_R_F32. To get rid of the
+ // dependency on openmax.
+ typedef void OMXFFTSpec_R_F32_;
+ const int order_;
+
+ OMXFFTSpec_R_F32_* const omx_spec_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_REAL_FOURIER_OPENMAX_H_
+
diff --git a/webrtc/common_audio/real_fourier_unittest.cc b/webrtc/common_audio/real_fourier_unittest.cc
new file mode 100644
index 0000000000..5c8542138b
--- /dev/null
+++ b/webrtc/common_audio/real_fourier_unittest.cc
@@ -0,0 +1,110 @@
+/*
+ * 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 "webrtc/common_audio/real_fourier.h"
+
+#include <stdlib.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/real_fourier_openmax.h"
+#include "webrtc/common_audio/real_fourier_ooura.h"
+
+namespace webrtc {
+
+using std::complex;
+
+TEST(RealFourierStaticsTest, AllocatorAlignment) {
+ {
+ RealFourier::fft_real_scoper real;
+ real = RealFourier::AllocRealBuffer(3);
+ ASSERT_TRUE(real.get() != nullptr);
+ int64_t ptr_value = reinterpret_cast<int64_t>(real.get());
+ EXPECT_EQ(0, ptr_value % RealFourier::kFftBufferAlignment);
+ }
+ {
+ RealFourier::fft_cplx_scoper cplx;
+ cplx = RealFourier::AllocCplxBuffer(3);
+ ASSERT_TRUE(cplx.get() != nullptr);
+ int64_t ptr_value = reinterpret_cast<int64_t>(cplx.get());
+ EXPECT_EQ(0, 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<
+#if defined(RTC_USE_OPENMAX_DL)
+ RealFourierOpenmax,
+#endif
+ RealFourierOoura>;
+TYPED_TEST_CASE(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/webrtc/common_audio/resampler/Android.mk b/webrtc/common_audio/resampler/Android.mk
new file mode 100644
index 0000000000..60b55c5d58
--- /dev/null
+++ b/webrtc/common_audio/resampler/Android.mk
@@ -0,0 +1,51 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(LOCAL_PATH)/../../../android-webrtc.mk
+
+LOCAL_ARM_MODE := arm
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := libwebrtc_resampler
+LOCAL_MODULE_TAGS := optional
+LOCAL_CPP_EXTENSION := .cc
+LOCAL_SRC_FILES := \
+ push_sinc_resampler.cc \
+ resampler.cc \
+ sinc_resampler.cc \
+
+ifeq ($(TARGET_ARCH), $(filter $(TARGET_ARCH),x86 x86_64))
+LOCAL_SRC_FILES += sinc_resampler_sse.cc
+endif
+
+# Flags passed to both C and C++ files.
+LOCAL_CFLAGS := \
+ $(MY_WEBRTC_COMMON_DEFS)
+
+LOCAL_CFLAGS_arm := $(MY_WEBRTC_COMMON_DEFS_arm)
+LOCAL_CFLAGS_x86 := $(MY_WEBRTC_COMMON_DEFS_x86)
+LOCAL_CFLAGS_mips := $(MY_WEBRTC_COMMON_DEFS_mips)
+LOCAL_CFLAGS_arm64 := $(MY_WEBRTC_COMMON_DEFS_arm64)
+LOCAL_CFLAGS_x86_64 := $(MY_WEBRTC_COMMON_DEFS_x86_64)
+LOCAL_CFLAGS_mips64 := $(MY_WEBRTC_COMMON_DEFS_mips64)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../../.. \
+ $(LOCAL_PATH)/../signal_processing/include
+
+ifdef WEBRTC_STL
+LOCAL_NDK_STL_VARIANT := $(WEBRTC_STL)
+LOCAL_SDK_VERSION := 14
+LOCAL_MODULE := $(LOCAL_MODULE)_$(WEBRTC_STL)
+endif
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc/common_audio/resampler/include/push_resampler.h b/webrtc/common_audio/resampler/include/push_resampler.h
new file mode 100644
index 0000000000..b5c0003615
--- /dev/null
+++ b/webrtc/common_audio/resampler/include/push_resampler.h
@@ -0,0 +1,52 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
+#define WEBRTC_COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
+
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/typedefs.h"
+
+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,
+ int 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:
+ rtc::scoped_ptr<PushSincResampler> sinc_resampler_;
+ rtc::scoped_ptr<PushSincResampler> sinc_resampler_right_;
+ int src_sample_rate_hz_;
+ int dst_sample_rate_hz_;
+ int num_channels_;
+ rtc::scoped_ptr<T[]> src_left_;
+ rtc::scoped_ptr<T[]> src_right_;
+ rtc::scoped_ptr<T[]> dst_left_;
+ rtc::scoped_ptr<T[]> dst_right_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_INCLUDE_PUSH_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/include/resampler.h b/webrtc/common_audio/resampler/include/resampler.h
new file mode 100644
index 0000000000..0d4c1afe4e
--- /dev/null
+++ b/webrtc/common_audio/resampler/include/resampler.h
@@ -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.
+ */
+
+
+/*
+ * A wrapper for resampling a numerous amount of sampling combinations.
+ */
+
+#ifndef WEBRTC_RESAMPLER_RESAMPLER_H_
+#define WEBRTC_RESAMPLER_RESAMPLER_H_
+
+#include <stddef.h>
+
+#include "webrtc/typedefs.h"
+
+namespace webrtc {
+
+// All methods return 0 on success and -1 on failure.
+class Resampler
+{
+
+public:
+ Resampler();
+ Resampler(int inFreq, int outFreq, int num_channels);
+ ~Resampler();
+
+ // Reset all states
+ int Reset(int inFreq, int outFreq, int num_channels);
+
+ // Reset all states if any parameter has changed
+ int ResetIfNeeded(int inFreq, int outFreq, int num_channels);
+
+ // Resample samplesIn to samplesOut.
+ int Push(const int16_t* samplesIn, size_t lengthIn, int16_t* samplesOut,
+ size_t maxLen, size_t &outLen);
+
+private:
+ enum ResamplerMode
+ {
+ kResamplerMode1To1,
+ kResamplerMode1To2,
+ kResamplerMode1To3,
+ kResamplerMode1To4,
+ kResamplerMode1To6,
+ kResamplerMode1To12,
+ kResamplerMode2To3,
+ kResamplerMode2To11,
+ kResamplerMode4To11,
+ kResamplerMode8To11,
+ kResamplerMode11To16,
+ kResamplerMode11To32,
+ kResamplerMode2To1,
+ kResamplerMode3To1,
+ kResamplerMode4To1,
+ kResamplerMode6To1,
+ kResamplerMode12To1,
+ kResamplerMode3To2,
+ kResamplerMode11To2,
+ kResamplerMode11To4,
+ kResamplerMode11To8
+ };
+
+ // 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_;
+ int num_channels_;
+
+ // Extra instance for stereo
+ Resampler* slave_left_;
+ Resampler* slave_right_;
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_RESAMPLER_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/push_resampler.cc b/webrtc/common_audio/resampler/push_resampler.cc
new file mode 100644
index 0000000000..566acdeaa3
--- /dev/null
+++ b/webrtc/common_audio/resampler/push_resampler.cc
@@ -0,0 +1,110 @@
+/*
+ * 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 "webrtc/common_audio/resampler/include/push_resampler.h"
+
+#include <string.h>
+
+#include "webrtc/common_audio/include/audio_util.h"
+#include "webrtc/common_audio/resampler/include/resampler.h"
+#include "webrtc/common_audio/resampler/push_sinc_resampler.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,
+ int num_channels) {
+ 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 || num_channels > 2)
+ 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);
+ sinc_resampler_.reset(new PushSincResampler(src_size_10ms_mono,
+ dst_size_10ms_mono));
+ if (num_channels_ == 2) {
+ src_left_.reset(new T[src_size_10ms_mono]);
+ src_right_.reset(new T[src_size_10ms_mono]);
+ dst_left_.reset(new T[dst_size_10ms_mono]);
+ dst_right_.reset(new T[dst_size_10ms_mono]);
+ sinc_resampler_right_.reset(new PushSincResampler(src_size_10ms_mono,
+ dst_size_10ms_mono));
+ }
+
+ return 0;
+}
+
+template <typename T>
+int PushResampler<T>::Resample(const T* src, size_t src_length, T* dst,
+ size_t dst_capacity) {
+ const size_t src_size_10ms =
+ static_cast<size_t>(src_sample_rate_hz_ * num_channels_ / 100);
+ const size_t dst_size_10ms =
+ static_cast<size_t>(dst_sample_rate_hz_ * num_channels_ / 100);
+ if (src_length != src_size_10ms || dst_capacity < dst_size_10ms)
+ return -1;
+
+ 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);
+ }
+ if (num_channels_ == 2) {
+ const size_t src_length_mono = src_length / num_channels_;
+ const size_t dst_capacity_mono = dst_capacity / num_channels_;
+ T* deinterleaved[] = {src_left_.get(), src_right_.get()};
+ Deinterleave(src, src_length_mono, num_channels_, deinterleaved);
+
+ size_t dst_length_mono =
+ sinc_resampler_->Resample(src_left_.get(), src_length_mono,
+ dst_left_.get(), dst_capacity_mono);
+ sinc_resampler_right_->Resample(src_right_.get(), src_length_mono,
+ dst_right_.get(), dst_capacity_mono);
+
+ deinterleaved[0] = dst_left_.get();
+ deinterleaved[1] = dst_right_.get();
+ Interleave(deinterleaved, dst_length_mono, num_channels_, dst);
+ return static_cast<int>(dst_length_mono * num_channels_);
+ } else {
+ return static_cast<int>(
+ sinc_resampler_->Resample(src, src_length, dst, dst_capacity));
+ }
+}
+
+// Explictly generate required instantiations.
+template class PushResampler<int16_t>;
+template class PushResampler<float>;
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/push_resampler_unittest.cc b/webrtc/common_audio/resampler/push_resampler_unittest.cc
new file mode 100644
index 0000000000..4449f4c633
--- /dev/null
+++ b/webrtc/common_audio/resampler/push_resampler_unittest.cc
@@ -0,0 +1,28 @@
+/*
+ * 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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/resampler/include/push_resampler.h"
+
+// Quality testing of PushResampler is handled through output_mixer_unittest.cc.
+
+namespace webrtc {
+
+TEST(PushResamplerTest, VerifiesInputParameters) {
+ PushResampler<int16_t> resampler;
+ EXPECT_EQ(-1, resampler.InitializeIfNeeded(-1, 16000, 1));
+ EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, -1, 1));
+ EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, 16000, 0));
+ EXPECT_EQ(-1, resampler.InitializeIfNeeded(16000, 16000, 3));
+ EXPECT_EQ(0, resampler.InitializeIfNeeded(16000, 16000, 1));
+ EXPECT_EQ(0, resampler.InitializeIfNeeded(16000, 16000, 2));
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/push_sinc_resampler.cc b/webrtc/common_audio/resampler/push_sinc_resampler.cc
new file mode 100644
index 0000000000..a740423eec
--- /dev/null
+++ b/webrtc/common_audio/resampler/push_sinc_resampler.cc
@@ -0,0 +1,103 @@
+/*
+ * 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 "webrtc/common_audio/resampler/push_sinc_resampler.h"
+
+#include <cstring>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/include/audio_util.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/webrtc/common_audio/resampler/push_sinc_resampler.h b/webrtc/common_audio/resampler/push_sinc_resampler.h
new file mode 100644
index 0000000000..cefc62aa2a
--- /dev/null
+++ b/webrtc/common_audio/resampler/push_sinc_resampler.h
@@ -0,0 +1,76 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
+#define WEBRTC_COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/resampler/sinc_resampler.h"
+#include "webrtc/typedefs.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;
+
+ // 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(); }
+
+ rtc::scoped_ptr<SincResampler> resampler_;
+ rtc::scoped_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_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(PushSincResampler);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_PUSH_SINC_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc b/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc
new file mode 100644
index 0000000000..17e3dba1e2
--- /dev/null
+++ b/webrtc/common_audio/resampler/push_sinc_resampler_unittest.cc
@@ -0,0 +1,335 @@
+/*
+ * 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 <cmath>
+#include <cstring>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/include/audio_util.h"
+#include "webrtc/common_audio/resampler/push_sinc_resampler.h"
+#include "webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h"
+#include "webrtc/system_wrappers/include/tick_util.h"
+#include "webrtc/typedefs.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) {
+ 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;
+
+ rtc::scoped_ptr<float[]> resampled_destination(new float[output_samples]);
+ rtc::scoped_ptr<float[]> source(new float[input_samples]);
+ rtc::scoped_ptr<int16_t[]> source_int(new int16_t[input_samples]);
+ rtc::scoped_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);
+ TickTime start = TickTime::Now();
+ for (int i = 0; i < kResampleIterations; ++i) {
+ sinc_resampler.Resample(output_samples, resampled_destination.get());
+ }
+ double total_time_sinc_us = (TickTime::Now() - start).Microseconds();
+ printf("SincResampler took %.2f us per frame.\n",
+ total_time_sinc_us / kResampleIterations);
+
+ PushSincResampler resampler(input_samples, output_samples);
+ start = TickTime::Now();
+ 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 = (TickTime::Now() - start).Microseconds();
+ 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.
+ rtc::scoped_ptr<float[]> resampled_destination(new float[output_samples]);
+ rtc::scoped_ptr<float[]> pure_destination(new float[output_samples]);
+ rtc::scoped_ptr<float[]> source(new float[input_samples]);
+ rtc::scoped_ptr<int16_t[]> source_int(new int16_t[input_block_size]);
+ rtc::scoped_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.02;
+ 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_CASE_P(
+ PushSincResamplerTest,
+ PushSincResamplerTest,
+ ::testing::Values(
+ // First run through the rates tested in SincResamplerTest. The
+ // thresholds are identical.
+ //
+ // We don't test rates which fail to provide an integer number of
+ // samples in a 10 ms block (22050 and 11025 Hz). WebRTC doesn't support
+ // these rates in any case (for the same reason).
+
+ // To 44.1kHz
+ ::testing::make_tuple(8000, 44100, kResamplingRMSError, -62.73),
+ ::testing::make_tuple(16000, 44100, kResamplingRMSError, -62.54),
+ ::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(16000, 48000, kResamplingRMSError, -63.96),
+ ::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(16000, 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(16000, 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(16000, 16000, kResamplingRMSError, -75.51),
+ ::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.96),
+
+ // To 32 kHz
+ ::testing::make_tuple(8000, 32000, kResamplingRMSError, -70.30),
+ ::testing::make_tuple(16000, 32000, kResamplingRMSError, -75.51),
+ ::testing::make_tuple(32000, 32000, kResamplingRMSError, -75.51),
+ ::testing::make_tuple(44100, 32000, -16.44, -51.10),
+ ::testing::make_tuple(48000, 32000, -16.90, -44.03),
+ ::testing::make_tuple(96000, 32000, -19.61, -18.04),
+ ::testing::make_tuple(192000, 32000, -21.02, -10.94)));
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/resampler.cc b/webrtc/common_audio/resampler/resampler.cc
new file mode 100644
index 0000000000..c9e7a1fb96
--- /dev/null
+++ b/webrtc/common_audio/resampler/resampler.cc
@@ -0,0 +1,959 @@
+/*
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include "webrtc/common_audio/resampler/include/resampler.h"
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.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),
+ slave_left_(nullptr),
+ slave_right_(nullptr) {
+}
+
+Resampler::Resampler(int inFreq, int outFreq, int 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 (slave_left_)
+ {
+ delete slave_left_;
+ }
+ if (slave_right_)
+ {
+ delete slave_right_;
+ }
+}
+
+int Resampler::ResetIfNeeded(int inFreq, int outFreq, int 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, int num_channels)
+{
+ if (num_channels != 1 && num_channels != 2) {
+ return -1;
+ }
+ num_channels_ = num_channels;
+
+ if (state1_)
+ {
+ free(state1_);
+ state1_ = NULL;
+ }
+ if (state2_)
+ {
+ free(state2_);
+ state2_ = NULL;
+ }
+ if (state3_)
+ {
+ free(state3_);
+ state3_ = NULL;
+ }
+ if (in_buffer_)
+ {
+ free(in_buffer_);
+ in_buffer_ = NULL;
+ }
+ if (out_buffer_)
+ {
+ free(out_buffer_);
+ out_buffer_ = NULL;
+ }
+ if (slave_left_)
+ {
+ delete slave_left_;
+ slave_left_ = NULL;
+ }
+ if (slave_right_)
+ {
+ delete slave_right_;
+ slave_right_ = NULL;
+ }
+
+ in_buffer_size_ = 0;
+ out_buffer_size_ = 0;
+ in_buffer_size_max_ = 0;
+ out_buffer_size_max_ = 0;
+
+ // Start with a math exercise, Euclid's algorithm to find the gcd:
+ int a = inFreq;
+ int b = outFreq;
+ int c = a % b;
+ while (c != 0)
+ {
+ a = b;
+ b = c;
+ c = a % b;
+ }
+ // b is now the gcd;
+
+ // We need to track what domain we're in.
+ my_in_frequency_khz_ = inFreq / 1000;
+ my_out_frequency_khz_ = outFreq / 1000;
+
+ // Scale with GCD
+ inFreq = inFreq / b;
+ outFreq = outFreq / b;
+
+ if (num_channels_ == 2)
+ {
+ // Create two mono resamplers.
+ slave_left_ = new Resampler(inFreq, outFreq, 1);
+ slave_right_ = new Resampler(inFreq, outFreq, 1);
+ }
+
+ if (inFreq == outFreq)
+ {
+ my_mode_ = kResamplerMode1To1;
+ } else if (inFreq == 1)
+ {
+ switch (outFreq)
+ {
+ case 2:
+ my_mode_ = kResamplerMode1To2;
+ break;
+ case 3:
+ my_mode_ = kResamplerMode1To3;
+ break;
+ case 4:
+ my_mode_ = kResamplerMode1To4;
+ break;
+ case 6:
+ my_mode_ = kResamplerMode1To6;
+ break;
+ case 12:
+ my_mode_ = kResamplerMode1To12;
+ break;
+ default:
+ return -1;
+ }
+ } else if (outFreq == 1)
+ {
+ switch (inFreq)
+ {
+ case 2:
+ my_mode_ = kResamplerMode2To1;
+ break;
+ case 3:
+ my_mode_ = kResamplerMode3To1;
+ break;
+ case 4:
+ my_mode_ = kResamplerMode4To1;
+ break;
+ case 6:
+ my_mode_ = kResamplerMode6To1;
+ break;
+ case 12:
+ my_mode_ = kResamplerMode12To1;
+ break;
+ default:
+ return -1;
+ }
+ } else if ((inFreq == 2) && (outFreq == 3))
+ {
+ my_mode_ = kResamplerMode2To3;
+ } else if ((inFreq == 2) && (outFreq == 11))
+ {
+ my_mode_ = kResamplerMode2To11;
+ } else if ((inFreq == 4) && (outFreq == 11))
+ {
+ my_mode_ = kResamplerMode4To11;
+ } else if ((inFreq == 8) && (outFreq == 11))
+ {
+ my_mode_ = kResamplerMode8To11;
+ } else if ((inFreq == 3) && (outFreq == 2))
+ {
+ my_mode_ = kResamplerMode3To2;
+ } else if ((inFreq == 11) && (outFreq == 2))
+ {
+ my_mode_ = kResamplerMode11To2;
+ } else if ((inFreq == 11) && (outFreq == 4))
+ {
+ my_mode_ = kResamplerMode11To4;
+ } else if ((inFreq == 11) && (outFreq == 16))
+ {
+ my_mode_ = kResamplerMode11To16;
+ } else if ((inFreq == 11) && (outFreq == 32))
+ {
+ my_mode_ = kResamplerMode11To32;
+ } else if ((inFreq == 11) && (outFreq == 8))
+ {
+ my_mode_ = kResamplerMode11To8;
+ } else
+ {
+ return -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((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((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(
+ (WebRtcSpl_State16khzTo48khz*) state3_);
+ break;
+ case kResamplerMode2To3:
+ // 2:6
+ state1_ = malloc(sizeof(WebRtcSpl_State16khzTo48khz));
+ WebRtcSpl_ResetResample16khzTo48khz((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((WebRtcSpl_State8khzTo22khz *)state2_);
+ break;
+ case kResamplerMode4To11:
+ state1_ = malloc(sizeof(WebRtcSpl_State8khzTo22khz));
+ WebRtcSpl_ResetResample8khzTo22khz((WebRtcSpl_State8khzTo22khz *)state1_);
+ break;
+ case kResamplerMode8To11:
+ state1_ = malloc(sizeof(WebRtcSpl_State16khzTo22khz));
+ WebRtcSpl_ResetResample16khzTo22khz((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((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((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((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((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(
+ (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((WebRtcSpl_State48khzTo16khz *)state2_);
+ break;
+ case kResamplerMode11To2:
+ state1_ = malloc(sizeof(WebRtcSpl_State22khzTo8khz));
+ WebRtcSpl_ResetResample22khzTo8khz((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((WebRtcSpl_State22khzTo8khz *)state1_);
+ break;
+ case kResamplerMode11To8:
+ state1_ = malloc(sizeof(WebRtcSpl_State22khzTo16khz));
+ WebRtcSpl_ResetResample22khzTo16khz((WebRtcSpl_State22khzTo16khz *)state1_);
+ break;
+
+ }
+
+ 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 slave object for each channel
+ int16_t* left = (int16_t*)malloc(lengthIn * sizeof(int16_t) / 2);
+ int16_t* right = (int16_t*)malloc(lengthIn * sizeof(int16_t) / 2);
+ int16_t* out_left = (int16_t*)malloc(maxLen / 2 * sizeof(int16_t));
+ int16_t* out_right =
+ (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 |= slave_left_->Push(left, lengthIn, out_left, maxLen / 2, actualOutLen_left);
+ res |= slave_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, (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 = (int32_t*)malloc(336 * sizeof(int32_t));
+
+ for (size_t i = 0; i < lengthIn; i += 160)
+ {
+ WebRtcSpl_Resample16khzTo48khz(samplesIn + i, samplesOut + i * 3,
+ (WebRtcSpl_State16khzTo48khz *)state1_,
+ tmp_mem);
+ }
+ outLen = lengthIn * 3;
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode1To4:
+ if (maxLen < (lengthIn * 4))
+ {
+ return -1;
+ }
+
+ tmp = (int16_t*)malloc(sizeof(int16_t) * 2 * lengthIn);
+ // 1:2
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
+ // 2:4
+ WebRtcSpl_UpsampleBy2(tmp, lengthIn * 2, samplesOut, (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 = (int32_t*)malloc(336 * sizeof(int32_t));
+ tmp = (int16_t*)malloc(sizeof(int16_t) * 2 * lengthIn);
+
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
+ outLen = lengthIn * 2;
+
+ for (size_t i = 0; i < outLen; i += 160)
+ {
+ WebRtcSpl_Resample16khzTo48khz(tmp + i, samplesOut + i * 3,
+ (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 = (int32_t*) malloc(336 * sizeof(int32_t));
+ tmp = (int16_t*) malloc(sizeof(int16_t) * 4 * lengthIn);
+ //1:2
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut,
+ (int32_t*) state1_);
+ outLen = lengthIn * 2;
+ //2:4
+ WebRtcSpl_UpsampleBy2(samplesOut, outLen, tmp, (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,
+ (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 = (int32_t*)malloc(336 * sizeof(int32_t));
+ for (size_t i = 0; i < lengthIn; i += 160)
+ {
+ WebRtcSpl_Resample16khzTo48khz(samplesIn + i, tmp + i * 3,
+ (WebRtcSpl_State16khzTo48khz *)state1_,
+ tmp_mem);
+ }
+ lengthIn = lengthIn * 3;
+ // 6:3
+ WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut, (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 = (int16_t*)malloc(sizeof(int16_t) * 2 * lengthIn);
+ // 1:2
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
+ lengthIn *= 2;
+
+ tmp_mem = (int32_t*)malloc(98 * sizeof(int32_t));
+
+ for (size_t i = 0; i < lengthIn; i += 80)
+ {
+ WebRtcSpl_Resample8khzTo22khz(tmp + i, samplesOut + (i * 11) / 4,
+ (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 = (int32_t*)malloc(98 * sizeof(int32_t));
+
+ for (size_t i = 0; i < lengthIn; i += 80)
+ {
+ WebRtcSpl_Resample8khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 4,
+ (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 = (int32_t*)malloc(88 * sizeof(int32_t));
+
+ for (size_t i = 0; i < lengthIn; i += 160)
+ {
+ WebRtcSpl_Resample16khzTo22khz(samplesIn + i, samplesOut + (i * 11) / 8,
+ (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 = (int32_t*)malloc(104 * sizeof(int32_t));
+ tmp = (int16_t*)malloc((sizeof(int16_t) * lengthIn * 2));
+
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
+
+ for (size_t i = 0; i < (lengthIn * 2); i += 220)
+ {
+ WebRtcSpl_Resample22khzTo16khz(tmp + i, samplesOut + (i / 220) * 160,
+ (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 = (int32_t*)malloc(104 * sizeof(int32_t));
+ tmp = (int16_t*)malloc((sizeof(int16_t) * lengthIn * 2));
+
+ // 11 -> 22 kHz in samplesOut
+ WebRtcSpl_UpsampleBy2(samplesIn, lengthIn, samplesOut, (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,
+ (WebRtcSpl_State22khzTo16khz *)state2_,
+ tmp_mem);
+ }
+
+ // 16 -> 32 in samplesOut
+ WebRtcSpl_UpsampleBy2(tmp, (lengthIn * 16) / 11, samplesOut,
+ (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, (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 = (int32_t*)malloc(496 * sizeof(int32_t));
+
+ for (size_t i = 0; i < lengthIn; i += 480)
+ {
+ WebRtcSpl_Resample48khzTo16khz(samplesIn + i, samplesOut + i / 3,
+ (WebRtcSpl_State48khzTo16khz *)state1_,
+ tmp_mem);
+ }
+ outLen = lengthIn / 3;
+ free(tmp_mem);
+ return 0;
+ case kResamplerMode4To1:
+ if (maxLen < (lengthIn / 4))
+ {
+ return -1;
+ }
+ tmp = (int16_t*)malloc(sizeof(int16_t) * lengthIn / 2);
+ // 4:2
+ WebRtcSpl_DownsampleBy2(samplesIn, lengthIn, tmp, (int32_t*)state1_);
+ // 2:1
+ WebRtcSpl_DownsampleBy2(tmp, lengthIn / 2, samplesOut, (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 = (int32_t*)malloc(496 * sizeof(int32_t));
+ tmp = (int16_t*)malloc((sizeof(int16_t) * lengthIn) / 3);
+
+ for (size_t i = 0; i < lengthIn; i += 480)
+ {
+ WebRtcSpl_Resample48khzTo16khz(samplesIn + i, tmp + i / 3,
+ (WebRtcSpl_State48khzTo16khz *)state1_,
+ tmp_mem);
+ }
+ outLen = lengthIn / 3;
+ free(tmp_mem);
+ WebRtcSpl_DownsampleBy2(tmp, outLen, samplesOut, (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 = (int32_t*) malloc(496 * sizeof(int32_t));
+ tmp = (int16_t*) malloc((sizeof(int16_t) * lengthIn) / 3);
+ tmp_2 = (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,
+ (WebRtcSpl_State48khzTo16khz*) state1_,
+ tmp_mem);
+ }
+ outLen = lengthIn / 3;
+ free(tmp_mem);
+ // 4:2
+ WebRtcSpl_DownsampleBy2(tmp, outLen, tmp_2, (int32_t*) state2_);
+ outLen = outLen / 2;
+ free(tmp);
+ // 2:1
+ WebRtcSpl_DownsampleBy2(tmp_2, outLen, samplesOut,
+ (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, (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 = (int32_t*)malloc(496 * sizeof(int32_t));
+ for (size_t i = 0; i < lengthIn; i += 480)
+ {
+ WebRtcSpl_Resample48khzTo16khz(tmp + i, samplesOut + i / 3,
+ (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 = (int32_t*)malloc(126 * sizeof(int32_t));
+ tmp = (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,
+ (WebRtcSpl_State22khzTo8khz *)state1_,
+ tmp_mem);
+ }
+ lengthIn = (lengthIn * 4) / 11;
+
+ WebRtcSpl_DownsampleBy2(tmp, lengthIn, samplesOut,
+ (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 = (int32_t*)malloc(126 * sizeof(int32_t));
+
+ for (size_t i = 0; i < lengthIn; i += 220)
+ {
+ WebRtcSpl_Resample22khzTo8khz(samplesIn + i, samplesOut + (i * 4) / 11,
+ (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 = (int32_t*)malloc(104 * sizeof(int32_t));
+
+ for (size_t i = 0; i < lengthIn; i += 220)
+ {
+ WebRtcSpl_Resample22khzTo16khz(samplesIn + i, samplesOut + (i * 8) / 11,
+ (WebRtcSpl_State22khzTo16khz *)state1_,
+ tmp_mem);
+ }
+ outLen = (lengthIn * 8) / 11;
+ free(tmp_mem);
+ return 0;
+ break;
+
+ }
+ return 0;
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/resampler_unittest.cc b/webrtc/common_audio/resampler/resampler_unittest.cc
new file mode 100644
index 0000000000..c5953d030b
--- /dev/null
+++ b/webrtc/common_audio/resampler/resampler_unittest.cc
@@ -0,0 +1,139 @@
+/*
+ * 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 "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/common_audio/resampler/include/resampler.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();
+ virtual void SetUp();
+ virtual void TearDown();
+
+ 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() {}
+
+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) {
+ std::ostringstream 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) {
+ std::ostringstream 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) {
+ std::ostringstream 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));
+ }
+ }
+ }
+}
+
+} // namespace
+} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/sinc_resampler.cc b/webrtc/common_audio/resampler/sinc_resampler.cc
new file mode 100644
index 0000000000..69ac2208cf
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinc_resampler.cc
@@ -0,0 +1,378 @@
+/*
+ * 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 "webrtc/common_audio/resampler/sinc_resampler.h"
+
+#include <assert.h>
+#include <math.h>
+#include <string.h>
+
+#include <limits>
+
+#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
+#include "webrtc/typedefs.h"
+
+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
+
+// If we know the minimum architecture at compile time, avoid CPU detection.
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#if defined(__SSE2__)
+#define CONVOLVE_FUNC Convolve_SSE
+void SincResampler::InitializeCPUSpecificFeatures() {}
+#else
+// x86 CPU detection required. Function will be set by
+// InitializeCPUSpecificFeatures().
+// TODO(dalecurtis): Once Chrome moves to an SSE baseline this can be removed.
+#define CONVOLVE_FUNC convolve_proc_
+
+void SincResampler::InitializeCPUSpecificFeatures() {
+ convolve_proc_ = WebRtc_GetCPUInfo(kSSE2) ? Convolve_SSE : Convolve_C;
+}
+#endif
+#elif defined(WEBRTC_HAS_NEON)
+#define CONVOLVE_FUNC Convolve_NEON
+void SincResampler::InitializeCPUSpecificFeatures() {}
+#elif defined(WEBRTC_DETECT_NEON)
+#define CONVOLVE_FUNC convolve_proc_
+void SincResampler::InitializeCPUSpecificFeatures() {
+ convolve_proc_ = WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON ?
+ Convolve_NEON : Convolve_C;
+}
+#else
+// Unknown architecture.
+#define CONVOLVE_FUNC Convolve_C
+void SincResampler::InitializeCPUSpecificFeatures() {}
+#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 16-byte alignment for SSE optimizations.
+ kernel_storage_(static_cast<float*>(
+ AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
+ kernel_pre_sinc_storage_(static_cast<float*>(
+ AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
+ kernel_window_storage_(static_cast<float*>(
+ AlignedMalloc(sizeof(float) * kKernelStorageSize, 16))),
+ input_buffer_(static_cast<float*>(
+ AlignedMalloc(sizeof(float) * input_buffer_size_, 16))),
+#if defined(WEBRTC_CPU_DETECTION)
+ convolve_proc_(NULL),
+#endif
+ r1_(input_buffer_.get()),
+ r2_(input_buffer_.get() + kKernelSize / 2) {
+#if defined(WEBRTC_CPU_DETECTION)
+ InitializeCPUSpecificFeatures();
+ assert(convolve_proc_);
+#endif
+ assert(request_frames_ > 0);
+ Flush();
+ assert(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.
+ assert(r1_ == input_buffer_.get());
+ // r1_ left of r2_, r4_ left of r3_ and size correct.
+ assert(r2_ - r1_ == r4_ - r3_);
+ // r2_ left of r3.
+ assert(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) {
+ assert(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 16-byte aligned for SIMD usage. Should always be
+ // true so long as kKernelSize is a multiple of 16.
+ assert(0u == (reinterpret_cast<uintptr_t>(k1) & 0x0F));
+ assert(0u == (reinterpret_cast<uintptr_t>(k2) & 0x0F));
+
+ // 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_FUNC(
+ 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/webrtc/common_audio/resampler/sinc_resampler.h b/webrtc/common_audio/resampler/sinc_resampler.h
new file mode 100644
index 0000000000..45ade0cc69
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinc_resampler.h
@@ -0,0 +1,170 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
+#define WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/system_wrappers/include/aligned_malloc.h"
+#include "webrtc/test/testsupport/gtest_prod_util.h"
+#include "webrtc/typedefs.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();
+
+ // 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);
+#elif defined(WEBRTC_DETECT_NEON) || 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.
+ rtc::scoped_ptr<float[], AlignedFreeDeleter> kernel_storage_;
+ rtc::scoped_ptr<float[], AlignedFreeDeleter> kernel_pre_sinc_storage_;
+ rtc::scoped_ptr<float[], AlignedFreeDeleter> kernel_window_storage_;
+
+ // Data from the source is copied into this buffer for each processing pass.
+ rtc::scoped_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.
+#if defined(WEBRTC_CPU_DETECTION)
+ typedef float (*ConvolveProc)(const float*, const float*, const float*,
+ double);
+ ConvolveProc convolve_proc_;
+#endif
+
+ // 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_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(SincResampler);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_SINC_RESAMPLER_H_
diff --git a/webrtc/common_audio/resampler/sinc_resampler_neon.cc b/webrtc/common_audio/resampler/sinc_resampler_neon.cc
new file mode 100644
index 0000000000..e909a6c5de
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinc_resampler_neon.cc
@@ -0,0 +1,47 @@
+/*
+ * 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 "webrtc/common_audio/resampler/sinc_resampler.h"
+
+#include <arm_neon.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/webrtc/common_audio/resampler/sinc_resampler_sse.cc b/webrtc/common_audio/resampler/sinc_resampler_sse.cc
new file mode 100644
index 0000000000..9e3953fede
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinc_resampler_sse.cc
@@ -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.
+ */
+
+// Modified from the Chromium original:
+// src/media/base/simd/sinc_resampler_sse.cc
+
+#include "webrtc/common_audio/resampler/sinc_resampler.h"
+
+#include <xmmintrin.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/webrtc/common_audio/resampler/sinc_resampler_unittest.cc b/webrtc/common_audio/resampler/sinc_resampler_unittest.cc
new file mode 100644
index 0000000000..b8d6c341a2
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinc_resampler_unittest.cc
@@ -0,0 +1,389 @@
+/*
+ * 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 <math.h>
+
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/resampler/sinc_resampler.h"
+#include "webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h"
+#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
+#include "webrtc/system_wrappers/include/stringize_macros.h"
+#include "webrtc/system_wrappers/include/tick_util.h"
+#include "webrtc/test/test_suite.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_METHOD2(Run, void(size_t frames, float* destination));
+};
+
+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;
+ rtc::scoped_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);
+ rtc::scoped_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);
+
+ TickTime start = TickTime::Now();
+ for (int i = 1; i < 10000; ++i)
+ resampler.SetRatio(1.0 / i);
+ double total_time_c_us = (TickTime::Now() - start).Microseconds();
+ printf("SetRatio() took %.2fms.\n", total_time_c_us / 1000);
+}
+
+
+// Define platform independent function name for Convolve* tests.
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+#define CONVOLVE_FUNC Convolve_SSE
+#elif defined(WEBRTC_ARCH_ARM_V7)
+#define CONVOLVE_FUNC Convolve_NEON
+#endif
+
+// 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.
+#if defined(CONVOLVE_FUNC)
+TEST(SincResamplerTest, Convolve) {
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ ASSERT_TRUE(WebRtc_GetCPUInfo(kSSE2));
+#elif defined(WEBRTC_ARCH_ARM_V7)
+ ASSERT_TRUE(WebRtc_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_FUNC(
+ 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_FUNC(
+ resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(),
+ resampler.kernel_storage_.get(), kKernelInterpolationFactor);
+ EXPECT_NEAR(result2, result, kEpsilon);
+}
+#endif
+
+// 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().
+ TickTime start = TickTime::Now();
+ 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 = (TickTime::Now() - start).Microseconds();
+ printf("Convolve_C took %.2fms.\n", total_time_c_us / 1000);
+
+#if defined(CONVOLVE_FUNC)
+#if defined(WEBRTC_ARCH_X86_FAMILY)
+ ASSERT_TRUE(WebRtc_GetCPUInfo(kSSE2));
+#elif defined(WEBRTC_ARCH_ARM_V7)
+ ASSERT_TRUE(WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON);
+#endif
+
+ // Benchmark with unaligned input pointer.
+ start = TickTime::Now();
+ for (int j = 0; j < kConvolveIterations; ++j) {
+ resampler.CONVOLVE_FUNC(
+ resampler.kernel_storage_.get() + 1, resampler.kernel_storage_.get(),
+ resampler.kernel_storage_.get(), kKernelInterpolationFactor);
+ }
+ double total_time_optimized_unaligned_us =
+ (TickTime::Now() - start).Microseconds();
+ printf(STRINGIZE(CONVOLVE_FUNC) "(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 = TickTime::Now();
+ for (int j = 0; j < kConvolveIterations; ++j) {
+ resampler.CONVOLVE_FUNC(
+ resampler.kernel_storage_.get(), resampler.kernel_storage_.get(),
+ resampler.kernel_storage_.get(), kKernelInterpolationFactor);
+ }
+ double total_time_optimized_aligned_us =
+ (TickTime::Now() - start).Microseconds();
+ printf(STRINGIZE(CONVOLVE_FUNC) " (aligned) took %.2fms; which is %.2fx "
+ "faster than Convolve_C and %.2fx faster than "
+ STRINGIZE(CONVOLVE_FUNC) " (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);
+#endif
+}
+
+#undef CONVOLVE_FUNC
+
+typedef std::tr1::tuple<int, int, double, double> SincResamplerTestData;
+class SincResamplerTest
+ : public testing::TestWithParam<SincResamplerTestData> {
+ public:
+ SincResamplerTest()
+ : input_rate_(std::tr1::get<0>(GetParam())),
+ output_rate_(std::tr1::get<1>(GetParam())),
+ rms_error_(std::tr1::get<2>(GetParam())),
+ low_freq_error_(std::tr1::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 dyanmic sample rate
+ // changes are working correctly.
+ rtc::scoped_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.
+ rtc::scoped_ptr<float[]> resampled_destination(new float[output_samples]);
+ rtc::scoped_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_CASE_P(
+ SincResamplerTest, SincResamplerTest, testing::Values(
+ // To 44.1kHz
+ std::tr1::make_tuple(8000, 44100, kResamplingRMSError, -62.73),
+ std::tr1::make_tuple(11025, 44100, kResamplingRMSError, -72.19),
+ std::tr1::make_tuple(16000, 44100, kResamplingRMSError, -62.54),
+ std::tr1::make_tuple(22050, 44100, kResamplingRMSError, -73.53),
+ std::tr1::make_tuple(32000, 44100, kResamplingRMSError, -63.32),
+ std::tr1::make_tuple(44100, 44100, kResamplingRMSError, -73.53),
+ std::tr1::make_tuple(48000, 44100, -15.01, -64.04),
+ std::tr1::make_tuple(96000, 44100, -18.49, -25.51),
+ std::tr1::make_tuple(192000, 44100, -20.50, -13.31),
+
+ // To 48kHz
+ std::tr1::make_tuple(8000, 48000, kResamplingRMSError, -63.43),
+ std::tr1::make_tuple(11025, 48000, kResamplingRMSError, -62.61),
+ std::tr1::make_tuple(16000, 48000, kResamplingRMSError, -63.96),
+ std::tr1::make_tuple(22050, 48000, kResamplingRMSError, -62.42),
+ std::tr1::make_tuple(32000, 48000, kResamplingRMSError, -64.04),
+ std::tr1::make_tuple(44100, 48000, kResamplingRMSError, -62.63),
+ std::tr1::make_tuple(48000, 48000, kResamplingRMSError, -73.52),
+ std::tr1::make_tuple(96000, 48000, -18.40, -28.44),
+ std::tr1::make_tuple(192000, 48000, -20.43, -14.11),
+
+ // To 96kHz
+ std::tr1::make_tuple(8000, 96000, kResamplingRMSError, -63.19),
+ std::tr1::make_tuple(11025, 96000, kResamplingRMSError, -62.61),
+ std::tr1::make_tuple(16000, 96000, kResamplingRMSError, -63.39),
+ std::tr1::make_tuple(22050, 96000, kResamplingRMSError, -62.42),
+ std::tr1::make_tuple(32000, 96000, kResamplingRMSError, -63.95),
+ std::tr1::make_tuple(44100, 96000, kResamplingRMSError, -62.63),
+ std::tr1::make_tuple(48000, 96000, kResamplingRMSError, -73.52),
+ std::tr1::make_tuple(96000, 96000, kResamplingRMSError, -73.52),
+ std::tr1::make_tuple(192000, 96000, kResamplingRMSError, -28.41),
+
+ // To 192kHz
+ std::tr1::make_tuple(8000, 192000, kResamplingRMSError, -63.10),
+ std::tr1::make_tuple(11025, 192000, kResamplingRMSError, -62.61),
+ std::tr1::make_tuple(16000, 192000, kResamplingRMSError, -63.14),
+ std::tr1::make_tuple(22050, 192000, kResamplingRMSError, -62.42),
+ std::tr1::make_tuple(32000, 192000, kResamplingRMSError, -63.38),
+ std::tr1::make_tuple(44100, 192000, kResamplingRMSError, -62.63),
+ std::tr1::make_tuple(48000, 192000, kResamplingRMSError, -73.44),
+ std::tr1::make_tuple(96000, 192000, kResamplingRMSError, -73.52),
+ std::tr1::make_tuple(192000, 192000, kResamplingRMSError, -73.52)));
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc
new file mode 100644
index 0000000000..5d215688ba
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.cc
@@ -0,0 +1,58 @@
+/*
+ * 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 "webrtc/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/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h
new file mode 100644
index 0000000000..1807f86a19
--- /dev/null
+++ b/webrtc/common_audio/resampler/sinusoidal_linear_chirp_source.h
@@ -0,0 +1,55 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
+#define WEBRTC_COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
+
+#include "webrtc/base/constructormagic.h"
+#include "webrtc/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);
+
+ virtual ~SinusoidalLinearChirpSource() {}
+
+ void Run(size_t frames, float* destination) override;
+
+ double Frequency(size_t position);
+
+ private:
+ enum {
+ kMinFrequency = 5
+ };
+
+ int sample_rate_;
+ size_t total_samples_;
+ double max_frequency_;
+ double k_;
+ size_t current_index_;
+ double delay_samples_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(SinusoidalLinearChirpSource);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_RESAMPLER_SINUSOIDAL_LINEAR_CHIRP_SOURCE_H_
diff --git a/webrtc/common_audio/ring_buffer.c b/webrtc/common_audio/ring_buffer.c
new file mode 100644
index 0000000000..60fb5dff20
--- /dev/null
+++ b/webrtc/common_audio/ring_buffer.c
@@ -0,0 +1,247 @@
+/*
+ * 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 "webrtc/common_audio/ring_buffer.h"
+
+#include <stddef.h> // size_t
+#include <stdlib.h>
+#include <string.h>
+
+enum Wrap {
+ SAME_WRAP,
+ DIFF_WRAP
+};
+
+struct RingBuffer {
+ size_t read_pos;
+ size_t write_pos;
+ size_t element_count;
+ size_t element_size;
+ enum Wrap rw_wrap;
+ char* data;
+};
+
+// 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 = 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/webrtc/common_audio/ring_buffer.h b/webrtc/common_audio/ring_buffer.h
new file mode 100644
index 0000000000..4125c48d01
--- /dev/null
+++ b/webrtc/common_audio/ring_buffer.h
@@ -0,0 +1,66 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_RING_BUFFER_H_
+#define WEBRTC_COMMON_AUDIO_RING_BUFFER_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stddef.h> // size_t
+
+typedef struct RingBuffer 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. The |data_ptr| will point to the address where
+// it is located. If all |element_count| data are feasible to read without
+// buffer wrap around |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 // WEBRTC_COMMON_AUDIO_RING_BUFFER_H_
diff --git a/webrtc/common_audio/ring_buffer_unittest.cc b/webrtc/common_audio/ring_buffer_unittest.cc
new file mode 100644
index 0000000000..f8cce74d9c
--- /dev/null
+++ b/webrtc/common_audio/ring_buffer_unittest.cc
@@ -0,0 +1,149 @@
+/*
+ * 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 "webrtc/common_audio/ring_buffer.h"
+
+#include <stdlib.h>
+#include <time.h>
+#include <algorithm>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/scoped_ptr.h"
+
+namespace webrtc {
+
+struct FreeBufferDeleter {
+ inline void operator()(void* ptr) const {
+ WebRtc_FreeBuffer(ptr);
+ }
+};
+typedef rtc::scoped_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(NULL);
+ printf("seed=%u\n", seed);
+ srand(seed);
+ for (int i = 0; i < kNumTests; i++) {
+ const int buffer_size = std::max(rand() % kMaxBufferSize, 1);
+ rtc::scoped_ptr<int[]> write_data(new int[buffer_size]);
+ rtc::scoped_ptr<int[]> read_data(new int[buffer_size]);
+ scoped_ring_buffer buffer(WebRtc_CreateBuffer(buffer_size, sizeof(int)));
+ ASSERT_TRUE(buffer.get() != NULL);
+ 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;
+ const int num_elements = rand() % buffer_size;
+ 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 = NULL;
+ RandomStressTest(&data_ptr);
+}
+
+TEST(RingBufferTest, RandomStressTestWithNullPtr) {
+ RandomStressTest(NULL);
+}
+
+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() != NULL);
+ 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(), NULL, 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) == NULL);
+ EXPECT_TRUE(WebRtc_CreateBuffer(1, 0) == NULL);
+ RingBuffer* buffer = WebRtc_CreateBuffer(1, 1);
+ EXPECT_TRUE(buffer != NULL);
+ WebRtc_FreeBuffer(buffer);
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/signal_processing/Android.mk b/webrtc/common_audio/signal_processing/Android.mk
new file mode 100644
index 0000000000..8f2f67813d
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/Android.mk
@@ -0,0 +1,104 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(LOCAL_PATH)/../../../android-webrtc.mk
+
+LOCAL_ARM_MODE := arm
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := libwebrtc_spl
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := \
+ auto_corr_to_refl_coef.c \
+ auto_correlation.c \
+ complex_fft.c \
+ copy_set_operations.c \
+ division_operations.c \
+ dot_product_with_scale.c \
+ energy.c \
+ filter_ar.c \
+ filter_ma_fast_q12.c \
+ get_hanning_window.c \
+ get_scaling_square.c \
+ ilbc_specific_functions.c \
+ levinson_durbin.c \
+ lpc_to_refl_coef.c \
+ min_max_operations.c \
+ randomization_functions.c \
+ real_fft.c \
+ refl_coef_to_lpc.c \
+ resample.c \
+ resample_48khz.c \
+ resample_by_2.c \
+ resample_by_2_internal.c \
+ resample_fractional.c \
+ spl_init.c \
+ spl_sqrt.c \
+ splitting_filter.c \
+ sqrt_of_one_minus_x_squared.c \
+ vector_scaling_operations.c
+
+# Flags passed to both C and C++ files.
+LOCAL_CFLAGS := \
+ $(MY_WEBRTC_COMMON_DEFS)
+
+LOCAL_CFLAGS_arm := $(MY_WEBRTC_COMMON_DEFS_arm)
+LOCAL_CFLAGS_x86 := $(MY_WEBRTC_COMMON_DEFS_x86)
+LOCAL_CFLAGS_mips := $(MY_WEBRTC_COMMON_DEFS_mips)
+LOCAL_CFLAGS_arm64 := $(MY_WEBRTC_COMMON_DEFS_arm64)
+LOCAL_CFLAGS_x86_64 := $(MY_WEBRTC_COMMON_DEFS_x86_64)
+LOCAL_CFLAGS_mips64 := $(MY_WEBRTC_COMMON_DEFS_mips64)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../../..
+
+# Some new .s files have compilation error with AOSP configuration,
+# so they are not used. The next merge of upstream .S file might work.
+#ifeq ($(ARCH_ARM_HAVE_NEON),true)
+#LOCAL_SRC_FILES += \
+# cross_correlation_neon.s \
+# downsample_fast_neon.s \
+# min_max_operations_neon.s \
+# vector_scaling_operations_neon.s
+#LOCAL_CFLAGS += \
+# $(MY_ARM_CFLAGS_NEON)
+#else
+LOCAL_SRC_FILES += \
+ cross_correlation.c \
+ downsample_fast.c
+#endif
+
+#ifeq ($(ARCH_ARM_HAVE_ARMV7A),true)
+#LOCAL_SRC_FILES += \
+# filter_ar_fast_q12_armv7.S
+#else
+LOCAL_SRC_FILES += \
+ filter_ar_fast_q12.c
+#endif
+
+ifeq ($(TARGET_ARCH),arm)
+LOCAL_SRC_FILES += \
+ complex_bit_reverse_arm.S \
+ spl_sqrt_floor_arm.S
+else
+LOCAL_SRC_FILES += \
+ complex_bit_reverse.c \
+ spl_sqrt_floor.c
+endif
+
+ifdef WEBRTC_STL
+LOCAL_NDK_STL_VARIANT := $(WEBRTC_STL)
+LOCAL_SDK_VERSION := 14
+LOCAL_MODULE := $(LOCAL_MODULE)_$(WEBRTC_STL)
+endif
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c b/webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
new file mode 100644
index 0000000000..f99dd62b82
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/auto_correlation.c b/webrtc/common_audio/signal_processing/auto_correlation.c
new file mode 100644
index 0000000000..fda4fffeed
--- /dev/null
+++ b/webrtc/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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+#include <assert.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;
+
+ assert(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/webrtc/common_audio/signal_processing/complex_bit_reverse.c b/webrtc/common_audio/signal_processing/complex_bit_reverse.c
new file mode 100644
index 0000000000..c8bd2dc457
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S b/webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
new file mode 100644
index 0000000000..93de99f51b
--- /dev/null
+++ b/webrtc/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 "webrtc/system_wrappers/include/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/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c b/webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
new file mode 100644
index 0000000000..583fe4f610
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/complex_fft.c b/webrtc/common_audio/signal_processing/complex_fft.c
new file mode 100644
index 0000000000..97ebacc498
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/complex_fft.c
@@ -0,0 +1,298 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/complex_fft_tables.h"
+#include "webrtc/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, 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]) << CFFTSFT;
+ qi32 = ((int32_t)frfi[2 * i + 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 = 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]) << CIFFTSFT;
+ qi32 = ((int32_t)frfi[2 * i + 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/webrtc/common_audio/signal_processing/complex_fft_mips.c b/webrtc/common_audio/signal_processing/complex_fft_mips.c
new file mode 100644
index 0000000000..34c4f232a0
--- /dev/null
+++ b/webrtc/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 "webrtc/common_audio/signal_processing/complex_fft_tables.h"
+#include "webrtc/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/webrtc/common_audio/signal_processing/complex_fft_tables.h b/webrtc/common_audio/signal_processing/complex_fft_tables.h
new file mode 100644
index 0000000000..ca7b7fe39b
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/complex_fft_tables.h
@@ -0,0 +1,148 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
+#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
+
+#include "webrtc/typedefs.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 // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_COMPLEX_FFT_TABLES_H_
diff --git a/webrtc/common_audio/signal_processing/copy_set_operations.c b/webrtc/common_audio/signal_processing/copy_set_operations.c
new file mode 100644
index 0000000000..9d7cf47e3b
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/cross_correlation.c b/webrtc/common_audio/signal_processing/cross_correlation.c
new file mode 100644
index 0000000000..d7c9f2b9af
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/cross_correlation_mips.c b/webrtc/common_audio/signal_processing/cross_correlation_mips.c
new file mode 100644
index 0000000000..b2364026c6
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/cross_correlation_neon.c b/webrtc/common_audio/signal_processing/cross_correlation_neon.c
new file mode 100644
index 0000000000..918b6715cd
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/cross_correlation_neon.c
@@ -0,0 +1,87 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.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/webrtc/common_audio/signal_processing/division_operations.c b/webrtc/common_audio/signal_processing/division_operations.c
new file mode 100644
index 0000000000..eaa06a1ff9
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/division_operations.c
@@ -0,0 +1,138 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.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
+
+ tmpW32 = (int32_t)0x7fffffffL - tmpW32; // result in Q30 (tmpW32 = 2.0-(den*approx))
+
+ // 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/webrtc/common_audio/signal_processing/dot_product_with_scale.c b/webrtc/common_audio/signal_processing/dot_product_with_scale.c
new file mode 100644
index 0000000000..1302d62541
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/dot_product_with_scale.c
@@ -0,0 +1,32 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+int32_t WebRtcSpl_DotProductWithScale(const int16_t* vector1,
+ const int16_t* vector2,
+ size_t length,
+ int scaling) {
+ int32_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 sum;
+}
diff --git a/webrtc/common_audio/signal_processing/downsample_fast.c b/webrtc/common_audio/signal_processing/downsample_fast.c
new file mode 100644
index 0000000000..726a88819a
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/downsample_fast.c
@@ -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.
+ */
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.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) {
+ 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;
+ }
+
+ for (i = delay; i < endpos; i += factor) {
+ out_s32 = 2048; // Round value, 0.5 in Q12.
+
+ for (j = 0; j < coefficients_length; j++) {
+ out_s32 += coefficients[j] * data_in[i - j]; // Q12.
+ }
+
+ out_s32 >>= 12; // Q0.
+
+ // Saturate and store the output.
+ *data_out++ = WebRtcSpl_SatW32ToW16(out_s32);
+ }
+
+ return 0;
+}
diff --git a/webrtc/common_audio/signal_processing/downsample_fast_mips.c b/webrtc/common_audio/signal_processing/downsample_fast_mips.c
new file mode 100644
index 0000000000..ac39401abb
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/downsample_fast_neon.c b/webrtc/common_audio/signal_processing/downsample_fast_neon.c
new file mode 100644
index 0000000000..58732dab1c
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/energy.c b/webrtc/common_audio/signal_processing/energy.c
new file mode 100644
index 0000000000..e83f1a698f
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/filter_ar.c b/webrtc/common_audio/signal_processing/filter_ar.c
new file mode 100644
index 0000000000..dfbc4c2f7a
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/filter_ar.c
@@ -0,0 +1,89 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.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)
+{
+ int32_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];
+ int16_t* filtered_ptr = &filtered[i - 1];
+ int16_t* filtered_low_ptr = &filtered_low[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++) << 12;
+ oLOW = (int32_t)0;
+
+ stop = (i < a_length) ? i + 1 : a_length;
+ for (j = 1; j < stop; j++)
+ {
+ o -= *a_ptr * *filtered_ptr--;
+ oLOW -= *a_ptr++ * *filtered_low_ptr--;
+ }
+ 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++)
+ << 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[state_length - x_length + i] = filtered_low[i];
+ }
+ }
+
+ return x_length;
+}
diff --git a/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c b/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
new file mode 100644
index 0000000000..70001a0882
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
@@ -0,0 +1,42 @@
+/*
+ * 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 <assert.h>
+
+#include "webrtc/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;
+
+ assert(data_length > 0);
+ assert(coefficients_length > 1);
+
+ for (i = 0; i < data_length; i++) {
+ int32_t output = 0;
+ int32_t sum = 0;
+
+ for (j = coefficients_length - 1; j > 0; j--) {
+ sum += coefficients[j] * data_out[i - 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/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S b/webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
new file mode 100644
index 0000000000..f16362738a
--- /dev/null
+++ b/webrtc/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 "webrtc/system_wrappers/include/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/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c b/webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
new file mode 100644
index 0000000000..03847018e3
--- /dev/null
+++ b/webrtc/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 <assert.h>
+
+#include "webrtc/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)
+
+ assert(data_length > 0);
+ assert(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/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c b/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
new file mode 100644
index 0000000000..f4d9a3d303
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
@@ -0,0 +1,45 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.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;
+ for (i = 0; i < length; i++)
+ {
+ int32_t o = 0;
+
+ for (j = 0; j < B_length; j++)
+ {
+ o += B[j] * in_ptr[i - 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/webrtc/common_audio/signal_processing/get_hanning_window.c b/webrtc/common_audio/signal_processing/get_hanning_window.c
new file mode 100644
index 0000000000..d83ac21682
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/get_scaling_square.c b/webrtc/common_audio/signal_processing/get_scaling_square.c
new file mode 100644
index 0000000000..82e3c8b09c
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/ilbc_specific_functions.c b/webrtc/common_audio/signal_processing/ilbc_specific_functions.c
new file mode 100644
index 0000000000..301a922d79
--- /dev/null
+++ b/webrtc/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 "webrtc/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, 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, 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/webrtc/common_audio/signal_processing/include/real_fft.h b/webrtc/common_audio/signal_processing/include/real_fft.h
new file mode 100644
index 0000000000..e7942f04c4
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/include/real_fft.h
@@ -0,0 +1,97 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
+#define WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
+
+#include "webrtc/typedefs.h"
+
+// For ComplexFFT(), the maximum fft order is 10;
+// for OpenMax FFT in ARM, it is 12;
+// 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 // WEBRTC_COMMON_AUDIO_SIGNAL_PROCESSING_INCLUDE_REAL_FFT_H_
diff --git a/webrtc/common_audio/signal_processing/include/signal_processing_library.h b/webrtc/common_audio/signal_processing/include/signal_processing_library.h
new file mode 100644
index 0000000000..2e96883e6d
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/include/signal_processing_library.h
@@ -0,0 +1,1645 @@
+/*
+ * 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 WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_
+#define WEBRTC_SPL_SIGNAL_PROCESSING_LIBRARY_H_
+
+#include <string.h>
+#include "webrtc/typedefs.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))
+
+#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) << 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) << 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) \
+ + (((WEBRTC_SPL_MUL_16_U16(a, (uint16_t)(b)) >> 1) + 0x2000) >> 14))
+
+#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)(0x0000FFFF & B) * 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) << (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 "webrtc/common_audio/signal_processing/include/spl_inl.h"
+
+// Initialize SPL. Currently it contains only function pointer initialization.
+// If the underlying platform is known to be ARM-Neon (WEBRTC_HAS_NEON defined),
+// the pointers will be assigned to code optimized for Neon; otherwise
+// if run-time Neon detection (WEBRTC_DETECT_NEON) is enabled, the pointers
+// will be assigned to either Neon code or generic C code; otherwise, generic C
+// code will be assigned.
+// Note that this function MUST be called in any application that uses SPL
+// functions.
+void WebRtcSpl_Init();
+
+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 MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
+int16_t WebRtcSpl_MaxAbsValueW16C(const int16_t* vector, size_t length);
+#if (defined WEBRTC_DETECT_NEON) || (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 MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
+int32_t WebRtcSpl_MaxAbsValueW32C(const int32_t* vector, size_t length);
+#if (defined WEBRTC_DETECT_NEON) || (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 MaxValueW16 WebRtcSpl_MaxValueW16;
+int16_t WebRtcSpl_MaxValueW16C(const int16_t* vector, size_t length);
+#if (defined WEBRTC_DETECT_NEON) || (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 MaxValueW32 WebRtcSpl_MaxValueW32;
+int32_t WebRtcSpl_MaxValueW32C(const int32_t* vector, size_t length);
+#if (defined WEBRTC_DETECT_NEON) || (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 MinValueW16 WebRtcSpl_MinValueW16;
+int16_t WebRtcSpl_MinValueW16C(const int16_t* vector, size_t length);
+#if (defined WEBRTC_DETECT_NEON) || (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 MinValueW32 WebRtcSpl_MinValueW32;
+int32_t WebRtcSpl_MinValueW32C(const int32_t* vector, size_t length);
+#if (defined WEBRTC_DETECT_NEON) || (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 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 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 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,
+ 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,
+ 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 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_DETECT_NEON) || (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);
+int32_t WebRtcSpl_SqrtFloor(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);
+
+// 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);
+
+// 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 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_DETECT_NEON) || (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 // WEBRTC_SPL_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_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
+//
+
+//
+// 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/webrtc/common_audio/signal_processing/include/spl_inl.h b/webrtc/common_audio/signal_processing/include/spl_inl.h
new file mode 100644
index 0000000000..d3cc6dee6c
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/include/spl_inl.h
@@ -0,0 +1,173 @@
+/*
+ * 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 WEBRTC_SPL_SPL_INL_H_
+#define WEBRTC_SPL_SPL_INL_H_
+
+#ifdef WEBRTC_ARCH_ARM_V7
+#include "webrtc/common_audio/signal_processing/include/spl_inl_armv7.h"
+#else
+
+#if defined(MIPS32_LE)
+#include "webrtc/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 l_var1, int32_t l_var2) {
+ int32_t l_sum;
+
+ // Perform long addition
+ l_sum = l_var1 + l_var2;
+
+ if (l_var1 < 0) { // Check for underflow.
+ if ((l_var2 < 0) && (l_sum >= 0)) {
+ l_sum = (int32_t)0x80000000;
+ }
+ } else { // Check for overflow.
+ if ((l_var2 > 0) && (l_sum < 0)) {
+ l_sum = (int32_t)0x7FFFFFFF;
+ }
+ }
+
+ return l_sum;
+}
+
+static __inline int32_t WebRtcSpl_SubSatW32(int32_t l_var1, int32_t l_var2) {
+ int32_t l_diff;
+
+ // Perform subtraction.
+ l_diff = l_var1 - l_var2;
+
+ if (l_var1 < 0) { // Check for underflow.
+ if ((l_var2 > 0) && (l_diff > 0)) {
+ l_diff = (int32_t)0x80000000;
+ }
+ } else { // Check for overflow.
+ if ((l_var2 < 0) && (l_diff < 0)) {
+ l_diff = (int32_t)0x7FFFFFFF;
+ }
+ }
+
+ return l_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) {
+ int16_t bits;
+
+ if (0xFFFF0000 & n) {
+ bits = 16;
+ } else {
+ bits = 0;
+ }
+ if (0x0000FF00 & (n >> bits)) bits += 8;
+ if (0x000000F0 & (n >> bits)) bits += 4;
+ if (0x0000000C & (n >> bits)) bits += 2;
+ if (0x00000002 & (n >> bits)) bits += 1;
+ if (0x00000001 & (n >> bits)) bits += 1;
+
+ return bits;
+}
+
+static __inline int16_t WebRtcSpl_NormW32(int32_t a) {
+ int16_t zeros;
+
+ if (a == 0) {
+ return 0;
+ }
+ else if (a < 0) {
+ a = ~a;
+ }
+
+ if (!(0xFFFF8000 & a)) {
+ zeros = 16;
+ } else {
+ zeros = 0;
+ }
+ if (!(0xFF800000 & (a << zeros))) zeros += 8;
+ if (!(0xF8000000 & (a << zeros))) zeros += 4;
+ if (!(0xE0000000 & (a << zeros))) zeros += 2;
+ if (!(0xC0000000 & (a << zeros))) zeros += 1;
+
+ return zeros;
+}
+
+static __inline int16_t WebRtcSpl_NormU32(uint32_t a) {
+ int16_t zeros;
+
+ if (a == 0) return 0;
+
+ if (!(0xFFFF0000 & a)) {
+ zeros = 16;
+ } else {
+ zeros = 0;
+ }
+ if (!(0xFF000000 & (a << zeros))) zeros += 8;
+ if (!(0xF0000000 & (a << zeros))) zeros += 4;
+ if (!(0xC0000000 & (a << zeros))) zeros += 2;
+ if (!(0x80000000 & (a << zeros))) zeros += 1;
+
+ return zeros;
+}
+
+static __inline int16_t WebRtcSpl_NormW16(int16_t a) {
+ int16_t zeros;
+
+ if (a == 0) {
+ return 0;
+ }
+ else if (a < 0) {
+ a = ~a;
+ }
+
+ if (!(0xFF80 & a)) {
+ zeros = 8;
+ } else {
+ zeros = 0;
+ }
+ if (!(0xF800 & (a << zeros))) zeros += 4;
+ if (!(0xE000 & (a << zeros))) zeros += 2;
+ if (!(0xC000 & (a << zeros))) zeros += 1;
+
+ return zeros;
+}
+
+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 // WEBRTC_SPL_SPL_INL_H_
diff --git a/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h b/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
new file mode 100644
index 0000000000..2718801159
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
@@ -0,0 +1,136 @@
+/*
+ * 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 WEBRTC_SPL_SPL_INL_ARMV7_H_
+#define WEBRTC_SPL_SPL_INL_ARMV7_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 // WEBRTC_SPL_SPL_INL_ARMV7_H_
diff --git a/webrtc/common_audio/signal_processing/include/spl_inl_mips.h b/webrtc/common_audio/signal_processing/include/spl_inl_mips.h
new file mode 100644
index 0000000000..cd04bddcfa
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/include/spl_inl_mips.h
@@ -0,0 +1,225 @@
+/*
+ * 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 WEBRTC_SPL_SPL_INL_MIPS_H_
+#define WEBRTC_SPL_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 // WEBRTC_SPL_SPL_INL_MIPS_H_
diff --git a/webrtc/common_audio/signal_processing/levinson_durbin.c b/webrtc/common_audio/signal_processing/levinson_durbin.c
new file mode 100644
index 0000000000..d46e551367
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/levinson_durbin.c
@@ -0,0 +1,246 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+#define SPL_LEVINSON_MAXORDER 20
+
+int16_t 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 = WEBRTC_SPL_LSHIFT_W32(R[i], norm);
+ // 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] << 16)) >> 1);
+ }
+
+ // K = A[1] = -R[1] / R[0]
+
+ temp2W32 = WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[1],16)
+ + WEBRTC_SPL_LSHIFT_W32((int32_t)R_low[1],1); // 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 << 16)) >> 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] << 16)) >> 1);
+
+ // Alpha = R[0] * (1-K^2)
+
+ temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) << 1; // = 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] << 1) +
+ (((R_hi[j] * A_low[i - j] >> 15) +
+ (R_low[j] * A_hi[i - j] >> 15)) << 1);
+ }
+
+ temp1W32 = WEBRTC_SPL_LSHIFT_W32(temp1W32, 4);
+ temp1W32 += (WEBRTC_SPL_LSHIFT_W32((int32_t)R_hi[i], 16)
+ + 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 = WEBRTC_SPL_LSHIFT_W32(temp3W32, 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 << 16)) >> 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 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[j],16)
+ + 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)) << 1;
+
+ // 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] << 16)) >> 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] << 16)) >> 1);
+
+ // Alpha = Alpha * (1-K^2)
+
+ temp1W32 = ((K_hi * K_low >> 14) + K_hi * K_hi) << 1; // 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 = WEBRTC_SPL_LSHIFT_W32((int32_t)A_hi[i], 16)
+ + WEBRTC_SPL_LSHIFT_W32((int32_t)A_low[i], 1);
+ // Round and store upper word
+ A[i] = (int16_t)(((temp1W32 << 1) + 32768) >> 16);
+ }
+ return 1; // Stable filters
+}
diff --git a/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c b/webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
new file mode 100644
index 0000000000..edcebd4e63
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/min_max_operations.c b/webrtc/common_audio/signal_processing/min_max_operations.c
new file mode 100644
index 0000000000..4a962f86a0
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/min_max_operations.c
@@ -0,0 +1,224 @@
+/*
+ * 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 <assert.h>
+#include <stdlib.h>
+
+#include "webrtc/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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(length > 0);
+
+ for (i = 0; i < length; i++) {
+ absolute = abs((int)vector[i]);
+
+ if (absolute > maximum) {
+ maximum = absolute;
+ index = i;
+ }
+ }
+
+ return index;
+}
+
+// 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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(length > 0);
+
+ for (i = 0; i < length; i++) {
+ if (vector[i] < minimum) {
+ minimum = vector[i];
+ index = i;
+ }
+ }
+
+ return index;
+}
diff --git a/webrtc/common_audio/signal_processing/min_max_operations_mips.c b/webrtc/common_audio/signal_processing/min_max_operations_mips.c
new file mode 100644
index 0000000000..28de45b3a5
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/min_max_operations_mips.c
@@ -0,0 +1,376 @@
+/*
+ * 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 <assert.h>
+
+#include "webrtc/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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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/webrtc/common_audio/signal_processing/min_max_operations_neon.c b/webrtc/common_audio/signal_processing/min_max_operations_neon.c
new file mode 100644
index 0000000000..6fbbf94ee0
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/min_max_operations_neon.c
@@ -0,0 +1,283 @@
+/*
+ * 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 <assert.h>
+#include <stdlib.h>
+
+#include "webrtc/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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+
+ assert(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;
+}
+
diff --git a/webrtc/common_audio/signal_processing/randomization_functions.c b/webrtc/common_audio/signal_processing/randomization_functions.c
new file mode 100644
index 0000000000..73f24093c2
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/real_fft.c b/webrtc/common_audio/signal_processing/real_fft.c
new file mode 100644
index 0000000000..92daae4d38
--- /dev/null
+++ b/webrtc/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 "webrtc/common_audio/signal_processing/include/real_fft.h"
+
+#include <stdlib.h>
+
+#include "webrtc/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/webrtc/common_audio/signal_processing/real_fft_unittest.cc b/webrtc/common_audio/signal_processing/real_fft_unittest.cc
new file mode 100644
index 0000000000..9bd35cd68b
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/real_fft_unittest.cc
@@ -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 "webrtc/common_audio/signal_processing/include/real_fft.h"
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/test/testsupport/gtest_disable.h"
+#include "webrtc/typedefs.h"
+
+#include "testing/gtest/include/gtest/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
+};
+
+class RealFFTTest : public ::testing::Test {
+ protected:
+ RealFFTTest() {
+ WebRtcSpl_Init();
+ }
+};
+
+TEST_F(RealFFTTest, CreateFailsOnBadInput) {
+ RealFFT* fft = WebRtcSpl_CreateRealFFT(11);
+ EXPECT_TRUE(fft == NULL);
+ fft = WebRtcSpl_CreateRealFFT(-1);
+ EXPECT_TRUE(fft == NULL);
+}
+
+TEST_F(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 != NULL);
+ 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/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c b/webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
new file mode 100644
index 0000000000..06a29b6632
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/resample.c b/webrtc/common_audio/signal_processing/resample.c
new file mode 100644
index 0000000000..45fe52aa98
--- /dev/null
+++ b/webrtc/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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/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/webrtc/common_audio/signal_processing/resample_48khz.c b/webrtc/common_audio/signal_processing/resample_48khz.c
new file mode 100644
index 0000000000..2220cc3331
--- /dev/null
+++ b/webrtc/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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/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/webrtc/common_audio/signal_processing/resample_by_2.c b/webrtc/common_audio/signal_processing/resample_by_2.c
new file mode 100644
index 0000000000..dcba82e35f
--- /dev/null
+++ b/webrtc/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 "webrtc/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++) << 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);
+ }
+
+ 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++) << 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/webrtc/common_audio/signal_processing/resample_by_2_internal.c b/webrtc/common_audio/signal_processing/resample_by_2_internal.c
new file mode 100644
index 0000000000..085069c835
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/resample_by_2_internal.c
@@ -0,0 +1,679 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/resample_by_2_internal.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 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];
+ // 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 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];
+ // 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 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];
+ // 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/webrtc/common_audio/signal_processing/resample_by_2_internal.h b/webrtc/common_audio/signal_processing/resample_by_2_internal.h
new file mode 100644
index 0000000000..5c9533eefa
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/resample_by_2_internal.h
@@ -0,0 +1,47 @@
+/*
+ * 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 WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
+#define WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
+
+#include "webrtc/typedefs.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 // WEBRTC_SPL_RESAMPLE_BY_2_INTERNAL_H_
diff --git a/webrtc/common_audio/signal_processing/resample_by_2_mips.c b/webrtc/common_audio/signal_processing/resample_by_2_mips.c
new file mode 100644
index 0000000000..ec5fc8b3b6
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/resample_by_2_mips.c
@@ -0,0 +1,290 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+// 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)
+
+// 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/webrtc/common_audio/signal_processing/resample_fractional.c b/webrtc/common_audio/signal_processing/resample_fractional.c
new file mode 100644
index 0000000000..6409fbac47
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/signal_processing_unittest.cc b/webrtc/common_audio/signal_processing/signal_processing_unittest.cc
new file mode 100644
index 0000000000..108f459c89
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/signal_processing_unittest.cc
@@ -0,0 +1,579 @@
+/*
+ * 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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.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};
+
+class SplTest : public testing::Test {
+ protected:
+ SplTest() {
+ WebRtcSpl_Init();
+ }
+ virtual ~SplTest() {
+ }
+};
+
+TEST_F(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(-2147483645, 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_F(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));
+
+ EXPECT_EQ(109410, WebRtcSpl_AddSatW32(a32, b32));
+ EXPECT_EQ(112832, WebRtcSpl_SubSatW32(a32, b32));
+
+ a32 = 0x80000000;
+ b32 = 0x80000000;
+ // Cast to signed int to avoid compiler complaint on gtest.h.
+ EXPECT_EQ(static_cast<int>(0x80000000), WebRtcSpl_AddSatW32(a32, b32));
+ a32 = 0x7fffffff;
+ b32 = 0x7fffffff;
+ EXPECT_EQ(0x7fffffff, WebRtcSpl_AddSatW32(a32, b32));
+ a32 = 0;
+ b32 = 0x80000000;
+ EXPECT_EQ(0x7fffffff, WebRtcSpl_SubSatW32(a32, b32));
+ a32 = 0x7fffffff;
+ b32 = 0x80000000;
+ EXPECT_EQ(0x7fffffff, WebRtcSpl_SubSatW32(a32, b32));
+ a32 = 0x80000000;
+ b32 = 0x7fffffff;
+ EXPECT_EQ(static_cast<int>(0x80000000), WebRtcSpl_SubSatW32(a32, b32));
+}
+
+TEST_F(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_F(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_F(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));
+
+ // 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));
+
+ // 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));
+}
+
+TEST_F(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_F(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_F(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_F(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_F(SplTest, DotProductWithScaleTest) {
+ EXPECT_EQ(605362796, WebRtcSpl_DotProductWithScale(vector16,
+ vector16, kVector16Size, 2));
+}
+
+TEST_F(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_F(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_F(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_F(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_F(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/webrtc/common_audio/signal_processing/spl_init.c b/webrtc/common_audio/signal_processing/spl_init.c
new file mode 100644
index 0000000000..fdab038399
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/spl_init.c
@@ -0,0 +1,140 @@
+/*
+ * 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.
+ */
+
+/* The global function contained in this file initializes SPL function
+ * pointers, currently only for ARM platforms.
+ *
+ * Some code came from common/rtcd.c in the WebM project.
+ */
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/system_wrappers/include/cpu_features_wrapper.h"
+
+/* Declare function pointers. */
+MaxAbsValueW16 WebRtcSpl_MaxAbsValueW16;
+MaxAbsValueW32 WebRtcSpl_MaxAbsValueW32;
+MaxValueW16 WebRtcSpl_MaxValueW16;
+MaxValueW32 WebRtcSpl_MaxValueW32;
+MinValueW16 WebRtcSpl_MinValueW16;
+MinValueW32 WebRtcSpl_MinValueW32;
+CrossCorrelation WebRtcSpl_CrossCorrelation;
+DownsampleFast WebRtcSpl_DownsampleFast;
+ScaleAndAddVectorsWithRound WebRtcSpl_ScaleAndAddVectorsWithRound;
+
+#if (defined(WEBRTC_DETECT_NEON) || !defined(WEBRTC_HAS_NEON)) && \
+ !defined(MIPS32_LE)
+/* Initialize function pointers to the generic C version. */
+static void InitPointersToC() {
+ WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16C;
+ WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
+ WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16C;
+ WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32C;
+ WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16C;
+ WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32C;
+ WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationC;
+ WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastC;
+ WebRtcSpl_ScaleAndAddVectorsWithRound =
+ WebRtcSpl_ScaleAndAddVectorsWithRoundC;
+}
+#endif
+
+#if defined(WEBRTC_DETECT_NEON) || defined(WEBRTC_HAS_NEON)
+/* Initialize function pointers to the Neon version. */
+static void InitPointersToNeon() {
+ WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16Neon;
+ WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32Neon;
+ WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16Neon;
+ WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32Neon;
+ WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16Neon;
+ WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32Neon;
+ WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelationNeon;
+ WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFastNeon;
+ WebRtcSpl_ScaleAndAddVectorsWithRound =
+ WebRtcSpl_ScaleAndAddVectorsWithRoundC;
+}
+#endif
+
+#if defined(MIPS32_LE)
+/* Initialize function pointers to the MIPS version. */
+static void InitPointersToMIPS() {
+ WebRtcSpl_MaxAbsValueW16 = WebRtcSpl_MaxAbsValueW16_mips;
+ WebRtcSpl_MaxValueW16 = WebRtcSpl_MaxValueW16_mips;
+ WebRtcSpl_MaxValueW32 = WebRtcSpl_MaxValueW32_mips;
+ WebRtcSpl_MinValueW16 = WebRtcSpl_MinValueW16_mips;
+ WebRtcSpl_MinValueW32 = WebRtcSpl_MinValueW32_mips;
+ WebRtcSpl_CrossCorrelation = WebRtcSpl_CrossCorrelation_mips;
+ WebRtcSpl_DownsampleFast = WebRtcSpl_DownsampleFast_mips;
+#if defined(MIPS_DSP_R1_LE)
+ WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32_mips;
+ WebRtcSpl_ScaleAndAddVectorsWithRound =
+ WebRtcSpl_ScaleAndAddVectorsWithRound_mips;
+#else
+ WebRtcSpl_MaxAbsValueW32 = WebRtcSpl_MaxAbsValueW32C;
+ WebRtcSpl_ScaleAndAddVectorsWithRound =
+ WebRtcSpl_ScaleAndAddVectorsWithRoundC;
+#endif
+}
+#endif
+
+static void InitFunctionPointers(void) {
+#if defined(WEBRTC_DETECT_NEON)
+ if ((WebRtc_GetCPUFeaturesARM() & kCPUFeatureNEON) != 0) {
+ InitPointersToNeon();
+ } else {
+ InitPointersToC();
+ }
+#elif defined(WEBRTC_HAS_NEON)
+ InitPointersToNeon();
+#elif defined(MIPS32_LE)
+ InitPointersToMIPS();
+#else
+ InitPointersToC();
+#endif /* WEBRTC_DETECT_NEON */
+}
+
+#if defined(WEBRTC_POSIX)
+#include <pthread.h>
+
+static void once(void (*func)(void)) {
+ static pthread_once_t lock = PTHREAD_ONCE_INIT;
+ pthread_once(&lock, func);
+}
+
+#elif defined(_WIN32)
+#include <windows.h>
+
+static void once(void (*func)(void)) {
+ /* Didn't use InitializeCriticalSection() since there's no race-free context
+ * in which to execute it.
+ *
+ * TODO(kma): Change to different implementation (e.g.
+ * InterlockedCompareExchangePointer) to avoid issues similar to
+ * http://code.google.com/p/webm/issues/detail?id=467.
+ */
+ static CRITICAL_SECTION lock = {(void *)((size_t)-1), -1, 0, 0, 0, 0};
+ static int done = 0;
+
+ EnterCriticalSection(&lock);
+ if (!done) {
+ func();
+ done = 1;
+ }
+ LeaveCriticalSection(&lock);
+}
+
+/* There's no fallback version as an #else block here to ensure thread safety.
+ * In case of neither pthread for WEBRTC_POSIX nor _WIN32 is present, build
+ * system should pick it up.
+ */
+#endif /* WEBRTC_POSIX */
+
+void WebRtcSpl_Init() {
+ once(InitFunctionPointers);
+}
diff --git a/webrtc/common_audio/signal_processing/spl_sqrt.c b/webrtc/common_audio/signal_processing/spl_sqrt.c
new file mode 100644
index 0000000000..24db4f822c
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/spl_sqrt.c
@@ -0,0 +1,184 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+#include <assert.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;
+
+ if (A == 0)
+ return (int32_t)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);
+ assert(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/webrtc/common_audio/signal_processing/spl_sqrt_floor.c b/webrtc/common_audio/signal_processing/spl_sqrt_floor.c
new file mode 100644
index 0000000000..370307a08f
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/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 "webrtc/common_audio/signal_processing/include/signal_processing_library.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/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S b/webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S
new file mode 100644
index 0000000000..72cd2d9a0a
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/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 "webrtc/system_wrappers/include/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/webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c b/webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c
new file mode 100644
index 0000000000..8716459b1d
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/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 "webrtc/common_audio/signal_processing/include/signal_processing_library.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/webrtc/common_audio/signal_processing/splitting_filter.c b/webrtc/common_audio/signal_processing/splitting_filter.c
new file mode 100644
index 0000000000..36fcf355ec
--- /dev/null
+++ b/webrtc/common_audio/signal_processing/splitting_filter.c
@@ -0,0 +1,208 @@
+/*
+ * 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 "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+
+#include <assert.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|
+//
+
+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;
+ assert(in_data_length % 2 == 0);
+ assert(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] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k], 10);
+ half_in1[i] = WEBRTC_SPL_LSHIFT_W32((int32_t)in_data[k + 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;
+ assert(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] = WEBRTC_SPL_LSHIFT_W32(tmp, 10);
+ tmp = (int32_t)low_band[i] - (int32_t)high_band[i];
+ half_in2[i] = WEBRTC_SPL_LSHIFT_W32(tmp, 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/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c b/webrtc/common_audio/signal_processing/sqrt_of_one_minus_x_squared.c
new file mode 100644
index 0000000000..ff78b5228f
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/signal_processing/vector_scaling_operations.c b/webrtc/common_audio/signal_processing/vector_scaling_operations.c
new file mode 100644
index 0000000000..fdefd06760
--- /dev/null
+++ b/webrtc/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 "webrtc/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++) << (-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/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c b/webrtc/common_audio/signal_processing/vector_scaling_operations_mips.c
new file mode 100644
index 0000000000..dd73eeaebb
--- /dev/null
+++ b/webrtc/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 "webrtc/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/webrtc/common_audio/sparse_fir_filter.cc b/webrtc/common_audio/sparse_fir_filter.cc
new file mode 100644
index 0000000000..5862b7cc6b
--- /dev/null
+++ b/webrtc/common_audio/sparse_fir_filter.cc
@@ -0,0 +1,60 @@
+/*
+ * 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 "webrtc/common_audio/sparse_fir_filter.h"
+
+#include "webrtc/base/checks.h"
+
+namespace webrtc {
+
+SparseFIRFilter::SparseFIRFilter(const float* nonzero_coeffs,
+ size_t num_nonzero_coeffs,
+ size_t sparsity,
+ size_t offset)
+ : sparsity_(sparsity),
+ offset_(offset),
+ nonzero_coeffs_(nonzero_coeffs, nonzero_coeffs + num_nonzero_coeffs),
+ state_(sparsity_ * (num_nonzero_coeffs - 1) + offset_, 0.f) {
+ RTC_CHECK_GE(num_nonzero_coeffs, 1u);
+ RTC_CHECK_GE(sparsity, 1u);
+}
+
+void SparseFIRFilter::Filter(const float* in, size_t length, float* out) {
+ // Convolves the input signal |in| with the filter kernel |nonzero_coeffs_|
+ // taking into account the previous state.
+ for (size_t i = 0; i < length; ++i) {
+ out[i] = 0.f;
+ size_t j;
+ for (j = 0; i >= j * sparsity_ + offset_ &&
+ j < nonzero_coeffs_.size(); ++j) {
+ out[i] += in[i - j * sparsity_ - offset_] * nonzero_coeffs_[j];
+ }
+ for (; j < nonzero_coeffs_.size(); ++j) {
+ out[i] += state_[i + (nonzero_coeffs_.size() - j - 1) * sparsity_] *
+ nonzero_coeffs_[j];
+ }
+ }
+
+ // Update current state.
+ if (state_.size() > 0u) {
+ if (length >= state_.size()) {
+ std::memcpy(&state_[0],
+ &in[length - state_.size()],
+ state_.size() * sizeof(*in));
+ } else {
+ std::memmove(&state_[0],
+ &state_[length],
+ (state_.size() - length) * sizeof(state_[0]));
+ std::memcpy(&state_[state_.size() - length], in, length * sizeof(*in));
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/sparse_fir_filter.h b/webrtc/common_audio/sparse_fir_filter.h
new file mode 100644
index 0000000000..2ba5cf4600
--- /dev/null
+++ b/webrtc/common_audio/sparse_fir_filter.h
@@ -0,0 +1,52 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_SPARSE_FIR_FILTER_H_
+#define WEBRTC_COMMON_AUDIO_SPARSE_FIR_FILTER_H_
+
+#include <cstring>
+#include <vector>
+
+#include "webrtc/base/constructormagic.h"
+
+namespace webrtc {
+
+// A Finite Impulse Response filter implementation which takes advantage of a
+// sparse structure with uniformly distributed non-zero coefficients.
+class SparseFIRFilter final {
+ public:
+ // |num_nonzero_coeffs| is the number of non-zero coefficients,
+ // |nonzero_coeffs|. They are assumed to be uniformly distributed every
+ // |sparsity| samples and with an initial |offset|. The rest of the filter
+ // coefficients will be assumed zeros. For example, with sparsity = 3, and
+ // offset = 1 the filter coefficients will be:
+ // B = [0 coeffs[0] 0 0 coeffs[1] 0 0 coeffs[2] ... ]
+ // All initial state values will be zeros.
+ SparseFIRFilter(const float* nonzero_coeffs,
+ size_t num_nonzero_coeffs,
+ size_t sparsity,
+ size_t offset);
+
+ // Filters the |in| data supplied.
+ // |out| must be previously allocated and it must be at least of |length|.
+ void Filter(const float* in, size_t length, float* out);
+
+ private:
+ const size_t sparsity_;
+ const size_t offset_;
+ const std::vector<float> nonzero_coeffs_;
+ std::vector<float> state_;
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(SparseFIRFilter);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_SPARSE_FIR_FILTER_H_
diff --git a/webrtc/common_audio/sparse_fir_filter_unittest.cc b/webrtc/common_audio/sparse_fir_filter_unittest.cc
new file mode 100644
index 0000000000..82a53a5287
--- /dev/null
+++ b/webrtc/common_audio/sparse_fir_filter_unittest.cc
@@ -0,0 +1,231 @@
+/*
+ * 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 "webrtc/common_audio/sparse_fir_filter.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/base/arraysize.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/fir_filter.h"
+
+namespace webrtc {
+namespace {
+
+static const float kCoeffs[] = {0.2f, 0.3f, 0.5f, 0.7f, 0.11f};
+static const float kInput[] =
+ {1.f, 2.f, 3.f, 4.f, 5.f, 6.f, 7.f, 8.f, 9.f, 10.f};
+
+template <size_t N>
+void VerifyOutput(const float (&expected_output)[N], const float (&output)[N]) {
+ EXPECT_EQ(0, memcmp(expected_output, output, sizeof(output)));
+}
+
+} // namespace
+
+TEST(SparseFIRFilterTest, FilterAsIdentity) {
+ const float kCoeff = 1.f;
+ const size_t kNumCoeff = 1;
+ const size_t kSparsity = 3;
+ const size_t kOffset = 0;
+ float output[arraysize(kInput)];
+ SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
+ filter.Filter(kInput, arraysize(kInput), output);
+ VerifyOutput(kInput, output);
+}
+
+TEST(SparseFIRFilterTest, SameOutputForScalarCoefficientAndDifferentSparsity) {
+ const float kCoeff = 2.f;
+ const size_t kNumCoeff = 1;
+ const size_t kLowSparsity = 1;
+ const size_t kHighSparsity = 7;
+ const size_t kOffset = 0;
+ float low_sparsity_output[arraysize(kInput)];
+ float high_sparsity_output[arraysize(kInput)];
+ SparseFIRFilter low_sparsity_filter(&kCoeff,
+ kNumCoeff,
+ kLowSparsity,
+ kOffset);
+ SparseFIRFilter high_sparsity_filter(&kCoeff,
+ kNumCoeff,
+ kHighSparsity,
+ kOffset);
+ low_sparsity_filter.Filter(kInput, arraysize(kInput), low_sparsity_output);
+ high_sparsity_filter.Filter(kInput, arraysize(kInput), high_sparsity_output);
+ VerifyOutput(low_sparsity_output, high_sparsity_output);
+}
+
+TEST(SparseFIRFilterTest, FilterUsedAsScalarMultiplication) {
+ const float kCoeff = 5.f;
+ const size_t kNumCoeff = 1;
+ const size_t kSparsity = 5;
+ const size_t kOffset = 0;
+ float output[arraysize(kInput)];
+ SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
+ filter.Filter(kInput, arraysize(kInput), 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[arraysize(kInput) - 1]);
+}
+
+TEST(SparseFIRFilterTest, FilterUsedAsInputShifting) {
+ const float kCoeff = 1.f;
+ const size_t kNumCoeff = 1;
+ const size_t kSparsity = 1;
+ const size_t kOffset = 4;
+ float output[arraysize(kInput)];
+ SparseFIRFilter filter(&kCoeff, kNumCoeff, kSparsity, kOffset);
+ filter.Filter(kInput, arraysize(kInput), 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[arraysize(kInput) - 1]);
+}
+
+TEST(SparseFIRFilterTest, FilterUsedAsArbitraryWeighting) {
+ const size_t kSparsity = 2;
+ const size_t kOffset = 1;
+ float output[arraysize(kInput)];
+ SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
+ filter.Filter(kInput, arraysize(kInput), output);
+ EXPECT_FLOAT_EQ(0.f, output[0]);
+ EXPECT_FLOAT_EQ(0.9f, output[3]);
+ EXPECT_FLOAT_EQ(1.4f, output[4]);
+ EXPECT_FLOAT_EQ(2.4f, output[5]);
+ EXPECT_FLOAT_EQ(8.61f, output[arraysize(kInput) - 1]);
+}
+
+TEST(SparseFIRFilterTest, FilterInLengthLesserOrEqualToCoefficientsLength) {
+ const size_t kSparsity = 1;
+ const size_t kOffset = 0;
+ float output[arraysize(kInput)];
+ SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
+ filter.Filter(kInput, 2, output);
+ EXPECT_FLOAT_EQ(0.2f, output[0]);
+ EXPECT_FLOAT_EQ(0.7f, output[1]);
+}
+
+TEST(SparseFIRFilterTest, MultipleFilterCalls) {
+ const size_t kSparsity = 1;
+ const size_t kOffset = 0;
+ float output[arraysize(kInput)];
+ SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
+ 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(SparseFIRFilterTest, VerifySampleBasedVsBlockBasedFiltering) {
+ const size_t kSparsity = 3;
+ const size_t kOffset = 1;
+ float output_block_based[arraysize(kInput)];
+ SparseFIRFilter filter_block(kCoeffs,
+ arraysize(kCoeffs),
+ kSparsity,
+ kOffset);
+ filter_block.Filter(kInput, arraysize(kInput), output_block_based);
+ float output_sample_based[arraysize(kInput)];
+ SparseFIRFilter filter_sample(kCoeffs,
+ arraysize(kCoeffs),
+ kSparsity,
+ kOffset);
+ for (size_t i = 0; i < arraysize(kInput); ++i)
+ filter_sample.Filter(&kInput[i], 1, &output_sample_based[i]);
+ VerifyOutput(output_block_based, output_sample_based);
+}
+
+TEST(SparseFIRFilterTest, SimpleHighPassFilter) {
+ const size_t kSparsity = 2;
+ const size_t kOffset = 2;
+ const float kHPCoeffs[] = {1.f, -1.f};
+ const float kConstantInput[] =
+ {1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f};
+ float output[arraysize(kConstantInput)];
+ SparseFIRFilter filter(kHPCoeffs, arraysize(kHPCoeffs), kSparsity, kOffset);
+ filter.Filter(kConstantInput, arraysize(kConstantInput), output);
+ EXPECT_FLOAT_EQ(0.f, output[0]);
+ EXPECT_FLOAT_EQ(0.f, output[1]);
+ EXPECT_FLOAT_EQ(1.f, output[2]);
+ EXPECT_FLOAT_EQ(1.f, output[3]);
+ for (size_t i = kSparsity + kOffset; i < arraysize(kConstantInput); ++i)
+ EXPECT_FLOAT_EQ(0.f, output[i]);
+}
+
+TEST(SparseFIRFilterTest, SimpleLowPassFilter) {
+ const size_t kSparsity = 2;
+ const size_t kOffset = 2;
+ const float kLPCoeffs[] = {1.f, 1.f};
+ const float kHighFrequencyInput[] =
+ {1.f, 1.f, -1.f, -1.f, 1.f, 1.f, -1.f, -1.f, 1.f, 1.f};
+ float output[arraysize(kHighFrequencyInput)];
+ SparseFIRFilter filter(kLPCoeffs, arraysize(kLPCoeffs), kSparsity, kOffset);
+ filter.Filter(kHighFrequencyInput, arraysize(kHighFrequencyInput), output);
+ EXPECT_FLOAT_EQ(0.f, output[0]);
+ EXPECT_FLOAT_EQ(0.f, output[1]);
+ EXPECT_FLOAT_EQ(1.f, output[2]);
+ EXPECT_FLOAT_EQ(1.f, output[3]);
+ for (size_t i = kSparsity + kOffset; i < arraysize(kHighFrequencyInput); ++i)
+ EXPECT_FLOAT_EQ(0.f, output[i]);
+}
+
+TEST(SparseFIRFilterTest, SameOutputWhenSwappedCoefficientsAndInput) {
+ const size_t kSparsity = 1;
+ const size_t kOffset = 0;
+ float output[arraysize(kCoeffs)];
+ float output_swapped[arraysize(kCoeffs)];
+ SparseFIRFilter filter(kCoeffs, arraysize(kCoeffs), kSparsity, kOffset);
+ // Use arraysize(kCoeffs) for in_length to get same-length outputs.
+ filter.Filter(kInput, arraysize(kCoeffs), output);
+ SparseFIRFilter filter_swapped(kInput,
+ arraysize(kCoeffs),
+ kSparsity,
+ kOffset);
+ filter_swapped.Filter(kCoeffs, arraysize(kCoeffs), output_swapped);
+ VerifyOutput(output, output_swapped);
+}
+
+TEST(SparseFIRFilterTest, SameOutputAsFIRFilterWhenSparsityOneAndOffsetZero) {
+ const size_t kSparsity = 1;
+ const size_t kOffset = 0;
+ float output[arraysize(kInput)];
+ float sparse_output[arraysize(kInput)];
+ rtc::scoped_ptr<FIRFilter> filter(FIRFilter::Create(kCoeffs,
+ arraysize(kCoeffs),
+ arraysize(kInput)));
+ SparseFIRFilter sparse_filter(kCoeffs,
+ arraysize(kCoeffs),
+ kSparsity,
+ kOffset);
+ filter->Filter(kInput, arraysize(kInput), output);
+ sparse_filter.Filter(kInput, arraysize(kInput), sparse_output);
+ for (size_t i = 0; i < arraysize(kInput); ++i) {
+ EXPECT_FLOAT_EQ(output[i], sparse_output[i]);
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/vad/Android.mk b/webrtc/common_audio/vad/Android.mk
new file mode 100644
index 0000000000..cd67055d41
--- /dev/null
+++ b/webrtc/common_audio/vad/Android.mk
@@ -0,0 +1,48 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+include $(LOCAL_PATH)/../../../android-webrtc.mk
+
+LOCAL_ARM_MODE := arm
+LOCAL_MODULE_CLASS := STATIC_LIBRARIES
+LOCAL_MODULE := libwebrtc_vad
+LOCAL_MODULE_TAGS := optional
+LOCAL_SRC_FILES := \
+ webrtc_vad.c \
+ vad_core.c \
+ vad_filterbank.c \
+ vad_gmm.c \
+ vad_sp.c
+
+# Flags passed to both C and C++ files.
+LOCAL_CFLAGS := \
+ $(MY_WEBRTC_COMMON_DEFS)
+
+LOCAL_CFLAGS_arm := $(MY_WEBRTC_COMMON_DEFS_arm)
+LOCAL_CFLAGS_x86 := $(MY_WEBRTC_COMMON_DEFS_x86)
+LOCAL_CFLAGS_mips := $(MY_WEBRTC_COMMON_DEFS_mips)
+LOCAL_CFLAGS_arm64 := $(MY_WEBRTC_COMMON_DEFS_arm64)
+LOCAL_CFLAGS_x86_64 := $(MY_WEBRTC_COMMON_DEFS_x86_64)
+LOCAL_CFLAGS_mips64 := $(MY_WEBRTC_COMMON_DEFS_mips64)
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/../../.. \
+ $(LOCAL_PATH)/../signal_processing/include
+
+ifdef WEBRTC_STL
+LOCAL_NDK_STL_VARIANT := $(WEBRTC_STL)
+LOCAL_SDK_VERSION := 14
+LOCAL_MODULE := $(LOCAL_MODULE)_$(WEBRTC_STL)
+endif
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/webrtc/common_audio/vad/include/vad.h b/webrtc/common_audio/vad/include/vad.h
new file mode 100644
index 0000000000..087970f58e
--- /dev/null
+++ b/webrtc/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 WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/scoped_ptr.h"
+#include "webrtc/common_audio/vad/include/webrtc_vad.h"
+#include "webrtc/typedefs.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.
+rtc::scoped_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness);
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_VAD_H_
diff --git a/webrtc/common_audio/vad/include/webrtc_vad.h b/webrtc/common_audio/vad/include/webrtc_vad.h
new file mode 100644
index 0000000000..91308eef12
--- /dev/null
+++ b/webrtc/common_audio/vad/include/webrtc_vad.h
@@ -0,0 +1,86 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
+#define WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_
+
+#include <stddef.h>
+
+#include "webrtc/typedefs.h"
+
+typedef struct WebRtcVadInst VadInst;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Creates an instance to the VAD structure.
+VadInst* WebRtcVad_Create();
+
+// 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 // WEBRTC_COMMON_AUDIO_VAD_INCLUDE_WEBRTC_VAD_H_ // NOLINT
diff --git a/webrtc/common_audio/vad/mock/mock_vad.h b/webrtc/common_audio/vad/mock/mock_vad.h
new file mode 100644
index 0000000000..bc763bb9d9
--- /dev/null
+++ b/webrtc/common_audio/vad/mock/mock_vad.h
@@ -0,0 +1,34 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
+#define WEBRTC_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
+
+#include "webrtc/common_audio/vad/include/vad.h"
+
+#include "testing/gmock/include/gmock/gmock.h"
+
+namespace webrtc {
+
+class MockVad : public Vad {
+ public:
+ virtual ~MockVad() { Die(); }
+ MOCK_METHOD0(Die, void());
+
+ MOCK_METHOD3(VoiceActivity,
+ enum Activity(const int16_t* audio,
+ size_t num_samples,
+ int sample_rate_hz));
+ MOCK_METHOD0(Reset, void());
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_VAD_MOCK_MOCK_VAD_H_
diff --git a/webrtc/common_audio/vad/vad.cc b/webrtc/common_audio/vad/vad.cc
new file mode 100644
index 0000000000..95a162fb92
--- /dev/null
+++ b/webrtc/common_audio/vad/vad.cc
@@ -0,0 +1,63 @@
+/*
+ * 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 "webrtc/common_audio/vad/include/vad.h"
+
+#include "webrtc/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(false) << "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
+
+rtc::scoped_ptr<Vad> CreateVad(Vad::Aggressiveness aggressiveness) {
+ return rtc::scoped_ptr<Vad>(new VadImpl(aggressiveness));
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/vad/vad_core.c b/webrtc/common_audio/vad/vad_core.c
new file mode 100644
index 0000000000..51797eed54
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_core.c
@@ -0,0 +1,676 @@
+/*
+ * 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 "webrtc/common_audio/vad/vad_core.h"
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/common_audio/vad/vad_filterbank.h"
+#include "webrtc/common_audio/vad/vad_gmm.h"
+#include "webrtc/common_audio/vad/vad_sp.h"
+#include "webrtc/typedefs.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;
+}
+
+// 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 << 2) > 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 = 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/webrtc/common_audio/vad/vad_core.h b/webrtc/common_audio/vad/vad_core.h
new file mode 100644
index 0000000000..b38c515ea1
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_core.h
@@ -0,0 +1,115 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
+#define WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/typedefs.h"
+
+enum { kNumChannels = 6 }; // Number of frequency bands (named channels).
+enum { kNumGaussians = 2 }; // Number of Gaussians per channel in the GMM.
+enum { kTableSize = kNumChannels * kNumGaussians };
+enum { 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 // WEBRTC_COMMON_AUDIO_VAD_VAD_CORE_H_
diff --git a/webrtc/common_audio/vad/vad_core_unittest.cc b/webrtc/common_audio/vad/vad_core_unittest.cc
new file mode 100644
index 0000000000..ee69484f0a
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_core_unittest.cc
@@ -0,0 +1,105 @@
+/*
+ * 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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/vad/vad_unittest.h"
+#include "webrtc/typedefs.h"
+
+extern "C" {
+#include "webrtc/common_audio/vad/vad_core.h"
+}
+
+namespace {
+
+TEST_F(VadTest, InitCore) {
+ // Test WebRtcVad_InitCore().
+ VadInstT* self = reinterpret_cast<VadInstT*>(malloc(sizeof(VadInstT)));
+
+ // NULL pointer test.
+ EXPECT_EQ(-1, WebRtcVad_InitCore(NULL));
+
+ // 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
diff --git a/webrtc/common_audio/vad/vad_filterbank.c b/webrtc/common_audio/vad/vad_filterbank.c
new file mode 100644
index 0000000000..8b9df93b00
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_filterbank.c
@@ -0,0 +1,331 @@
+/*
+ * 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 "webrtc/common_audio/vad/vad_filterbank.h"
+
+#include <assert.h>
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/typedefs.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) << 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 << 14) - filter_coefficient * tmp16; // Q14
+ state32 <<= 1; // 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;
+
+ assert(data_in != NULL);
+ assert(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.
+
+ assert(data_length <= 240);
+ assert(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/webrtc/common_audio/vad/vad_filterbank.h b/webrtc/common_audio/vad/vad_filterbank.h
new file mode 100644
index 0000000000..42bf3fc331
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_filterbank.h
@@ -0,0 +1,44 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
+#define WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
+
+#include "webrtc/common_audio/vad/vad_core.h"
+#include "webrtc/typedefs.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 // WEBRTC_COMMON_AUDIO_VAD_VAD_FILTERBANK_H_
diff --git a/webrtc/common_audio/vad/vad_filterbank_unittest.cc b/webrtc/common_audio/vad/vad_filterbank_unittest.cc
new file mode 100644
index 0000000000..11b503a196
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_filterbank_unittest.cc
@@ -0,0 +1,92 @@
+/*
+ * 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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/vad/vad_unittest.h"
+#include "webrtc/typedefs.h"
+
+extern "C" {
+#include "webrtc/common_audio/vad/vad_core.h"
+#include "webrtc/common_audio/vad/vad_filterbank.h"
+}
+
+namespace {
+
+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
diff --git a/webrtc/common_audio/vad/vad_gmm.c b/webrtc/common_audio/vad/vad_gmm.c
new file mode 100644
index 0000000000..4a014401d9
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_gmm.c
@@ -0,0 +1,83 @@
+/*
+ * 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 "webrtc/common_audio/vad/vad_gmm.h"
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/typedefs.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/webrtc/common_audio/vad/vad_gmm.h b/webrtc/common_audio/vad/vad_gmm.h
new file mode 100644
index 0000000000..992a156050
--- /dev/null
+++ b/webrtc/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 WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
+#define WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
+
+#include "webrtc/typedefs.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 // WEBRTC_COMMON_AUDIO_VAD_VAD_GMM_H_
diff --git a/webrtc/common_audio/vad/vad_gmm_unittest.cc b/webrtc/common_audio/vad/vad_gmm_unittest.cc
new file mode 100644
index 0000000000..31a8a155c4
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_gmm_unittest.cc
@@ -0,0 +1,43 @@
+/*
+ * 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 "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/vad/vad_unittest.h"
+#include "webrtc/typedefs.h"
+
+extern "C" {
+#include "webrtc/common_audio/vad/vad_gmm.h"
+}
+
+namespace {
+
+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
diff --git a/webrtc/common_audio/vad/vad_sp.c b/webrtc/common_audio/vad/vad_sp.c
new file mode 100644
index 0000000000..a54be17daa
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_sp.c
@@ -0,0 +1,178 @@
+/*
+ * 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 "webrtc/common_audio/vad/vad_sp.h"
+
+#include <assert.h>
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/common_audio/vad/vad_core.h"
+#include "webrtc/typedefs.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];
+
+ assert(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 < 16; 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/webrtc/common_audio/vad/vad_sp.h b/webrtc/common_audio/vad/vad_sp.h
new file mode 100644
index 0000000000..4d2b02a1ef
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_sp.h
@@ -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 includes specific signal processing tools used in vad_core.c.
+
+#ifndef WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
+#define WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
+
+#include "webrtc/common_audio/vad/vad_core.h"
+#include "webrtc/typedefs.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 // WEBRTC_COMMON_AUDIO_VAD_VAD_SP_H_
diff --git a/webrtc/common_audio/vad/vad_sp_unittest.cc b/webrtc/common_audio/vad/vad_sp_unittest.cc
new file mode 100644
index 0000000000..6d5e2a646b
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_sp_unittest.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <stdlib.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/vad/vad_unittest.h"
+#include "webrtc/typedefs.h"
+
+extern "C" {
+#include "webrtc/common_audio/vad/vad_core.h"
+#include "webrtc/common_audio/vad/vad_sp.h"
+}
+
+namespace {
+
+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
diff --git a/webrtc/common_audio/vad/vad_unittest.cc b/webrtc/common_audio/vad/vad_unittest.cc
new file mode 100644
index 0000000000..a0e16b1ce5
--- /dev/null
+++ b/webrtc/common_audio/vad/vad_unittest.cc
@@ -0,0 +1,156 @@
+/*
+ * 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 "webrtc/common_audio/vad/vad_unittest.h"
+
+#include <stdlib.h>
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/base/arraysize.h"
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/common_audio/vad/include/webrtc_vad.h"
+#include "webrtc/typedefs.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 {
+
+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
diff --git a/webrtc/common_audio/vad/vad_unittest.h b/webrtc/common_audio/vad/vad_unittest.h
new file mode 100644
index 0000000000..3efe61b632
--- /dev/null
+++ b/webrtc/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 WEBRTC_COMMON_AUDIO_VAD_VAD_UNITTEST_H
+#define WEBRTC_COMMON_AUDIO_VAD_VAD_UNITTEST_H
+
+#include <stddef.h> // size_t
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+#include "webrtc/typedefs.h"
+
+namespace {
+
+// 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
+
+class VadTest : public ::testing::Test {
+ protected:
+ VadTest();
+ virtual void SetUp();
+ virtual void TearDown();
+
+ // Returns true if the rate and frame length combination is valid.
+ bool ValidRatesAndFrameLengths(int rate, size_t frame_length);
+};
+
+#endif // WEBRTC_COMMON_AUDIO_VAD_VAD_UNITTEST_H
diff --git a/webrtc/common_audio/vad/webrtc_vad.c b/webrtc/common_audio/vad/webrtc_vad.c
new file mode 100644
index 0000000000..80c8f3c88d
--- /dev/null
+++ b/webrtc/common_audio/vad/webrtc_vad.c
@@ -0,0 +1,116 @@
+/*
+ * 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 "webrtc/common_audio/vad/include/webrtc_vad.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
+#include "webrtc/common_audio/vad/vad_core.h"
+#include "webrtc/typedefs.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() {
+ VadInstT* self = (VadInstT*)malloc(sizeof(VadInstT));
+
+ WebRtcSpl_Init();
+ 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/webrtc/common_audio/wav_file.cc b/webrtc/common_audio/wav_file.cc
new file mode 100644
index 0000000000..8dae7d6e98
--- /dev/null
+++ b/webrtc/common_audio/wav_file.cc
@@ -0,0 +1,174 @@
+/*
+ * 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 "webrtc/common_audio/wav_file.h"
+
+#include <algorithm>
+#include <cstdio>
+#include <limits>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/base/safe_conversions.h"
+#include "webrtc/common_audio/include/audio_util.h"
+#include "webrtc/common_audio/wav_header.h"
+
+namespace webrtc {
+
+// We write 16-bit PCM WAV files.
+static const WavFormat kWavFormat = kWavFormatPcm;
+static const int kBytesPerSample = 2;
+
+// Doesn't take ownership of the file handle and won't close it.
+class ReadableWavFile : public ReadableWav {
+ public:
+ explicit ReadableWavFile(FILE* file) : file_(file) {}
+ virtual size_t Read(void* buf, size_t num_bytes) {
+ return fread(buf, 1, num_bytes, file_);
+ }
+
+ private:
+ FILE* file_;
+};
+
+WavReader::WavReader(const std::string& filename)
+ : file_handle_(fopen(filename.c_str(), "rb")) {
+ RTC_CHECK(file_handle_ && "Could not open wav file for reading.");
+
+ ReadableWavFile readable(file_handle_);
+ WavFormat format;
+ int bytes_per_sample;
+ RTC_CHECK(ReadWavHeader(&readable, &num_channels_, &sample_rate_, &format,
+ &bytes_per_sample, &num_samples_));
+ num_samples_remaining_ = num_samples_;
+ RTC_CHECK_EQ(kWavFormat, format);
+ RTC_CHECK_EQ(kBytesPerSample, bytes_per_sample);
+}
+
+WavReader::~WavReader() {
+ Close();
+}
+
+size_t WavReader::ReadSamples(size_t num_samples, int16_t* samples) {
+#ifndef WEBRTC_ARCH_LITTLE_ENDIAN
+#error "Need to convert samples to big-endian when reading from WAV file"
+#endif
+ // There could be metadata after the audio; ensure we don't read it.
+ num_samples = std::min(rtc::checked_cast<uint32_t>(num_samples),
+ num_samples_remaining_);
+ const size_t read =
+ fread(samples, sizeof(*samples), num_samples, file_handle_);
+ // If we didn't read what was requested, ensure we've reached the EOF.
+ RTC_CHECK(read == num_samples || feof(file_handle_));
+ RTC_CHECK_LE(read, num_samples_remaining_);
+ num_samples_remaining_ -= rtc::checked_cast<uint32_t>(read);
+ return read;
+}
+
+size_t WavReader::ReadSamples(size_t num_samples, float* samples) {
+ static const size_t kChunksize = 4096 / sizeof(uint16_t);
+ size_t read = 0;
+ for (size_t i = 0; i < num_samples; i += kChunksize) {
+ int16_t isamples[kChunksize];
+ size_t chunk = std::min(kChunksize, num_samples - i);
+ chunk = ReadSamples(chunk, isamples);
+ for (size_t j = 0; j < chunk; ++j)
+ samples[i + j] = isamples[j];
+ read += chunk;
+ }
+ return read;
+}
+
+void WavReader::Close() {
+ RTC_CHECK_EQ(0, fclose(file_handle_));
+ file_handle_ = NULL;
+}
+
+WavWriter::WavWriter(const std::string& filename, int sample_rate,
+ int num_channels)
+ : sample_rate_(sample_rate),
+ num_channels_(num_channels),
+ num_samples_(0),
+ file_handle_(fopen(filename.c_str(), "wb")) {
+ RTC_CHECK(file_handle_ && "Could not open wav file for writing.");
+ RTC_CHECK(CheckWavParameters(num_channels_, sample_rate_, kWavFormat,
+ kBytesPerSample, num_samples_));
+
+ // 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[kWavHeaderSize] = {0};
+ RTC_CHECK_EQ(1u, fwrite(blank_header, kWavHeaderSize, 1, file_handle_));
+}
+
+WavWriter::~WavWriter() {
+ Close();
+}
+
+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
+ const size_t written =
+ fwrite(samples, sizeof(*samples), num_samples, file_handle_);
+ RTC_CHECK_EQ(num_samples, written);
+ num_samples_ += static_cast<uint32_t>(written);
+ RTC_CHECK(written <= std::numeric_limits<uint32_t>::max() ||
+ num_samples_ >= written); // detect uint32_t overflow
+}
+
+void WavWriter::WriteSamples(const float* samples, size_t num_samples) {
+ static const size_t kChunksize = 4096 / sizeof(uint16_t);
+ for (size_t i = 0; i < num_samples; i += kChunksize) {
+ int16_t isamples[kChunksize];
+ const size_t chunk = std::min(kChunksize, num_samples - i);
+ FloatS16ToS16(samples + i, chunk, isamples);
+ WriteSamples(isamples, chunk);
+ }
+}
+
+void WavWriter::Close() {
+ RTC_CHECK_EQ(0, fseek(file_handle_, 0, SEEK_SET));
+ uint8_t header[kWavHeaderSize];
+ WriteWavHeader(header, num_channels_, sample_rate_, kWavFormat,
+ kBytesPerSample, num_samples_);
+ RTC_CHECK_EQ(1u, fwrite(header, kWavHeaderSize, 1, file_handle_));
+ RTC_CHECK_EQ(0, fclose(file_handle_));
+ file_handle_ = NULL;
+}
+
+} // namespace webrtc
+
+rtc_WavWriter* rtc_WavOpen(const char* filename,
+ int sample_rate,
+ int num_channels) {
+ return reinterpret_cast<rtc_WavWriter*>(
+ new webrtc::WavWriter(filename, sample_rate, num_channels));
+}
+
+void rtc_WavClose(rtc_WavWriter* wf) {
+ delete reinterpret_cast<webrtc::WavWriter*>(wf);
+}
+
+void rtc_WavWriteSamples(rtc_WavWriter* wf,
+ const float* samples,
+ size_t num_samples) {
+ reinterpret_cast<webrtc::WavWriter*>(wf)->WriteSamples(samples, num_samples);
+}
+
+int rtc_WavSampleRate(const rtc_WavWriter* wf) {
+ return reinterpret_cast<const webrtc::WavWriter*>(wf)->sample_rate();
+}
+
+int rtc_WavNumChannels(const rtc_WavWriter* wf) {
+ return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_channels();
+}
+
+uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf) {
+ return reinterpret_cast<const webrtc::WavWriter*>(wf)->num_samples();
+}
diff --git a/webrtc/common_audio/wav_file.h b/webrtc/common_audio/wav_file.h
new file mode 100644
index 0000000000..2eadd3f775
--- /dev/null
+++ b/webrtc/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 WEBRTC_COMMON_AUDIO_WAV_FILE_H_
+#define WEBRTC_COMMON_AUDIO_WAV_FILE_H_
+
+#ifdef __cplusplus
+
+#include <stdint.h>
+#include <cstddef>
+#include <string>
+
+#include "webrtc/base/constructormagic.h"
+
+namespace webrtc {
+
+// Interface to provide access to WAV file parameters.
+class WavFile {
+ public:
+ virtual ~WavFile() {}
+
+ virtual int sample_rate() const = 0;
+ virtual int num_channels() const = 0;
+ virtual uint32_t num_samples() const = 0;
+};
+
+// Simple C++ class for writing 16-bit 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:
+ // Open a new WAV file for writing.
+ WavWriter(const std::string& filename, int sample_rate, int num_channels);
+
+ // Close the WAV file, after writing its header.
+ ~WavWriter();
+
+ // Write additional samples to the file. Each sample is in the range
+ // [-32768,32767], 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_; }
+ int num_channels() const override { return num_channels_; }
+ uint32_t num_samples() const override { return num_samples_; }
+
+ private:
+ void Close();
+ const int sample_rate_;
+ const int num_channels_;
+ uint32_t num_samples_; // Total number of samples written to file.
+ FILE* file_handle_; // Output file, owned by this class
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(WavWriter);
+};
+
+// Follows the conventions of WavWriter.
+class WavReader final : public WavFile {
+ public:
+ // Opens an existing WAV file for reading.
+ explicit WavReader(const std::string& filename);
+
+ // Close the WAV file.
+ ~WavReader();
+
+ // 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_; }
+ int num_channels() const override { return num_channels_; }
+ uint32_t num_samples() const override { return num_samples_; }
+
+ private:
+ void Close();
+ int sample_rate_;
+ int num_channels_;
+ uint32_t num_samples_; // Total number of samples in the file.
+ uint32_t num_samples_remaining_;
+ FILE* file_handle_; // Input file, owned by this class.
+
+ RTC_DISALLOW_COPY_AND_ASSIGN(WavReader);
+};
+
+} // namespace webrtc
+
+extern "C" {
+#endif // __cplusplus
+
+// C wrappers for the WavWriter class.
+typedef struct rtc_WavWriter rtc_WavWriter;
+rtc_WavWriter* rtc_WavOpen(const char* filename,
+ int sample_rate,
+ int num_channels);
+void rtc_WavClose(rtc_WavWriter* wf);
+void rtc_WavWriteSamples(rtc_WavWriter* wf,
+ const float* samples,
+ size_t num_samples);
+int rtc_WavSampleRate(const rtc_WavWriter* wf);
+int rtc_WavNumChannels(const rtc_WavWriter* wf);
+uint32_t rtc_WavNumSamples(const rtc_WavWriter* wf);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBRTC_COMMON_AUDIO_WAV_FILE_H_
diff --git a/webrtc/common_audio/wav_file_unittest.cc b/webrtc/common_audio/wav_file_unittest.cc
new file mode 100644
index 0000000000..78b0a34de9
--- /dev/null
+++ b/webrtc/common_audio/wav_file_unittest.cc
@@ -0,0 +1,177 @@
+/*
+ * 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 <cmath>
+#include <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/wav_header.h"
+#include "webrtc/common_audio/wav_file.h"
+#include "webrtc/test/testsupport/fileutils.h"
+
+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, CPP) {
+ const std::string outfile = test::OutputPath() + "wavtest1.wav";
+ static const uint32_t kNumSamples = 3;
+ {
+ WavWriter w(outfile, 14099, 1);
+ EXPECT_EQ(14099, w.sample_rate());
+ EXPECT_EQ(1, 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[] = {
+ '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],
+ };
+ static const int kContentSize =
+ kWavHeaderSize + kNumSamples * sizeof(int16_t) + sizeof(kMetadata);
+ static_assert(sizeof(kExpectedContents) == kContentSize, "content size");
+ EXPECT_EQ(size_t(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(1, 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 tiny WAV file with the C interface and verify the result.
+TEST(WavWriterTest, C) {
+ const std::string outfile = test::OutputPath() + "wavtest2.wav";
+ rtc_WavWriter* w = rtc_WavOpen(outfile.c_str(), 11904, 2);
+ EXPECT_EQ(11904, rtc_WavSampleRate(w));
+ EXPECT_EQ(2, rtc_WavNumChannels(w));
+ EXPECT_EQ(0u, rtc_WavNumSamples(w));
+ static const uint32_t kNumSamples = 4;
+ rtc_WavWriteSamples(w, &kSamples[0], 2);
+ EXPECT_EQ(2u, rtc_WavNumSamples(w));
+ rtc_WavWriteSamples(w, &kSamples[2], kNumSamples - 2);
+ EXPECT_EQ(kNumSamples, rtc_WavNumSamples(w));
+ rtc_WavClose(w);
+ static const uint8_t kExpectedContents[] = {
+ 'R', 'I', 'F', 'F',
+ 44, 0, 0, 0, // size of whole file - 8: 8 + 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)
+ 2, 0, // channels: 2
+ 0x80, 0x2e, 0, 0, // sample rate: 11904
+ 0, 0xba, 0, 0, // byte rate: 2 * 2 * 11904
+ 4, 0, // block align: NumChannels * BytesPerSample
+ 16, 0, // bits per sample: 2 * 8
+ 'd', 'a', 't', 'a',
+ 8, 0, 0, 0, // size of payload: 8
+ 0, 0, // first sample: 0.0
+ 10, 0, // second sample: 10.0
+ 0xff, 0x7f, // third sample: 4e4 (saturated)
+ 0, 0x80, // fourth sample: -1e9 (saturated)
+ };
+ static const int kContentSize =
+ kWavHeaderSize + kNumSamples * sizeof(int16_t);
+ static_assert(sizeof(kExpectedContents) == kContentSize, "content size");
+ EXPECT_EQ(size_t(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));
+}
+
+// Write a larger WAV file. You can listen to this file to sanity-check it.
+TEST(WavWriterTest, LargeFile) {
+ std::string outfile = test::OutputPath() + "wavtest3.wav";
+ static const int kSampleRate = 8000;
+ static const int kNumChannels = 2;
+ static const uint32_t kNumSamples = 3 * kSampleRate * kNumChannels;
+ float samples[kNumSamples];
+ for (uint32_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);
+ EXPECT_EQ(kSampleRate, w.sample_rate());
+ EXPECT_EQ(kNumChannels, w.num_channels());
+ EXPECT_EQ(0u, w.num_samples());
+ w.WriteSamples(samples, kNumSamples);
+ EXPECT_EQ(kNumSamples, w.num_samples());
+ }
+ EXPECT_EQ(sizeof(int16_t) * kNumSamples + kWavHeaderSize,
+ test::GetFileSize(outfile));
+
+ {
+ WavReader r(outfile);
+ EXPECT_EQ(kSampleRate, r.sample_rate());
+ EXPECT_EQ(kNumChannels, r.num_channels());
+ EXPECT_EQ(kNumSamples, r.num_samples());
+
+ 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));
+ }
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/wav_header.cc b/webrtc/common_audio/wav_header.cc
new file mode 100644
index 0000000000..61cfffe62c
--- /dev/null
+++ b/webrtc/common_audio/wav_header.cc
@@ -0,0 +1,242 @@
+/*
+ * 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 "webrtc/common_audio/wav_header.h"
+
+#include <algorithm>
+#include <cstring>
+#include <limits>
+#include <string>
+
+#include "webrtc/base/checks.h"
+#include "webrtc/common_audio/include/audio_util.h"
+
+namespace webrtc {
+namespace {
+
+struct ChunkHeader {
+ uint32_t ID;
+ uint32_t Size;
+};
+static_assert(sizeof(ChunkHeader) == 8, "ChunkHeader size");
+
+// We can't nest this definition in WavHeader, because VS2013 gives an error
+// on sizeof(WavHeader::fmt): "error C2070: 'unknown': illegal sizeof operand".
+struct FmtSubchunk {
+ ChunkHeader header;
+ uint16_t AudioFormat;
+ uint16_t NumChannels;
+ uint32_t SampleRate;
+ uint32_t ByteRate;
+ uint16_t BlockAlign;
+ uint16_t BitsPerSample;
+};
+static_assert(sizeof(FmtSubchunk) == 24, "FmtSubchunk size");
+const uint32_t kFmtSubchunkSize = sizeof(FmtSubchunk) - sizeof(ChunkHeader);
+
+struct WavHeader {
+ struct {
+ ChunkHeader header;
+ uint32_t Format;
+ } riff;
+ FmtSubchunk fmt;
+ struct {
+ ChunkHeader header;
+ } data;
+};
+static_assert(sizeof(WavHeader) == kWavHeaderSize, "no padding in header");
+
+} // namespace
+
+bool CheckWavParameters(int num_channels,
+ int sample_rate,
+ WavFormat format,
+ int bytes_per_sample,
+ uint32_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 (static_cast<uint64_t>(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 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 kWavFormatALaw:
+ case kWavFormatMuLaw:
+ if (bytes_per_sample != 1)
+ 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 uint32_t max_samples =
+ (std::numeric_limits<uint32_t>::max()
+ - (kWavHeaderSize - sizeof(ChunkHeader))) /
+ 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;
+}
+
+#ifdef WEBRTC_ARCH_LITTLE_ENDIAN
+static inline void WriteLE16(uint16_t* f, uint16_t x) { *f = x; }
+static inline void WriteLE32(uint32_t* f, uint32_t x) { *f = x; }
+static inline void WriteFourCC(uint32_t* f, char a, char b, char c, char d) {
+ *f = static_cast<uint32_t>(a)
+ | static_cast<uint32_t>(b) << 8
+ | static_cast<uint32_t>(c) << 16
+ | static_cast<uint32_t>(d) << 24;
+}
+
+static inline uint16_t ReadLE16(uint16_t x) { return x; }
+static inline uint32_t ReadLE32(uint32_t x) { return x; }
+static inline std::string ReadFourCC(uint32_t x) {
+ return std::string(reinterpret_cast<char*>(&x), 4);
+}
+#else
+#error "Write be-to-le conversion functions"
+#endif
+
+static inline uint32_t RiffChunkSize(uint32_t bytes_in_payload) {
+ return bytes_in_payload + kWavHeaderSize - sizeof(ChunkHeader);
+}
+
+static inline uint32_t ByteRate(int num_channels, int sample_rate,
+ int bytes_per_sample) {
+ return static_cast<uint32_t>(num_channels) * sample_rate * bytes_per_sample;
+}
+
+static inline uint16_t BlockAlign(int num_channels, int bytes_per_sample) {
+ return num_channels * bytes_per_sample;
+}
+
+void WriteWavHeader(uint8_t* buf,
+ int num_channels,
+ int sample_rate,
+ WavFormat format,
+ int bytes_per_sample,
+ uint32_t num_samples) {
+ RTC_CHECK(CheckWavParameters(num_channels, sample_rate, format,
+ bytes_per_sample, num_samples));
+
+ WavHeader header;
+ const uint32_t bytes_in_payload = bytes_per_sample * num_samples;
+
+ WriteFourCC(&header.riff.header.ID, 'R', 'I', 'F', 'F');
+ WriteLE32(&header.riff.header.Size, RiffChunkSize(bytes_in_payload));
+ WriteFourCC(&header.riff.Format, 'W', 'A', 'V', 'E');
+
+ WriteFourCC(&header.fmt.header.ID, 'f', 'm', 't', ' ');
+ WriteLE32(&header.fmt.header.Size, kFmtSubchunkSize);
+ WriteLE16(&header.fmt.AudioFormat, format);
+ WriteLE16(&header.fmt.NumChannels, num_channels);
+ WriteLE32(&header.fmt.SampleRate, sample_rate);
+ WriteLE32(&header.fmt.ByteRate, ByteRate(num_channels, sample_rate,
+ bytes_per_sample));
+ WriteLE16(&header.fmt.BlockAlign, BlockAlign(num_channels, bytes_per_sample));
+ WriteLE16(&header.fmt.BitsPerSample, 8 * bytes_per_sample);
+
+ WriteFourCC(&header.data.header.ID, 'd', 'a', 't', 'a');
+ WriteLE32(&header.data.header.Size, bytes_in_payload);
+
+ // Do an extra copy rather than writing everything to buf directly, since buf
+ // might not be correctly aligned.
+ memcpy(buf, &header, kWavHeaderSize);
+}
+
+bool ReadWavHeader(ReadableWav* readable,
+ int* num_channels,
+ int* sample_rate,
+ WavFormat* format,
+ int* bytes_per_sample,
+ uint32_t* num_samples) {
+ WavHeader header;
+ if (readable->Read(&header, kWavHeaderSize - sizeof(header.data)) !=
+ kWavHeaderSize - sizeof(header.data))
+ return false;
+
+ const uint32_t fmt_size = ReadLE32(header.fmt.header.Size);
+ if (fmt_size != kFmtSubchunkSize) {
+ // There is an optional two-byte extension field permitted to be present
+ // with PCM, but which must be zero.
+ int16_t ext_size;
+ if (kFmtSubchunkSize + 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;
+ }
+ if (readable->Read(&header.data, sizeof(header.data)) != sizeof(header.data))
+ return false;
+
+ // Parse needed fields.
+ *format = static_cast<WavFormat>(ReadLE16(header.fmt.AudioFormat));
+ *num_channels = ReadLE16(header.fmt.NumChannels);
+ *sample_rate = ReadLE32(header.fmt.SampleRate);
+ *bytes_per_sample = ReadLE16(header.fmt.BitsPerSample) / 8;
+ const uint32_t bytes_in_payload = ReadLE32(header.data.header.Size);
+ if (*bytes_per_sample <= 0)
+ return false;
+ *num_samples = bytes_in_payload / *bytes_per_sample;
+
+ // Sanity check remaining fields.
+ if (ReadFourCC(header.riff.header.ID) != "RIFF")
+ return false;
+ if (ReadFourCC(header.riff.Format) != "WAVE")
+ return false;
+ if (ReadFourCC(header.fmt.header.ID) != "fmt ")
+ return false;
+ if (ReadFourCC(header.data.header.ID) != "data")
+ return false;
+
+ if (ReadLE32(header.riff.header.Size) < RiffChunkSize(bytes_in_payload))
+ return false;
+ if (ReadLE32(header.fmt.ByteRate) !=
+ ByteRate(*num_channels, *sample_rate, *bytes_per_sample))
+ return false;
+ if (ReadLE16(header.fmt.BlockAlign) !=
+ BlockAlign(*num_channels, *bytes_per_sample))
+ return false;
+
+ return CheckWavParameters(*num_channels, *sample_rate, *format,
+ *bytes_per_sample, *num_samples);
+}
+
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/wav_header.h b/webrtc/common_audio/wav_header.h
new file mode 100644
index 0000000000..1a0fd7c81d
--- /dev/null
+++ b/webrtc/common_audio/wav_header.h
@@ -0,0 +1,64 @@
+/*
+ * 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 WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
+#define WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+namespace webrtc {
+
+static const size_t kWavHeaderSize = 44;
+
+class ReadableWav {
+ public:
+ // Returns the number of bytes read.
+ size_t virtual Read(void* buf, size_t num_bytes) = 0;
+ virtual ~ReadableWav() {}
+};
+
+enum WavFormat {
+ kWavFormatPcm = 1, // PCM, each sample of size bytes_per_sample
+ kWavFormatALaw = 6, // 8-bit ITU-T G.711 A-law
+ kWavFormatMuLaw = 7, // 8-bit ITU-T G.711 mu-law
+};
+
+// Return true if the given parameters will make a well-formed WAV header.
+bool CheckWavParameters(int num_channels,
+ int sample_rate,
+ WavFormat format,
+ int bytes_per_sample,
+ uint32_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. CHECKs the input parameters for validity.
+void WriteWavHeader(uint8_t* buf,
+ int num_channels,
+ int sample_rate,
+ WavFormat format,
+ int bytes_per_sample,
+ uint32_t num_samples);
+
+// Read a WAV header from an implemented ReadableWav and parse the values into
+// the provided output parameters. ReadableWav is used because the header can
+// be variably sized. Returns false if the header is invalid.
+bool ReadWavHeader(ReadableWav* readable,
+ int* num_channels,
+ int* sample_rate,
+ WavFormat* format,
+ int* bytes_per_sample,
+ uint32_t* num_samples);
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_WAV_HEADER_H_
diff --git a/webrtc/common_audio/wav_header_unittest.cc b/webrtc/common_audio/wav_header_unittest.cc
new file mode 100644
index 0000000000..e03cb303aa
--- /dev/null
+++ b/webrtc/common_audio/wav_header_unittest.cc
@@ -0,0 +1,323 @@
+/*
+ * 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 <limits>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "webrtc/common_audio/wav_header.h"
+
+namespace webrtc {
+
+// Doesn't take ownership of the buffer.
+class ReadableWavBuffer : public ReadableWav {
+ public:
+ ReadableWavBuffer(const uint8_t* buf, size_t size)
+ : buf_(buf),
+ size_(size),
+ pos_(0),
+ buf_exhausted_(false),
+ check_read_size_(true) {}
+ ReadableWavBuffer(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) {}
+
+ virtual ~ReadableWavBuffer() {
+ // Verify the entire buffer has been read.
+ if (check_read_size_)
+ EXPECT_EQ(size_, pos_);
+ }
+
+ virtual size_t Read(void* buf, size_t num_bytes) {
+ // Verify we don't try to read outside of a properly sized header.
+ if (size_ >= kWavHeaderSize)
+ EXPECT_GE(size_, pos_ + num_bytes);
+ 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;
+ }
+
+ 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, kWavFormatPcm, 1, 0));
+ EXPECT_FALSE(CheckWavParameters(0, 8000, kWavFormatPcm, 1, 0));
+ EXPECT_FALSE(CheckWavParameters(-1, 8000, kWavFormatPcm, 1, 0));
+ EXPECT_FALSE(CheckWavParameters(1, 0, kWavFormatPcm, 1, 0));
+ EXPECT_FALSE(CheckWavParameters(1, 8000, WavFormat(0), 1, 0));
+ EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 0, 0));
+
+ // Try invalid format/bytes-per-sample combinations.
+ EXPECT_TRUE(CheckWavParameters(1, 8000, kWavFormatPcm, 2, 0));
+ EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatPcm, 4, 0));
+ EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatALaw, 2, 0));
+ EXPECT_FALSE(CheckWavParameters(1, 8000, kWavFormatMuLaw, 2, 0));
+
+ // Too large values.
+ EXPECT_FALSE(CheckWavParameters(1 << 20, 1 << 20, kWavFormatPcm, 1, 0));
+ EXPECT_FALSE(CheckWavParameters(
+ 1, 8000, kWavFormatPcm, 1, std::numeric_limits<uint32_t>::max()));
+
+ // Not the same number of samples for each channel.
+ EXPECT_FALSE(CheckWavParameters(3, 8000, kWavFormatPcm, 1, 5));
+}
+
+TEST(WavHeaderTest, ReadWavHeaderWithErrors) {
+ int num_channels = 0;
+ int sample_rate = 0;
+ WavFormat format = kWavFormatPcm;
+ int bytes_per_sample = 0;
+ uint32_t num_samples = 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*.
+ {
+ static const uint8_t kBadRiffID[] = {
+ '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
+ 6, 0, // format: A-law (6)
+ 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
+ };
+ ReadableWavBuffer r(kBadRiffID, sizeof(kBadRiffID));
+ EXPECT_FALSE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ }
+ {
+ static const uint8_t kBadBitsPerSample[] = {
+ '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
+ 6, 0, // format: A-law (6)
+ 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
+ };
+ ReadableWavBuffer r(kBadBitsPerSample, sizeof(kBadBitsPerSample));
+ EXPECT_FALSE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ }
+ {
+ static const uint8_t kBadByteRate[] = {
+ '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
+ 6, 0, // format: A-law (6)
+ 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
+ };
+ ReadableWavBuffer r(kBadByteRate, sizeof(kBadByteRate));
+ EXPECT_FALSE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ }
+ {
+ static const uint8_t kBadFmtHeaderSize[] = {
+ '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.
+ 6, 0, // format: A-law (6)
+ 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
+ };
+ ReadableWavBuffer r(kBadFmtHeaderSize, sizeof(kBadFmtHeaderSize), false);
+ EXPECT_FALSE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ }
+ {
+ static const uint8_t kNonZeroExtensionField[] = {
+ '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
+ 6, 0, // format: A-law (6)
+ 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
+ };
+ ReadableWavBuffer r(kNonZeroExtensionField, sizeof(kNonZeroExtensionField),
+ false);
+ EXPECT_FALSE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ }
+ {
+ static const uint8_t kMissingDataChunk[] = {
+ '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
+ 6, 0, // format: A-law (6)
+ 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
+ };
+ ReadableWavBuffer r(kMissingDataChunk, sizeof(kMissingDataChunk));
+ EXPECT_FALSE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ }
+ {
+ static const uint8_t kMissingFmtAndDataChunks[] = {
+ 'R', 'I', 'F', 'F',
+ 0xbd, 0xd0, 0x5b, 0x07, // size of whole file - 8: 123457689 + 44 - 8
+ 'W', 'A', 'V', 'E',
+ };
+ ReadableWavBuffer r(kMissingFmtAndDataChunks,
+ sizeof(kMissingFmtAndDataChunks));
+ EXPECT_FALSE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ }
+}
+
+// Try writing and reading a valid WAV header and make sure it looks OK.
+TEST(WavHeaderTest, WriteAndReadWavHeader) {
+ static const int kSize = 4 + kWavHeaderSize + 4;
+ uint8_t buf[kSize];
+ memset(buf, 0xa4, sizeof(buf));
+ WriteWavHeader(buf + 4, 17, 12345, kWavFormatALaw, 1, 123457689);
+ static const uint8_t kExpectedBuf[] = {
+ 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes before header
+ '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
+ 6, 0, // format: A-law (6)
+ 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
+ 0xa4, 0xa4, 0xa4, 0xa4, // untouched bytes after header
+ };
+ static_assert(sizeof(kExpectedBuf) == kSize, "buffer size");
+ EXPECT_EQ(0, memcmp(kExpectedBuf, buf, kSize));
+
+ int num_channels = 0;
+ int sample_rate = 0;
+ WavFormat format = kWavFormatPcm;
+ int bytes_per_sample = 0;
+ uint32_t num_samples = 0;
+ ReadableWavBuffer r(buf + 4, sizeof(buf) - 8);
+ EXPECT_TRUE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ EXPECT_EQ(17, num_channels);
+ EXPECT_EQ(12345, sample_rate);
+ EXPECT_EQ(kWavFormatALaw, format);
+ EXPECT_EQ(1, 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) {
+ static const uint8_t kBuf[] = {
+ 'R', 'I', 'F', 'F',
+ 0x3d, 0xd1, 0x5b, 0x07, // size of whole file - 8 + an extra 128 bytes of
+ // "metadata": 123457689 + 44 - 8 + 128. (atypical)
+ 'W', 'A', 'V', 'E',
+ 'f', 'm', 't', ' ',
+ 18, 0, 0, 0, // size of fmt block (with an atypical extension size field)
+ 6, 0, // format: A-law (6)
+ 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
+ };
+
+ int num_channels = 0;
+ int sample_rate = 0;
+ WavFormat format = kWavFormatPcm;
+ int bytes_per_sample = 0;
+ uint32_t num_samples = 0;
+ ReadableWavBuffer r(kBuf, sizeof(kBuf));
+ EXPECT_TRUE(
+ ReadWavHeader(&r, &num_channels, &sample_rate, &format,
+ &bytes_per_sample, &num_samples));
+ EXPECT_EQ(17, num_channels);
+ EXPECT_EQ(12345, sample_rate);
+ EXPECT_EQ(kWavFormatALaw, format);
+ EXPECT_EQ(1, bytes_per_sample);
+ EXPECT_EQ(123457689u, num_samples);
+}
+
+} // namespace webrtc
diff --git a/webrtc/common_audio/window_generator.cc b/webrtc/common_audio/window_generator.cc
new file mode 100644
index 0000000000..ab983b736f
--- /dev/null
+++ b/webrtc/common_audio/window_generator.cc
@@ -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.
+ */
+
+#define _USE_MATH_DEFINES
+
+#include "webrtc/common_audio/window_generator.h"
+
+#include <cmath>
+#include <complex>
+
+#include "webrtc/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/webrtc/common_audio/window_generator.h b/webrtc/common_audio/window_generator.h
new file mode 100644
index 0000000000..25dd233b44
--- /dev/null
+++ b/webrtc/common_audio/window_generator.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 WEBRTC_COMMON_AUDIO_WINDOW_GENERATOR_H_
+#define WEBRTC_COMMON_AUDIO_WINDOW_GENERATOR_H_
+
+#include <stddef.h>
+
+#include "webrtc/base/constructormagic.h"
+
+namespace webrtc {
+
+// Helper class with generators for various signal transform windows.
+class WindowGenerator {
+ public:
+ static void Hanning(int length, float* window);
+ static void KaiserBesselDerived(float alpha, size_t length, float* window);
+
+ private:
+ RTC_DISALLOW_IMPLICIT_CONSTRUCTORS(WindowGenerator);
+};
+
+} // namespace webrtc
+
+#endif // WEBRTC_COMMON_AUDIO_WINDOW_GENERATOR_H_
+
diff --git a/webrtc/common_audio/window_generator_unittest.cc b/webrtc/common_audio/window_generator_unittest.cc
new file mode 100644
index 0000000000..124b301df6
--- /dev/null
+++ b/webrtc/common_audio/window_generator_unittest.cc
@@ -0,0 +1,92 @@
+/*
+ * 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 "webrtc/common_audio/window_generator.h"
+
+#include <cstring>
+
+#include "testing/gtest/include/gtest/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
+