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:
Arun Raghavan
2015-10-13 12:16:16 +05:30
parent 9413986e79
commit c4fb4e38de
230 changed files with 11201 additions and 8656 deletions

View 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" ]
}
}

View 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

View 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++;
}
}
}

View 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;
}

View 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;
}
}
}

View 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

View 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"
);
}
}

View 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;
}

View 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;
}

View 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_

View 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);
}

View 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;
}
}

View 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"
);
}

View File

@ -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++;
}
}

View 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;
}

View File

@ -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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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);
}
}

View 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);
@ }
@}

View 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"
);
}

View 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;
}

View 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];
}
}

View 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;
}
}

View File

@ -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);
}
}

View 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

View 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_

View 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_

View 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_

View 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
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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++;
}
}
}

View 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;
}
}

View 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));
}

View 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;
}

View 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;
}
}

View File

@ -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_

View 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)

View 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;
}
}

View 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);
}

View 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;
}

View 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;
}

View 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

View 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;
}

View 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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}

View 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_

View 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

View 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

View 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;
}

View 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_

View 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_

View 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;
}

View 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_

View 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;
}

View 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_

View 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];
}

View 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_

View 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;
}