Update common_audio
Corresponds to upstream commit 524e9b043e7e86fd72353b987c9d5f6a1ebf83e1 Update notes: * Moved src/ to webrtc/ to easily diff against the third_party/webrtc in the chromium tree * ARM/NEON/MIPS support is not yet hooked up * Tests have not been copied
This commit is contained in:
243
webrtc/common_audio/BUILD.gn
Normal file
243
webrtc/common_audio/BUILD.gn
Normal file
@ -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" ]
|
||||
}
|
||||
}
|
74
webrtc/common_audio/Makefile.am
Normal file
74
webrtc/common_audio/Makefile.am
Normal file
@ -0,0 +1,74 @@
|
||||
noinst_LTLIBRARIES = libcommon_audio.la
|
||||
|
||||
libcommon_audio_la_SOURCES = signal_processing/include/real_fft.h \
|
||||
signal_processing/include/signal_processing_library.h \
|
||||
signal_processing/include/spl_inl.h \
|
||||
signal_processing/include/spl_inl_armv7.h \
|
||||
signal_processing/include/spl_inl_mips.h \
|
||||
signal_processing/auto_corr_to_refl_coef.c \
|
||||
signal_processing/auto_correlation.c \
|
||||
signal_processing/complex_bit_reverse.c \
|
||||
signal_processing/complex_fft.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_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/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/spl_sqrt_floor.c \
|
||||
signal_processing/splitting_filter.c \
|
||||
signal_processing/sqrt_of_one_minus_x_squared.c \
|
||||
signal_processing/vector_scaling_operations.c \
|
||||
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
|
||||
|
||||
libcommon_audio_la_CFLAGS = $(AM_CFLAGS) $(COMMON_CFLAGS)
|
||||
libcommon_audio_la_CXXFLAGS = $(AM_CXXFLAGS) $(COMMON_CXXFLAGS)
|
||||
|
||||
# FIXME:
|
||||
# if ARM - signal_processing/complex_bit_reverse_arm.S
|
||||
# signal_processing/spl_sqrt_floor_arm.S
|
||||
# ARM7 - signal_processing/filter_ar_fast_q12_armv7.S
|
||||
# NEON - signal_processing/cross_correlation_neon.c
|
||||
# signal_processing/downsample_fast_neon.c
|
||||
# signal_processing/min_max_operations_neon.c
|
||||
# if MIPS - 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
|
||||
# signal_processing/vector_scaling_operations_mips.c
|
103
webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
Normal file
103
webrtc/common_audio/signal_processing/auto_corr_to_refl_coef.c
Normal file
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
65
webrtc/common_audio/signal_processing/auto_correlation.c
Normal file
65
webrtc/common_audio/signal_processing/auto_correlation.c
Normal file
@ -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;
|
||||
}
|
108
webrtc/common_audio/signal_processing/complex_bit_reverse.c
Normal file
108
webrtc/common_audio/signal_processing/complex_bit_reverse.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
119
webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
Normal file
119
webrtc/common_audio/signal_processing/complex_bit_reverse_arm.S
Normal file
@ -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/interface/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
|
176
webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
Normal file
176
webrtc/common_audio/signal_processing/complex_bit_reverse_mips.c
Normal file
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
298
webrtc/common_audio/signal_processing/complex_fft.c
Normal file
298
webrtc/common_audio/signal_processing/complex_fft.c
Normal file
@ -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;
|
||||
}
|
328
webrtc/common_audio/signal_processing/complex_fft_mips.c
Normal file
328
webrtc/common_audio/signal_processing/complex_fft_mips.c
Normal file
@ -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;
|
||||
|
||||
}
|
148
webrtc/common_audio/signal_processing/complex_fft_tables.h
Normal file
148
webrtc/common_audio/signal_processing/complex_fft_tables.h
Normal file
@ -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_
|
82
webrtc/common_audio/signal_processing/copy_set_operations.c
Normal file
82
webrtc/common_audio/signal_processing/copy_set_operations.c
Normal file
@ -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);
|
||||
}
|
30
webrtc/common_audio/signal_processing/cross_correlation.c
Normal file
30
webrtc/common_audio/signal_processing/cross_correlation.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
104
webrtc/common_audio/signal_processing/cross_correlation_mips.c
Normal file
104
webrtc/common_audio/signal_processing/cross_correlation_mips.c
Normal file
@ -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"
|
||||
);
|
||||
}
|
@ -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++;
|
||||
}
|
||||
}
|
138
webrtc/common_audio/signal_processing/division_operations.c
Normal file
138
webrtc/common_audio/signal_processing/division_operations.c
Normal file
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
48
webrtc/common_audio/signal_processing/downsample_fast.c
Normal file
48
webrtc/common_audio/signal_processing/downsample_fast.c
Normal file
@ -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;
|
||||
}
|
169
webrtc/common_audio/signal_processing/downsample_fast_mips.c
Normal file
169
webrtc/common_audio/signal_processing/downsample_fast_mips.c
Normal file
@ -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;
|
||||
}
|
217
webrtc/common_audio/signal_processing/downsample_fast_neon.c
Normal file
217
webrtc/common_audio/signal_processing/downsample_fast_neon.c
Normal file
@ -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;
|
||||
}
|
39
webrtc/common_audio/signal_processing/energy.c
Normal file
39
webrtc/common_audio/signal_processing/energy.c
Normal file
@ -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;
|
||||
}
|
89
webrtc/common_audio/signal_processing/filter_ar.c
Normal file
89
webrtc/common_audio/signal_processing/filter_ar.c
Normal file
@ -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;
|
||||
}
|
42
webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
Normal file
42
webrtc/common_audio/signal_processing/filter_ar_fast_q12.c
Normal file
@ -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);
|
||||
}
|
||||
}
|
218
webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
Normal file
218
webrtc/common_audio/signal_processing/filter_ar_fast_q12_armv7.S
Normal file
@ -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/interface/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);
|
||||
@ }
|
||||
@}
|
140
webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
Normal file
140
webrtc/common_audio/signal_processing/filter_ar_fast_q12_mips.c
Normal file
@ -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"
|
||||
);
|
||||
}
|
||||
|
45
webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
Normal file
45
webrtc/common_audio/signal_processing/filter_ma_fast_q12.c
Normal file
@ -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;
|
||||
}
|
77
webrtc/common_audio/signal_processing/get_hanning_window.c
Normal file
77
webrtc/common_audio/signal_processing/get_hanning_window.c
Normal file
@ -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];
|
||||
}
|
||||
|
||||
}
|
46
webrtc/common_audio/signal_processing/get_scaling_square.c
Normal file
46
webrtc/common_audio/signal_processing/get_scaling_square.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
97
webrtc/common_audio/signal_processing/include/real_fft.h
Normal file
97
webrtc/common_audio/signal_processing/include/real_fft.h
Normal file
@ -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_
|
File diff suppressed because it is too large
Load Diff
173
webrtc/common_audio/signal_processing/include/spl_inl.h
Normal file
173
webrtc/common_audio/signal_processing/include/spl_inl.h
Normal file
@ -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_
|
136
webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
Normal file
136
webrtc/common_audio/signal_processing/include/spl_inl_armv7.h
Normal file
@ -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_
|
225
webrtc/common_audio/signal_processing/include/spl_inl_mips.h
Normal file
225
webrtc/common_audio/signal_processing/include/spl_inl_mips.h
Normal file
@ -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_
|
246
webrtc/common_audio/signal_processing/levinson_durbin.c
Normal file
246
webrtc/common_audio/signal_processing/levinson_durbin.c
Normal file
@ -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
|
||||
}
|
56
webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
Normal file
56
webrtc/common_audio/signal_processing/lpc_to_refl_coef.c
Normal file
@ -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;
|
||||
}
|
224
webrtc/common_audio/signal_processing/min_max_operations.c
Normal file
224
webrtc/common_audio/signal_processing/min_max_operations.c
Normal file
@ -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;
|
||||
}
|
376
webrtc/common_audio/signal_processing/min_max_operations_mips.c
Normal file
376
webrtc/common_audio/signal_processing/min_max_operations_mips.c
Normal file
@ -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;
|
||||
}
|
283
webrtc/common_audio/signal_processing/min_max_operations_neon.c
Normal file
283
webrtc/common_audio/signal_processing/min_max_operations_neon.c
Normal file
@ -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;
|
||||
}
|
||||
|
115
webrtc/common_audio/signal_processing/randomization_functions.c
Normal file
115
webrtc/common_audio/signal_processing/randomization_functions.c
Normal file
@ -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;
|
||||
}
|
102
webrtc/common_audio/signal_processing/real_fft.c
Normal file
102
webrtc/common_audio/signal_processing/real_fft.c
Normal file
@ -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;
|
||||
}
|
59
webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
Normal file
59
webrtc/common_audio/signal_processing/refl_coef_to_lpc.c
Normal file
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
505
webrtc/common_audio/signal_processing/resample.c
Normal file
505
webrtc/common_audio/signal_processing/resample.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
186
webrtc/common_audio/signal_processing/resample_48khz.c
Normal file
186
webrtc/common_audio/signal_processing/resample_48khz.c
Normal file
@ -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));
|
||||
}
|
183
webrtc/common_audio/signal_processing/resample_by_2.c
Normal file
183
webrtc/common_audio/signal_processing/resample_by_2.c
Normal file
@ -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;
|
||||
}
|
679
webrtc/common_audio/signal_processing/resample_by_2_internal.c
Normal file
679
webrtc/common_audio/signal_processing/resample_by_2_internal.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
@ -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_
|
290
webrtc/common_audio/signal_processing/resample_by_2_mips.c
Normal file
290
webrtc/common_audio/signal_processing/resample_by_2_mips.c
Normal file
@ -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)
|
239
webrtc/common_audio/signal_processing/resample_fractional.c
Normal file
239
webrtc/common_audio/signal_processing/resample_fractional.c
Normal file
@ -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;
|
||||
}
|
||||
}
|
140
webrtc/common_audio/signal_processing/spl_init.c
Normal file
140
webrtc/common_audio/signal_processing/spl_init.c
Normal file
@ -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/interface/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);
|
||||
}
|
184
webrtc/common_audio/signal_processing/spl_sqrt.c
Normal file
184
webrtc/common_audio/signal_processing/spl_sqrt.c
Normal file
@ -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;
|
||||
}
|
77
webrtc/common_audio/signal_processing/spl_sqrt_floor.c
Normal file
77
webrtc/common_audio/signal_processing/spl_sqrt_floor.c
Normal file
@ -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;
|
||||
}
|
110
webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S
Normal file
110
webrtc/common_audio/signal_processing/spl_sqrt_floor_arm.S
Normal file
@ -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/interface/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
|
207
webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c
Normal file
207
webrtc/common_audio/signal_processing/spl_sqrt_floor_mips.c
Normal file
@ -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;
|
||||
}
|
||||
|
208
webrtc/common_audio/signal_processing/splitting_filter.c
Normal file
208
webrtc/common_audio/signal_processing/splitting_filter.c
Normal file
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
@ -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;
|
||||
}
|
50
webrtc/common_audio/vad/include/vad.h
Normal file
50
webrtc/common_audio/vad/include/vad.h
Normal file
@ -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_
|
86
webrtc/common_audio/vad/include/webrtc_vad.h
Normal file
86
webrtc/common_audio/vad/include/webrtc_vad.h
Normal file
@ -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
|
63
webrtc/common_audio/vad/vad.cc
Normal file
63
webrtc/common_audio/vad/vad.cc
Normal file
@ -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
|
676
webrtc/common_audio/vad/vad_core.c
Normal file
676
webrtc/common_audio/vad/vad_core.c
Normal file
@ -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;
|
||||
}
|
115
webrtc/common_audio/vad/vad_core.h
Normal file
115
webrtc/common_audio/vad/vad_core.h
Normal file
@ -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_
|
95
webrtc/common_audio/vad/vad_defines.h
Normal file
95
webrtc/common_audio/vad/vad_defines.h
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license
|
||||
* that can be found in the LICENSE file in the root of the source
|
||||
* tree. An additional intellectual property rights grant can be found
|
||||
* in the file PATENTS. All contributing project authors may
|
||||
* be found in the AUTHORS file in the root of the source tree.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This header file includes the macros used in VAD.
|
||||
*/
|
||||
|
||||
#ifndef WEBRTC_VAD_DEFINES_H_
|
||||
#define WEBRTC_VAD_DEFINES_H_
|
||||
|
||||
#define NUM_CHANNELS 6 // Eight frequency bands
|
||||
#define NUM_MODELS 2 // Number of Gaussian models
|
||||
#define NUM_TABLE_VALUES NUM_CHANNELS * NUM_MODELS
|
||||
|
||||
#define MIN_ENERGY 10
|
||||
#define ALPHA1 6553 // 0.2 in Q15
|
||||
#define ALPHA2 32439 // 0.99 in Q15
|
||||
#define NSP_MAX 6 // Maximum number of VAD=1 frames in a row counted
|
||||
#define MIN_STD 384 // Minimum standard deviation
|
||||
// Mode 0, Quality thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_Q 24
|
||||
#define INDIVIDUAL_20MS_Q 21 // (log10(2)*66)<<2 ~=16
|
||||
#define INDIVIDUAL_30MS_Q 24
|
||||
|
||||
#define TOTAL_10MS_Q 57
|
||||
#define TOTAL_20MS_Q 48
|
||||
#define TOTAL_30MS_Q 57
|
||||
|
||||
#define OHMAX1_10MS_Q 8 // Max Overhang 1
|
||||
#define OHMAX2_10MS_Q 14 // Max Overhang 2
|
||||
#define OHMAX1_20MS_Q 4 // Max Overhang 1
|
||||
#define OHMAX2_20MS_Q 7 // Max Overhang 2
|
||||
#define OHMAX1_30MS_Q 3
|
||||
#define OHMAX2_30MS_Q 5
|
||||
|
||||
// Mode 1, Low bitrate thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_LBR 37
|
||||
#define INDIVIDUAL_20MS_LBR 32
|
||||
#define INDIVIDUAL_30MS_LBR 37
|
||||
|
||||
#define TOTAL_10MS_LBR 100
|
||||
#define TOTAL_20MS_LBR 80
|
||||
#define TOTAL_30MS_LBR 100
|
||||
|
||||
#define OHMAX1_10MS_LBR 8 // Max Overhang 1
|
||||
#define OHMAX2_10MS_LBR 14 // Max Overhang 2
|
||||
#define OHMAX1_20MS_LBR 4
|
||||
#define OHMAX2_20MS_LBR 7
|
||||
|
||||
#define OHMAX1_30MS_LBR 3
|
||||
#define OHMAX2_30MS_LBR 5
|
||||
|
||||
// Mode 2, Very aggressive thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_AGG 82
|
||||
#define INDIVIDUAL_20MS_AGG 78
|
||||
#define INDIVIDUAL_30MS_AGG 82
|
||||
|
||||
#define TOTAL_10MS_AGG 285 //580
|
||||
#define TOTAL_20MS_AGG 260
|
||||
#define TOTAL_30MS_AGG 285
|
||||
|
||||
#define OHMAX1_10MS_AGG 6 // Max Overhang 1
|
||||
#define OHMAX2_10MS_AGG 9 // Max Overhang 2
|
||||
#define OHMAX1_20MS_AGG 3
|
||||
#define OHMAX2_20MS_AGG 5
|
||||
|
||||
#define OHMAX1_30MS_AGG 2
|
||||
#define OHMAX2_30MS_AGG 3
|
||||
|
||||
// Mode 3, Super aggressive thresholds - Different thresholds for the different frame lengths
|
||||
#define INDIVIDUAL_10MS_VAG 94
|
||||
#define INDIVIDUAL_20MS_VAG 94
|
||||
#define INDIVIDUAL_30MS_VAG 94
|
||||
|
||||
#define TOTAL_10MS_VAG 1100 //1700
|
||||
#define TOTAL_20MS_VAG 1050
|
||||
#define TOTAL_30MS_VAG 1100
|
||||
|
||||
#define OHMAX1_10MS_VAG 6 // Max Overhang 1
|
||||
#define OHMAX2_10MS_VAG 9 // Max Overhang 2
|
||||
#define OHMAX1_20MS_VAG 3
|
||||
#define OHMAX2_20MS_VAG 5
|
||||
|
||||
#define OHMAX1_30MS_VAG 2
|
||||
#define OHMAX2_30MS_VAG 3
|
||||
|
||||
#endif // WEBRTC_VAD_DEFINES_H_
|
331
webrtc/common_audio/vad/vad_filterbank.c
Normal file
331
webrtc/common_audio/vad/vad_filterbank.c
Normal file
@ -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;
|
||||
}
|
44
webrtc/common_audio/vad/vad_filterbank.h
Normal file
44
webrtc/common_audio/vad/vad_filterbank.h
Normal file
@ -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_
|
83
webrtc/common_audio/vad/vad_gmm.c
Normal file
83
webrtc/common_audio/vad/vad_gmm.c
Normal file
@ -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;
|
||||
}
|
39
webrtc/common_audio/vad/vad_gmm.h
Normal file
39
webrtc/common_audio/vad/vad_gmm.h
Normal file
@ -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_
|
178
webrtc/common_audio/vad/vad_sp.c
Normal file
178
webrtc/common_audio/vad/vad_sp.c
Normal file
@ -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];
|
||||
}
|
56
webrtc/common_audio/vad/vad_sp.h
Normal file
56
webrtc/common_audio/vad/vad_sp.h
Normal file
@ -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_
|
116
webrtc/common_audio/vad/webrtc_vad.c
Normal file
116
webrtc/common_audio/vad/webrtc_vad.c
Normal file
@ -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;
|
||||
}
|
Reference in New Issue
Block a user